From 2002cf5b463737e7f615f1469cb20d324c283544 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 8 Dec 2014 17:26:44 -0800 Subject: Fixing major regressions in Recents with multi-user. (Bug 18574950) In the process of front-loading a lot of the loading work, we moved logic into AlternateRecentsComponent, which is not multi-user friendly. This CL proxies all the necessary events for non-primary users to their own SystemUI process to ensure that they handle them correctly, and proxies visibility changes back to the primary user (since that is the only process with the right callbacks). Change-Id: I9fed92214ac4d4e2309ad6ffc35d09b5726c2880 --- packages/SystemUI/AndroidManifest.xml | 12 ++ .../src/com/android/systemui/recent/Recents.java | 44 +++-- .../recents/AlternateRecentsComponent.java | 217 ++++++++++++++++----- .../android/systemui/recents/RecentsActivity.java | 12 +- .../recents/RecentsUserEventProxyReceiver.java | 70 +++++++ .../systemui/recents/misc/SystemServicesProxy.java | 11 +- 6 files changed, 300 insertions(+), 66 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 0e69f74b0a1f..b606a6fb52ae 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -197,6 +197,7 @@ + + + + + + + + + + widgetInfo = - mSystemServicesProxy.bindSearchAppWidget(host); - if (widgetInfo != null) { - // Save the app widget id into the settings - mConfig.updateSearchBarAppWidgetId(mContext, widgetInfo.first); - } - } - } + reloadHeaderBarLayout(true); // When we start, preload the data associated with the previous recent tasks. // We can use a new plan since the caches will be the same. @@ -177,9 +226,19 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta mBootCompleted = true; } - /** Shows the recents */ - public void onShowRecents(boolean triggeredFromAltTab, View statusBarView) { - mStatusBarView = statusBarView; + /** Shows the Recents. */ + @ProxyFromPrimaryToCurrentUser + public void onShowRecents(boolean triggeredFromAltTab) { + if (mSystemServicesProxy.isForegroundUserOwner()) { + showRecents(triggeredFromAltTab); + } else { + Intent intent = createLocalBroadcastIntent(mContext, + RecentsUserEventProxyReceiver.ACTION_PROXY_SHOW_RECENTS_TO_USER); + intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + } + } + void showRecents(boolean triggeredFromAltTab) { mTriggeredFromAltTab = triggeredFromAltTab; try { @@ -189,16 +248,25 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } - /** Hides the recents */ + /** Hides the Recents. */ + @ProxyFromPrimaryToCurrentUser public void onHideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { + if (mSystemServicesProxy.isForegroundUserOwner()) { + hideRecents(triggeredFromAltTab, triggeredFromHomeKey); + } else { + Intent intent = createLocalBroadcastIntent(mContext, + RecentsUserEventProxyReceiver.ACTION_PROXY_HIDE_RECENTS_TO_USER); + intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab); + intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + } + } + void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { if (mBootCompleted) { ActivityManager.RunningTaskInfo topTask = getTopMostTask(); if (topTask != null && isRecentsTopMost(topTask, null)) { // Notify recents to hide itself - Intent intent = new Intent(ACTION_HIDE_RECENTS_ACTIVITY); - intent.setPackage(mContext.getPackageName()); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | - Intent.FLAG_RECEIVER_FOREGROUND); + Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY); intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab); intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey); mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); @@ -206,9 +274,18 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } - /** Toggles the alternate recents activity */ - public void onToggleRecents(View statusBarView) { - mStatusBarView = statusBarView; + /** Toggles the Recents activity. */ + @ProxyFromPrimaryToCurrentUser + public void onToggleRecents() { + if (mSystemServicesProxy.isForegroundUserOwner()) { + toggleRecents(); + } else { + Intent intent = createLocalBroadcastIntent(mContext, + RecentsUserEventProxyReceiver.ACTION_PROXY_TOGGLE_RECENTS_TO_USER); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + } + } + void toggleRecents() { mTriggeredFromAltTab = false; try { @@ -218,7 +295,18 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } + /** Preloads info for the Recents activity. */ + @ProxyFromPrimaryToCurrentUser public void onPreloadRecents() { + if (mSystemServicesProxy.isForegroundUserOwner()) { + preloadRecents(); + } else { + Intent intent = createLocalBroadcastIntent(mContext, + RecentsUserEventProxyReceiver.ACTION_PROXY_PRELOAD_RECENTS_TO_USER); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + } + } + void preloadRecents() { // Preload only the raw task list into a new load plan (which will be consumed by the // RecentsActivity) RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); @@ -309,15 +397,26 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta showRelativeAffiliatedTask(false); } + /** Updates on configuration change. */ + @ProxyFromPrimaryToCurrentUser public void onConfigurationChanged(Configuration newConfig) { + if (mSystemServicesProxy.isForegroundUserOwner()) { + configurationChanged(); + } else { + Intent intent = createLocalBroadcastIntent(mContext, + RecentsUserEventProxyReceiver.ACTION_PROXY_CONFIG_CHANGE_TO_USER); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + } + } + void configurationChanged() { // Don't reuse task stack views if the configuration changes mCanReuseTaskStackViews = false; // Reload the header bar layout - reloadHeaderBarLayout(); + reloadHeaderBarLayout(false); } /** Prepares the header bar layout. */ - void reloadHeaderBarLayout() { + void reloadHeaderBarLayout(boolean reloadWidget) { Resources res = mContext.getResources(); mWindowRect = mSystemServicesProxy.getWindowRect(); mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); @@ -325,6 +424,10 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width); mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy); mConfig.updateOnConfigurationChange(); + if (reloadWidget) { + // Reload the widget id before we get the task stack bounds + reloadSearchBarAppWidget(mContext, mSystemServicesProxy); + } mConfig.getTaskStackBounds(mWindowRect.width(), mWindowRect.height(), mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), mTaskStackBounds); if (mConfig.isLandscape && mConfig.hasTransposedNavBar) { @@ -350,6 +453,24 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight); } + /** Prepares the search bar app widget */ + void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) { + // Try and pre-emptively bind the search widget on startup to ensure that we + // have the right thumbnail bounds to animate to. + if (Constants.DebugFlags.App.EnableSearchLayout) { + // If there is no id, then bind a new search app widget + if (mConfig.searchBarAppWidgetId < 0) { + AppWidgetHost host = new RecentsAppWidgetHost(context, + Constants.Values.App.AppWidgetHostId); + Pair widgetInfo = ssp.bindSearchAppWidget(host); + if (widgetInfo != null) { + // Save the app widget id into the settings + mConfig.updateSearchBarAppWidgetId(context, widgetInfo.first); + } + } + } + } + /** Gets the top task. */ ActivityManager.RunningTaskInfo getTopMostTask() { SystemServicesProxy ssp = mSystemServicesProxy; @@ -397,10 +518,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta AtomicBoolean isTopTaskHome = new AtomicBoolean(true); if (topTask != null && isRecentsTopMost(topTask, isTopTaskHome)) { // Notify recents to toggle itself - Intent intent = new Intent(ACTION_TOGGLE_RECENTS_ACTIVITY); - intent.setPackage(mContext.getPackageName()); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | - Intent.FLAG_RECEIVER_FOREGROUND); + Intent intent = createLocalBroadcastIntent(mContext, ACTION_TOGGLE_RECENTS_ACTIVITY); mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); mLastToggleTime = SystemClock.elapsedRealtime(); return; @@ -474,7 +592,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } mStartAnimationTriggered = false; - return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView, + return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), toTaskRect.height(), this); } @@ -623,7 +741,19 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } /** Notifies the callbacks that the visibility of Recents has changed. */ - public static void notifyVisibilityChanged(boolean visible) { + @ProxyFromAnyToPrimaryUser + public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp, + boolean visible) { + if (ssp.isForegroundUserOwner()) { + visibilityChanged(visible); + } else { + Intent intent = createLocalBroadcastIntent(context, + ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER); + intent.putExtra(EXTRA_RECENTS_VISIBILITY, visible); + context.sendBroadcastAsUser(intent, UserHandle.OWNER); + } + } + static void visibilityChanged(boolean visible) { if (sRecentsComponentCallbacks != null) { sRecentsComponentCallbacks.onVisibilityChanged(visible); } @@ -667,10 +797,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta }; // Send the broadcast to notify Recents that the animation has started - Intent intent = new Intent(ACTION_START_ENTER_ANIMATION); - intent.setPackage(mContext.getPackageName()); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | - Intent.FLAG_RECEIVER_FOREGROUND); + Intent intent = createLocalBroadcastIntent(mContext, ACTION_START_ENTER_ANIMATION); mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, fallbackReceiver, null, Activity.RESULT_CANCELED, null, null); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 6baff9607f57..ee631f54f865 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -434,7 +434,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView protected void onStart() { super.onStart(); mVisible = true; - AlternateRecentsComponent.notifyVisibilityChanged(true); + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); + SystemServicesProxy ssp = loader.getSystemServicesProxy(); + AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, true); // Register the broadcast receiver to handle messages from our service IntentFilter filter = new IntentFilter(); @@ -444,7 +446,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView registerReceiver(mServiceBroadcastReceiver, filter); // Register any broadcast receivers for the task loader - RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView); + loader.registerReceivers(this, mRecentsView); // Update the recent tasks updateRecentsTasks(getIntent()); @@ -454,7 +456,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView protected void onStop() { super.onStop(); mVisible = false; - AlternateRecentsComponent.notifyVisibilityChanged(false); + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); + SystemServicesProxy ssp = loader.getSystemServicesProxy(); + AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, false); // Notify the views that we are no longer visible mRecentsView.onRecentsHidden(); @@ -463,7 +467,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView unregisterReceiver(mServiceBroadcastReceiver); // Unregister any broadcast receivers for the task loader - RecentsTaskLoader.getInstance().unregisterReceivers(); + loader.unregisterReceivers(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java new file mode 100644 index 000000000000..236da5dbec1f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import com.android.systemui.recent.Recents; + + +/** + * A proxy for Recents events which happens strictly for non-owner users. + */ +public class RecentsUserEventProxyReceiver extends BroadcastReceiver { + final public static String ACTION_PROXY_SHOW_RECENTS_TO_USER = + "com.android.systemui.recents.action.SHOW_RECENTS_FOR_USER"; + final public static String ACTION_PROXY_HIDE_RECENTS_TO_USER = + "com.android.systemui.recents.action.HIDE_RECENTS_FOR_USER"; + final public static String ACTION_PROXY_TOGGLE_RECENTS_TO_USER = + "com.android.systemui.recents.action.TOGGLE_RECENTS_FOR_USER"; + final public static String ACTION_PROXY_PRELOAD_RECENTS_TO_USER = + "com.android.systemui.recents.action.PRELOAD_RECENTS_FOR_USER"; + final public static String ACTION_PROXY_CONFIG_CHANGE_TO_USER = + "com.android.systemui.recents.action.CONFIG_CHANGED_FOR_USER"; + + @Override + public void onReceive(Context context, Intent intent) { + AlternateRecentsComponent recents = Recents.getRecentsComponent( + context.getApplicationContext(), true); + switch (intent.getAction()) { + case ACTION_PROXY_SHOW_RECENTS_TO_USER: { + boolean triggeredFromAltTab = intent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false); + recents.showRecents(triggeredFromAltTab); + break; + } + case ACTION_PROXY_HIDE_RECENTS_TO_USER: { + boolean triggeredFromAltTab = intent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false); + boolean triggeredFromHome = intent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false); + recents.hideRecents(triggeredFromAltTab, triggeredFromHome); + break; + } + case ACTION_PROXY_TOGGLE_RECENTS_TO_USER: + recents.toggleRecents(); + break; + case ACTION_PROXY_PRELOAD_RECENTS_TO_USER: + recents.preloadRecents(); + break; + case ACTION_PROXY_CONFIG_CHANGE_TO_USER: + recents.configurationChanged(); + break; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 3fbd5a6d344c..542f21cce816 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -49,14 +49,12 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.Pair; import android.view.Display; import android.view.DisplayInfo; -import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; @@ -395,6 +393,15 @@ public class SystemServicesProxy { return null; } + /** + * Returns whether the foreground user is the owner. + */ + public boolean isForegroundUserOwner() { + if (mAm == null) return false; + + return mAm.getCurrentUser() == UserHandle.USER_OWNER; + } + /** * Resolves and returns the first Recents widget from the same package as the global * assist activity. -- cgit v1.2.3-59-g8ed1b