1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.quickstep; 18 19 import static android.content.Intent.ACTION_PACKAGE_ADDED; 20 import static android.content.Intent.ACTION_PACKAGE_CHANGED; 21 import static android.content.Intent.ACTION_PACKAGE_REMOVED; 22 23 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY; 24 import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter; 25 import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED; 26 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED; 27 28 import android.content.BroadcastReceiver; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.pm.ActivityInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.ResolveInfo; 36 import android.util.SparseIntArray; 37 38 import com.android.launcher3.util.SimpleBroadcastReceiver; 39 import com.android.systemui.shared.system.PackageManagerWrapper; 40 41 import java.io.PrintWriter; 42 import java.util.ArrayList; 43 import java.util.Objects; 44 import java.util.function.Consumer; 45 46 /** 47 * Class to keep track of the current overview component based off user preferences and app updates 48 * and provide callers the relevant classes. 49 */ 50 public final class OverviewComponentObserver { 51 private final BroadcastReceiver mUserPreferenceChangeReceiver = 52 new SimpleBroadcastReceiver(this::updateOverviewTargets); 53 private final BroadcastReceiver mOtherHomeAppUpdateReceiver = 54 new SimpleBroadcastReceiver(this::updateOverviewTargets); 55 56 private final Context mContext; 57 private final RecentsAnimationDeviceState mDeviceState; 58 private final Intent mCurrentHomeIntent; 59 private final Intent mMyHomeIntent; 60 private final Intent mFallbackIntent; 61 private final SparseIntArray mConfigChangesMap = new SparseIntArray(); 62 63 private Consumer<Boolean> mOverviewChangeListener = b -> { }; 64 65 private String mUpdateRegisteredPackage; 66 private BaseActivityInterface mActivityInterface; 67 private Intent mOverviewIntent; 68 private boolean mIsHomeAndOverviewSame; 69 private boolean mIsDefaultHome; 70 private boolean mIsHomeDisabled; 71 72 OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState)73 public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) { 74 mContext = context; 75 mDeviceState = deviceState; 76 mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN) 77 .addCategory(Intent.CATEGORY_HOME) 78 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 79 mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(mContext.getPackageName()); 80 ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0); 81 ComponentName myHomeComponent = 82 new ComponentName(context.getPackageName(), info.activityInfo.name); 83 mMyHomeIntent.setComponent(myHomeComponent); 84 mConfigChangesMap.append(myHomeComponent.hashCode(), info.activityInfo.configChanges); 85 86 ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class); 87 mFallbackIntent = new Intent(Intent.ACTION_MAIN) 88 .addCategory(Intent.CATEGORY_DEFAULT) 89 .setComponent(fallbackComponent) 90 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 91 92 try { 93 ActivityInfo fallbackInfo = context.getPackageManager().getActivityInfo( 94 mFallbackIntent.getComponent(), 0 /* flags */); 95 mConfigChangesMap.append(fallbackComponent.hashCode(), fallbackInfo.configChanges); 96 } catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ } 97 98 mContext.registerReceiver(mUserPreferenceChangeReceiver, 99 new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED)); 100 updateOverviewTargets(); 101 } 102 103 /** 104 * Sets a listener for changes in {@link #isHomeAndOverviewSame()} 105 */ setOverviewChangeListener(Consumer<Boolean> overviewChangeListener)106 public void setOverviewChangeListener(Consumer<Boolean> overviewChangeListener) { 107 mOverviewChangeListener = overviewChangeListener; 108 } 109 onSystemUiStateChanged()110 public void onSystemUiStateChanged() { 111 if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) { 112 updateOverviewTargets(); 113 } 114 } 115 updateOverviewTargets(Intent unused)116 private void updateOverviewTargets(Intent unused) { 117 updateOverviewTargets(); 118 } 119 assistantGestureIsConstrained()120 public boolean assistantGestureIsConstrained() { 121 return (mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0; 122 } 123 124 /** 125 * Update overview intent and {@link BaseActivityInterface} based off the current launcher home 126 * component. 127 */ updateOverviewTargets()128 private void updateOverviewTargets() { 129 ComponentName defaultHome = PackageManagerWrapper.getInstance() 130 .getHomeActivities(new ArrayList<>()); 131 132 mIsHomeDisabled = mDeviceState.isHomeDisabled(); 133 mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome); 134 135 // Set assistant visibility to 0 from launcher's perspective, ensures any elements that 136 // launcher made invisible become visible again before the new activity control helper 137 // becomes active. 138 if (mActivityInterface != null) { 139 mActivityInterface.onAssistantVisibilityChanged(0.f); 140 } 141 142 if (SEPARATE_RECENTS_ACTIVITY.get()) { 143 mIsDefaultHome = false; 144 if (defaultHome == null) { 145 defaultHome = mMyHomeIntent.getComponent(); 146 } 147 } 148 149 if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) { 150 // User default home is same as out home app. Use Overview integrated in Launcher. 151 mActivityInterface = LauncherActivityInterface.INSTANCE; 152 mIsHomeAndOverviewSame = true; 153 mOverviewIntent = mMyHomeIntent; 154 mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent()); 155 156 // Remove any update listener as we don't care about other packages. 157 unregisterOtherHomeAppUpdateReceiver(); 158 } else { 159 // The default home app is a different launcher. Use the fallback Overview instead. 160 161 mActivityInterface = FallbackActivityInterface.INSTANCE; 162 mIsHomeAndOverviewSame = false; 163 mOverviewIntent = mFallbackIntent; 164 mCurrentHomeIntent.setComponent(defaultHome); 165 166 // User's default home app can change as a result of package updates of this app (such 167 // as uninstalling the app or removing the "Launcher" feature in an update). 168 // Listen for package updates of this app (and remove any previously attached 169 // package listener). 170 if (defaultHome == null) { 171 unregisterOtherHomeAppUpdateReceiver(); 172 } else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) { 173 unregisterOtherHomeAppUpdateReceiver(); 174 175 mUpdateRegisteredPackage = defaultHome.getPackageName(); 176 mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter( 177 mUpdateRegisteredPackage, ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, 178 ACTION_PACKAGE_REMOVED)); 179 } 180 } 181 mOverviewChangeListener.accept(mIsHomeAndOverviewSame); 182 } 183 184 /** 185 * Clean up any registered receivers. 186 */ onDestroy()187 public void onDestroy() { 188 mContext.unregisterReceiver(mUserPreferenceChangeReceiver); 189 unregisterOtherHomeAppUpdateReceiver(); 190 } 191 unregisterOtherHomeAppUpdateReceiver()192 private void unregisterOtherHomeAppUpdateReceiver() { 193 if (mUpdateRegisteredPackage != null) { 194 mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver); 195 mUpdateRegisteredPackage = null; 196 } 197 } 198 199 /** 200 * @return {@code true} if the overview component is able to handle the configuration changes. 201 */ canHandleConfigChanges(ComponentName component, int changes)202 boolean canHandleConfigChanges(ComponentName component, int changes) { 203 final int orientationChange = 204 ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE; 205 if ((changes & orientationChange) == orientationChange) { 206 // This is just an approximate guess for simple orientation change because the changes 207 // may contain non-public bits (e.g. window configuration). 208 return true; 209 } 210 211 int configMask = mConfigChangesMap.get(component.hashCode()); 212 return configMask != 0 && (~configMask & changes) == 0; 213 } 214 215 /** 216 * Get the intent for overview activity. It is used when lockscreen is shown and home was died 217 * in background, we still want to restart the one that will be used after unlock. 218 * 219 * @return the overview intent 220 */ getOverviewIntentIgnoreSysUiState()221 Intent getOverviewIntentIgnoreSysUiState() { 222 return mIsDefaultHome ? mMyHomeIntent : mOverviewIntent; 223 } 224 225 /** 226 * Get the current intent for going to the overview activity. 227 * 228 * @return the overview intent 229 */ getOverviewIntent()230 public Intent getOverviewIntent() { 231 return mOverviewIntent; 232 } 233 234 /** 235 * Get the current intent for going to the home activity. 236 */ getHomeIntent()237 public Intent getHomeIntent() { 238 return mCurrentHomeIntent; 239 } 240 241 /** 242 * Returns true if home and overview are same activity. 243 */ isHomeAndOverviewSame()244 public boolean isHomeAndOverviewSame() { 245 return mIsHomeAndOverviewSame; 246 } 247 248 /** 249 * Get the current activity control helper for managing interactions to the overview activity. 250 * 251 * @return the current activity control helper 252 */ getActivityInterface()253 public BaseActivityInterface getActivityInterface() { 254 return mActivityInterface; 255 } 256 dump(PrintWriter pw)257 public void dump(PrintWriter pw) { 258 pw.println("OverviewComponentObserver:"); 259 pw.println(" isDefaultHome=" + mIsDefaultHome); 260 pw.println(" isHomeDisabled=" + mIsHomeDisabled); 261 pw.println(" homeAndOverviewSame=" + mIsHomeAndOverviewSame); 262 pw.println(" overviewIntent=" + mOverviewIntent); 263 pw.println(" homeIntent=" + mCurrentHomeIntent); 264 } 265 } 266