/** * Copyright (C) 2013 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.securecomcode.text; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ProgressBar; import com.securecomcode.text.crypto.DecryptingQueue; import com.securecomcode.text.crypto.IdentityKeyUtil; import com.securecomcode.text.notifications.MessageNotifier; import com.securecomcode.text.util.Util; import org.whispersystems.textsecure.crypto.MasterSecret; import com.securecomcode.text.database.DatabaseFactory; import com.securecomcode.text.util.VersionTracker; import java.util.SortedSet; import java.util.TreeSet; public class DatabaseUpgradeActivity extends Activity { public static final int NO_MORE_KEY_EXCHANGE_PREFIX_VERSION = 46; public static final int MMS_BODY_VERSION = 46; public static final int TOFU_IDENTITIES_VERSION = 50; public static final int CURVE25519_VERSION = 63; public static final int ASYMMETRIC_MASTER_SECRET_FIX_VERSION = 73; private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{ add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION); add(TOFU_IDENTITIES_VERSION); add(CURVE25519_VERSION); add(ASYMMETRIC_MASTER_SECRET_FIX_VERSION); }}; private MasterSecret masterSecret; @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); this.masterSecret = getIntent().getParcelableExtra("master_secret"); if (needsUpgradeTask()) { Log.w("DatabaseUpgradeActivity", "Upgrading..."); setContentView(R.layout.database_upgrade_activity); ProgressBar indeterminateProgress = (ProgressBar)findViewById(R.id.indeterminate_progress); ProgressBar determinateProgress = (ProgressBar)findViewById(R.id.determinate_progress); new DatabaseUpgradeTask(indeterminateProgress, determinateProgress) .execute(VersionTracker.getLastSeenVersion(this)); } else { VersionTracker.updateLastSeenVersion(this); DecryptingQueue.schedulePendingDecrypts(DatabaseUpgradeActivity.this, masterSecret); MessageNotifier.updateNotification(DatabaseUpgradeActivity.this, masterSecret); startActivity((Intent)getIntent().getParcelableExtra("next_intent")); finish(); } } private boolean needsUpgradeTask() { int currentVersionCode = Util.getCurrentApkReleaseVersion(this); int lastSeenVersion = VersionTracker.getLastSeenVersion(this); Log.w("DatabaseUpgradeActivity", "LastSeenVersion: " + lastSeenVersion); if (lastSeenVersion >= currentVersionCode) return false; for (int version : UPGRADE_VERSIONS) { Log.w("DatabaseUpgradeActivity", "Comparing: " + version); if (lastSeenVersion < version) return true; } return false; } public static boolean isUpdate(Context context) { try { int currentVersionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; int previousVersionCode = VersionTracker.getLastSeenVersion(context); return previousVersionCode < currentVersionCode; } catch (PackageManager.NameNotFoundException e) { throw new AssertionError(e); } } public interface DatabaseUpgradeListener { public void setProgress(int progress, int total); } private class DatabaseUpgradeTask extends AsyncTask<Integer, Double, Void> implements DatabaseUpgradeListener { private final ProgressBar indeterminateProgress; private final ProgressBar determinateProgress; public DatabaseUpgradeTask(ProgressBar indeterminateProgress, ProgressBar determinateProgress) { this.indeterminateProgress = indeterminateProgress; this.determinateProgress = determinateProgress; } @Override protected Void doInBackground(Integer... params) { Context context = DatabaseUpgradeActivity.this.getApplicationContext(); Log.w("DatabaseUpgradeActivity", "Running background upgrade.."); DatabaseFactory.getInstance(DatabaseUpgradeActivity.this) .onApplicationLevelUpgrade(context, masterSecret, params[0], this); if (params[0] < CURVE25519_VERSION) { if (!IdentityKeyUtil.hasCurve25519IdentityKeys(context)) { IdentityKeyUtil.generateCurve25519IdentityKeys(context, masterSecret); } } return null; } @Override protected void onProgressUpdate(Double... update) { indeterminateProgress.setVisibility(View.GONE); determinateProgress.setVisibility(View.VISIBLE); double scaler = update[0]; determinateProgress.setProgress((int)Math.floor(determinateProgress.getMax() * scaler)); } @Override protected void onPostExecute(Void result) { VersionTracker.updateLastSeenVersion(DatabaseUpgradeActivity.this); DecryptingQueue.schedulePendingDecrypts(DatabaseUpgradeActivity.this, masterSecret); MessageNotifier.updateNotification(DatabaseUpgradeActivity.this, masterSecret); startActivity((Intent)getIntent().getParcelableExtra("next_intent")); finish(); } @Override public void setProgress(int progress, int total) { publishProgress(((double)progress / (double)total)); } } }