Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83c3ba28 authored by Joshua Trask's avatar Joshua Trask
Browse files

"Springboard" from system to new chooser.

These changes are somewhat hacky, but they allow
us to conditionally hand over to the new unbundled
chooser with minimal impact if the experiment
is disabled.

For a safer implementation, we could consider
starting with a separate springboard activity that
launches a normal (reverted) version of the
"bundled" chooser if we intend to show the UI
from the system side, but that would incur some
latency even when the flag is disabled.

Test: manual, as described in ag/16286296.
Bug: 202165481
Change-Id: I4073776b293806052e9ff66c50fea1181afd642a
parent 15cd688e
Loading
Loading
Loading
Loading
+95 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.SharedElementCallback;
import android.app.SharedElementCallback;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
import android.app.prediction.AppPredictionManager;
@@ -70,9 +71,11 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Environment;
import android.os.Environment;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Message;
import android.os.Parcelable;
import android.os.Parcelable;
import android.os.PatternMatcher;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
@@ -151,6 +154,19 @@ public class ChooserActivity extends ResolverActivity implements
        ChooserListAdapter.ChooserListCommunicator,
        ChooserListAdapter.ChooserListCommunicator,
        SelectableTargetInfoCommunicator {
        SelectableTargetInfoCommunicator {
    private static final String TAG = "ChooserActivity";
    private static final String TAG = "ChooserActivity";

    /**
     * Whether this chooser is operating in "headless springboard" mode (as determined during
     * onCreate). In this mode, our activity sits in the background and waits for the new
     * "unbundled" chooser to handle the Sharesheet experience; the system ChooserActivity is
     * responsible only for providing the startActivityAsCaller permission token and keeping it
     * valid for the life of the unbundled delegate activity.
     *
     * TODO: when the unbundled chooser is fully launched, the system-side "springboard" can use a
     * simpler implementation that doesn't inherit from ResolverActivity.
     */
    private boolean mIsHeadlessSpringboardActivity;

    private AppPredictor mPersonalAppPredictor;
    private AppPredictor mPersonalAppPredictor;
    private AppPredictor mWorkAppPredictor;
    private AppPredictor mWorkAppPredictor;
    private boolean mShouldDisplayLandscape;
    private boolean mShouldDisplayLandscape;
@@ -235,6 +251,11 @@ public class ChooserActivity extends ResolverActivity implements


    private static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;
    private static final float DIRECT_SHARE_EXPANSION_RATE = 0.78f;


    private boolean mEnableChooserDelegate =
            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                    SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
                    false);

    private static final int DEFAULT_SALT_EXPIRATION_DAYS = 7;
    private static final int DEFAULT_SALT_EXPIRATION_DAYS = 7;
    private int mMaxHashSaltDays = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
    private int mMaxHashSaltDays = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
            SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
            SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
@@ -500,6 +521,12 @@ public class ChooserActivity extends ResolverActivity implements


    @Override
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    protected void onCreate(Bundle savedInstanceState) {
        if (handOverToDelegateChooser()) {
            super_onCreate(savedInstanceState);
            mIsHeadlessSpringboardActivity = true;
            return;
        }

        final long intentReceivedTime = System.currentTimeMillis();
        final long intentReceivedTime = System.currentTimeMillis();
        getChooserActivityLogger().logSharesheetTriggered();
        getChooserActivityLogger().logSharesheetTriggered();
        // This is the only place this value is being set. Effectively final.
        // This is the only place this value is being set. Effectively final.
@@ -714,6 +741,64 @@ public class ChooserActivity extends ResolverActivity implements
        postponeEnterTransition();
        postponeEnterTransition();
    }
    }


    private boolean handOverToDelegateChooser() {
        // Check the explicit classname so that we don't interfere with the flow of any subclasses.
        if (!this.getClass().getName().equals("com.android.internal.app.ChooserActivity")
                || !mEnableChooserDelegate) {
            return false;
        }

        try {
            IBinder permissionToken = ActivityTaskManager.getService()
                    .requestStartActivityPermissionToken(getActivityToken());
            Intent delegationIntent = new Intent();
            final ComponentName delegateActivity = ComponentName.unflattenFromString(
                    Resources.getSystem().getString(R.string.config_chooserActivity));
            delegationIntent.setComponent(delegateActivity);
            delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent());
            delegationIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken);
            delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);

            // Don't close until the delegate finishes, or the token will be invalidated.
            mAwaitingDelegateResponse = true;
            startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER);
            return true;
        } catch (RemoteException e) {
            Log.e(TAG, e.toString());
        }
        return false;
    }

    @Override
    protected void onRestart() {
        if (mIsHeadlessSpringboardActivity) {
            super_onRestart();
            return;
        }

        super.onRestart();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (mIsHeadlessSpringboardActivity) {
            super_onSaveInstanceState(outState);
            return;
        }

        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        if (mIsHeadlessSpringboardActivity) {
            super_onRestoreInstanceState(savedInstanceState);
            return;
        }

        super.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    @Override
    protected int appliedThemeResId() {
    protected int appliedThemeResId() {
        return R.style.Theme_DeviceDefault_Chooser;
        return R.style.Theme_DeviceDefault_Chooser;
@@ -998,6 +1083,11 @@ public class ChooserActivity extends ResolverActivity implements


    @Override
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
    public void onConfigurationChanged(Configuration newConfig) {
        if (mIsHeadlessSpringboardActivity) {
            super_onConfigurationChanged(newConfig);
            return;
        }

        super.onConfigurationChanged(newConfig);
        super.onConfigurationChanged(newConfig);
        ViewPager viewPager = findViewById(R.id.profile_pager);
        ViewPager viewPager = findViewById(R.id.profile_pager);
        if (viewPager.isLayoutRtl()) {
        if (viewPager.isLayoutRtl()) {
@@ -1543,6 +1633,11 @@ public class ChooserActivity extends ResolverActivity implements
    @Override
    @Override
    protected void onDestroy() {
    protected void onDestroy() {
        super.onDestroy();
        super.onDestroy();

        if (mIsHeadlessSpringboardActivity) {
            return;
        }

        if (mRefinementResultReceiver != null) {
        if (mRefinementResultReceiver != null) {
            mRefinementResultReceiver.destroy();
            mRefinementResultReceiver.destroy();
            mRefinementResultReceiver = null;
            mRefinementResultReceiver = null;
+82 −2
Original line number Original line Diff line number Diff line
@@ -152,7 +152,7 @@ public class ResolverActivity extends Activity implements
    /** See {@link #setRetainInOnStop}. */
    /** See {@link #setRetainInOnStop}. */
    private boolean mRetainInOnStop;
    private boolean mRetainInOnStop;


    private static final int REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER = 20;
    protected static final int REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER = 20;


    private static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
    private static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
    private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
    private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
@@ -323,6 +323,86 @@ public class ResolverActivity extends Activity implements
        super.onCreate(savedInstanceState);
        super.onCreate(savedInstanceState);
    }
    }


    /**
     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
     * where we hand over to the unbundled chooser (while violating many of the invariants of a
     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
     * to opt-out of the normal ResolverActivity behavior.
     *
     * TODO: this should be removed later on in the unbundling migration, when the springboard
     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
     * implementations that depend on the invariants that are violated in the headless mode). If
     * necessary, we could instead consider using a springboard-only activity on the system side
     * immediately, which would delegate either to the unbundled chooser, or to a
     * (properly-inheriting) system ChooserActivity. This would have performance implications even
     * when the unbundling experiment is disabled.
     */
    protected void super_onRestart() {
        super.onRestart();
    }

    /**
     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
     * where we hand over to the unbundled chooser (while violating many of the invariants of a
     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
     * to opt-out of the normal ResolverActivity behavior.
     *
     * TODO: this should be removed later on in the unbundling migration, when the springboard
     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
     * implementations that depend on the invariants that are violated in the headless mode). If
     * necessary, we could instead consider using a springboard-only activity on the system side
     * immediately, which would delegate either to the unbundled chooser, or to a
     * (properly-inheriting) system ChooserActivity. This would have performance implications even
     * when the unbundling experiment is disabled.
     */
    protected void super_onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    /**
     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
     * where we hand over to the unbundled chooser (while violating many of the invariants of a
     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
     * to opt-out of the normal ResolverActivity behavior.
     *
     * TODO: this should be removed later on in the unbundling migration, when the springboard
     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
     * implementations that depend on the invariants that are violated in the headless mode). If
     * necessary, we could instead consider using a springboard-only activity on the system side
     * immediately, which would delegate either to the unbundled chooser, or to a
     * (properly-inheriting) system ChooserActivity. This would have performance implications even
     * when the unbundling experiment is disabled.
     */
    protected void super_onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    }

    /**
     * Pass-through API to support {@link ChooserActivity} running in "headless springboard" mode
     * where we hand over to the unbundled chooser (while violating many of the invariants of a
     * typical ResolverActivity implementation). Subclasses running in this mode need to be able
     * to opt-out of the normal ResolverActivity behavior.
     *
     * TODO: this should be removed later on in the unbundling migration, when the springboard
     * activity no longer needs to derive from ResolverActivity. The hold-over design here is
     * <em>not</em> good practice (e.g. there could be other events that weren't anticipated as
     * requiring this kind of "pass-through" override, and so might fall back on ResolverActivity
     * implementations that depend on the invariants that are violated in the headless mode). If
     * necessary, we could instead consider using a springboard-only activity on the system side
     * immediately, which would delegate either to the unbundled chooser, or to a
     * (properly-inheriting) system ChooserActivity. This would have performance implications even
     * when the unbundling experiment is disabled.
     */
    public void super_onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    protected void onCreate(Bundle savedInstanceState) {
        // Use a specialized prompt when we're handling the 'Home' app startActivity()
        // Use a specialized prompt when we're handling the 'Home' app startActivity()
@@ -877,7 +957,7 @@ public class ResolverActivity extends Activity implements
        }
        }
        final Intent intent = getIntent();
        final Intent intent = getIntent();
        if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
        if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
                && !mResolvingHome && !mRetainInOnStop) {
                && !mResolvingHome && !mRetainInOnStop && !mAwaitingDelegateResponse) {
            // This resolver is in the unusual situation where it has been
            // This resolver is in the unusual situation where it has been
            // launched at the top of a new task.  We don't let it be added
            // launched at the top of a new task.  We don't let it be added
            // to the recent tasks shown to the user, and we need to make sure
            // to the recent tasks shown to the user, and we need to make sure