Preload overview activity in background
To reduce the jank when swiping-up the overview which is not
ready yet, we restart the overview activity if the process
was died and update its configuration if there is change.
Bug: 127350205
Test: manual - Enable 2-button or gesture navigation.
Swipe-up overview after:
Case 1: Other app is in foreground and kill the process
of launcher.
Case 2: Change configuration, e.g. font size, language.
Change-Id: Ia6e365cc0faf3765781484d040bdddd4e10a2650
This commit is contained in:
@@ -43,6 +43,8 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
@@ -74,6 +76,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.logging.EventLogArray;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.model.AppLaunchTracker;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.LooperExecutor;
|
||||
import com.android.launcher3.util.UiThreadHelper;
|
||||
@@ -92,6 +95,7 @@ import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
|
||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.BackgroundExecutor;
|
||||
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
@@ -153,6 +157,7 @@ public class TouchInteractionService extends Service implements
|
||||
.asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
|
||||
MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
|
||||
MAIN_THREAD_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet);
|
||||
MAIN_THREAD_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -688,6 +693,54 @@ public class TouchInteractionService extends Service implements
|
||||
}
|
||||
}
|
||||
|
||||
private void preloadOverview(boolean fromInit) {
|
||||
if (!mIsUserUnlocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ActivityControlHelper<BaseDraggingActivity> activityControl =
|
||||
mOverviewComponentObserver.getActivityControlHelper();
|
||||
if (activityControl.getCreatedActivity() == null) {
|
||||
// Make sure that UI states will be initialized.
|
||||
activityControl.createActivityInitListener((activity, wasVisible) -> {
|
||||
AppLaunchTracker.INSTANCE.get(activity);
|
||||
return false;
|
||||
}).register();
|
||||
} else if (fromInit) {
|
||||
// The activity has been created before the initialization of overview service. It is
|
||||
// usually happens when booting or launcher is the top activity, so we should already
|
||||
// have the latest state.
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass null animation handler to indicate this start is preload.
|
||||
BackgroundExecutor.get().submit(
|
||||
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
|
||||
mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(),
|
||||
null /* assistDataReceiver */, null /* animationHandler */,
|
||||
null /* resultCallback */, null /* resultCallbackHandler */));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (!mIsUserUnlocked) {
|
||||
return;
|
||||
}
|
||||
final ActivityControlHelper activityControl =
|
||||
mOverviewComponentObserver.getActivityControlHelper();
|
||||
final BaseDraggingActivity activity = activityControl.getCreatedActivity();
|
||||
if (activity == null || activity.isStarted()) {
|
||||
// We only care about the existing background activity.
|
||||
return;
|
||||
}
|
||||
if (mOverviewComponentObserver.canHandleConfigChanges(activity.getComponentName(),
|
||||
activity.getResources().getConfiguration().diff(newConfig))) {
|
||||
return;
|
||||
}
|
||||
|
||||
preloadOverview(false /* fromInit */);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
|
||||
if (rawArgs.length > 0 && Utilities.IS_DEBUG_DEVICE) {
|
||||
|
||||
@@ -29,11 +29,15 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class to keep track of the current overview component based off user preferences and app updates
|
||||
@@ -53,22 +57,41 @@ public final class OverviewComponentObserver {
|
||||
}
|
||||
};
|
||||
private final Context mContext;
|
||||
private final ComponentName mMyHomeComponent;
|
||||
private final Intent mCurrentHomeIntent;
|
||||
private final Intent mMyHomeIntent;
|
||||
private final Intent mFallbackIntent;
|
||||
private final SparseIntArray mConfigChangesMap = new SparseIntArray();
|
||||
private String mUpdateRegisteredPackage;
|
||||
private ActivityControlHelper mActivityControlHelper;
|
||||
private Intent mOverviewIntent;
|
||||
private Intent mHomeIntent;
|
||||
private int mSystemUiStateFlags;
|
||||
private boolean mIsHomeAndOverviewSame;
|
||||
private boolean mIsDefaultHome;
|
||||
|
||||
public OverviewComponentObserver(Context context) {
|
||||
mContext = context;
|
||||
|
||||
Intent myHomeIntent = new Intent(Intent.ACTION_MAIN)
|
||||
mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME)
|
||||
.setPackage(mContext.getPackageName());
|
||||
ResolveInfo info = context.getPackageManager().resolveActivity(myHomeIntent, 0);
|
||||
mMyHomeComponent = new ComponentName(context.getPackageName(), info.activityInfo.name);
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(mContext.getPackageName());
|
||||
ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0);
|
||||
ComponentName myHomeComponent =
|
||||
new ComponentName(context.getPackageName(), info.activityInfo.name);
|
||||
mMyHomeIntent.setComponent(myHomeComponent);
|
||||
mConfigChangesMap.append(myHomeComponent.hashCode(), info.activityInfo.configChanges);
|
||||
|
||||
ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class);
|
||||
mFallbackIntent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
.setComponent(fallbackComponent)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
try {
|
||||
ActivityInfo fallbackInfo = context.getPackageManager().getActivityInfo(
|
||||
mFallbackIntent.getComponent(), 0 /* flags */);
|
||||
mConfigChangesMap.append(fallbackComponent.hashCode(), fallbackInfo.configChanges);
|
||||
} catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ }
|
||||
|
||||
mContext.registerReceiver(mUserPreferenceChangeReceiver,
|
||||
new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED));
|
||||
@@ -92,17 +115,14 @@ public final class OverviewComponentObserver {
|
||||
ComponentName defaultHome = PackageManagerWrapper.getInstance()
|
||||
.getHomeActivities(new ArrayList<>());
|
||||
|
||||
final String overviewIntentCategory;
|
||||
ComponentName overviewComponent;
|
||||
mHomeIntent = null;
|
||||
|
||||
if ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 &&
|
||||
(defaultHome == null || mMyHomeComponent.equals(defaultHome))) {
|
||||
mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome);
|
||||
if ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
|
||||
&& (defaultHome == null || mIsDefaultHome)) {
|
||||
// User default home is same as out home app. Use Overview integrated in Launcher.
|
||||
overviewComponent = mMyHomeComponent;
|
||||
mActivityControlHelper = new LauncherActivityControllerHelper();
|
||||
mIsHomeAndOverviewSame = true;
|
||||
overviewIntentCategory = Intent.CATEGORY_HOME;
|
||||
mOverviewIntent = mMyHomeIntent;
|
||||
mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
|
||||
|
||||
if (mUpdateRegisteredPackage != null) {
|
||||
// Remove any update listener as we don't care about other packages.
|
||||
@@ -111,14 +131,11 @@ public final class OverviewComponentObserver {
|
||||
}
|
||||
} else {
|
||||
// The default home app is a different launcher. Use the fallback Overview instead.
|
||||
overviewComponent = new ComponentName(mContext, RecentsActivity.class);
|
||||
mActivityControlHelper = new FallbackActivityControllerHelper();
|
||||
mIsHomeAndOverviewSame = false;
|
||||
overviewIntentCategory = Intent.CATEGORY_DEFAULT;
|
||||
mOverviewIntent = mFallbackIntent;
|
||||
mCurrentHomeIntent.setComponent(defaultHome);
|
||||
|
||||
mHomeIntent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME)
|
||||
.setComponent(defaultHome);
|
||||
// User's default home app can change as a result of package updates of this app (such
|
||||
// as uninstalling the app or removing the "Launcher" feature in an update).
|
||||
// Listen for package updates of this app (and remove any previously attached
|
||||
@@ -138,14 +155,6 @@ public final class OverviewComponentObserver {
|
||||
ACTION_PACKAGE_REMOVED));
|
||||
}
|
||||
}
|
||||
|
||||
mOverviewIntent = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(overviewIntentCategory)
|
||||
.setComponent(overviewComponent)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if (mHomeIntent == null) {
|
||||
mHomeIntent = mOverviewIntent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,6 +169,32 @@ public final class OverviewComponentObserver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the overview component is able to handle the configuration changes.
|
||||
*/
|
||||
boolean canHandleConfigChanges(ComponentName component, int changes) {
|
||||
final int orientationChange =
|
||||
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE;
|
||||
if ((changes & orientationChange) == orientationChange) {
|
||||
// This is just an approximate guess for simple orientation change because the changes
|
||||
// may contain non-public bits (e.g. window configuration).
|
||||
return true;
|
||||
}
|
||||
|
||||
int configMask = mConfigChangesMap.get(component.hashCode());
|
||||
return configMask != 0 && (~configMask & changes) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the intent for overview activity. It is used when lockscreen is shown and home was died
|
||||
* in background, we still want to restart the one that will be used after unlock.
|
||||
*
|
||||
* @return the overview intent
|
||||
*/
|
||||
Intent getOverviewIntentIgnoreSysUiState() {
|
||||
return mIsDefaultHome ? mMyHomeIntent : mOverviewIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current intent for going to the overview activity.
|
||||
*
|
||||
@@ -173,7 +208,7 @@ public final class OverviewComponentObserver {
|
||||
* Get the current intent for going to the home activity.
|
||||
*/
|
||||
public Intent getHomeIntent() {
|
||||
return mHomeIntent;
|
||||
return mCurrentHomeIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user