// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.upgrade; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.v7.app.AppCompatActivity; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApplicationStatus; import org.chromium.base.ContextUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin; import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin.DocumentModeAssassinObserver; import org.chromium.chrome.browser.util.IntentUtils; /** * Activity that interrupts launch and shows that users are being upgraded to a new version of * Chrome. * * TODO(dfalcantara): Do we need to worry about onNewIntent()? */ public class UpgradeActivity extends AppCompatActivity { public static final String EXTRA_INTENT_TO_REFIRE = "org.chromium.chrome.browser.upgrade.INTENT_TO_REFIRE"; private static final long MIN_MS_TO_DISPLAY_ACTIVITY = 3000; private static final long INVALID_TIMESTAMP = -1; private final Handler mHandler; private final DocumentModeAssassinObserver mObserver; private Intent mIntentToFireAfterUpgrade; private long mStartTimestamp = INVALID_TIMESTAMP; private boolean mIsDestroyed; public static void launchInstance(Activity activity, Intent originalIntent) { Intent intent = new Intent(); intent.setClass(activity, UpgradeActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT); intent.putExtra(UpgradeActivity.EXTRA_INTENT_TO_REFIRE, originalIntent); activity.startActivity(intent); activity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); } public UpgradeActivity() { mHandler = new Handler(Looper.getMainLooper()); mObserver = new DocumentModeAssassinObserver() { @Override public void onStageChange(int newStage) { if (newStage != DocumentModeAssassin.STAGE_DONE) return; DocumentModeAssassin.getInstance().removeObserver(this); // Always post to avoid any issues that could arise from firing the Runnable // while other Observers are being alerted. long msElapsed = System.currentTimeMillis() - mStartTimestamp; long msRemaining = Math.max(0, MIN_MS_TO_DISPLAY_ACTIVITY - msElapsed); mHandler.postDelayed(new Runnable() { @Override public void run() { continueApplicationLaunch(); } }, msRemaining); } }; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mIntentToFireAfterUpgrade = getIntentToFireAfterUpgrade(getIntent()); setContentView(R.layout.upgrade_activity); DocumentModeAssassin assassin = DocumentModeAssassin.getInstance(); if (assassin.isMigrationNecessary()) { // Kick off migration if it hasn't already started. assassin.addObserver(mObserver); assassin.migrateFromDocumentToTabbedMode(); } else { // Migration finished in the background. continueApplicationLaunch(); } } @Override protected void onResume() { super.onResume(); // Set the timestamp after the Activity is visible to avoid shortening the timer. if (mStartTimestamp == INVALID_TIMESTAMP) mStartTimestamp = System.currentTimeMillis(); } @Override protected void onDestroy() { mIsDestroyed = true; super.onDestroy(); } private static Intent getIntentToFireAfterUpgrade(Intent activityIntent) { Intent intentToFire = null; // Retrieve the Intent that caused the user to end up on the upgrade pathway. if (activityIntent != null) { intentToFire = (Intent) IntentUtils.safeGetParcelableExtra( activityIntent, EXTRA_INTENT_TO_REFIRE); } // If there's no Intent to refire, send them to the browser. if (intentToFire == null) { intentToFire = new Intent(Intent.ACTION_MAIN); intentToFire.setPackage(ContextUtils.getApplicationContext().getPackageName()); } // Fire the Intent into a different task so that this one can go away. intentToFire.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT); return intentToFire; } private void continueApplicationLaunch() { if (mIsDestroyed) return; ApiCompatibilityUtils.finishAndRemoveTask(this); if (mIntentToFireAfterUpgrade != null && ApplicationStatus.hasVisibleActivities()) { startActivity(mIntentToFireAfterUpgrade); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); mIntentToFireAfterUpgrade = null; } } }