1 /* 2 * Copyright (C) 2018 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.launcher3; 18 19 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION; 20 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 21 22 import android.app.WallpaperColors; 23 import android.app.WallpaperManager; 24 import android.app.WallpaperManager.OnColorsChangedListener; 25 import android.content.Context; 26 import android.content.res.Configuration; 27 import android.graphics.Point; 28 import android.graphics.Rect; 29 import android.os.Bundle; 30 import android.view.ActionMode; 31 import android.view.Display; 32 import android.view.View; 33 34 import androidx.annotation.NonNull; 35 import androidx.annotation.Nullable; 36 37 import com.android.launcher3.model.data.ItemInfo; 38 import com.android.launcher3.touch.ItemClickHandler; 39 import com.android.launcher3.util.ActivityOptionsWrapper; 40 import com.android.launcher3.util.DisplayController; 41 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; 42 import com.android.launcher3.util.DisplayController.Info; 43 import com.android.launcher3.util.RunnableList; 44 import com.android.launcher3.util.Themes; 45 import com.android.launcher3.util.TraceHelper; 46 import com.android.launcher3.util.WindowBounds; 47 48 /** 49 * Extension of BaseActivity allowing support for drag-n-drop 50 */ 51 @SuppressWarnings("NewApi") 52 public abstract class BaseDraggingActivity extends BaseActivity 53 implements OnColorsChangedListener, DisplayInfoChangeListener { 54 55 private static final String TAG = "BaseDraggingActivity"; 56 57 // When starting an action mode, setting this tag will cause the action mode to be cancelled 58 // automatically when user interacts with the launcher. 59 public static final Object AUTO_CANCEL_ACTION_MODE = new Object(); 60 61 private ActionMode mCurrentActionMode; 62 protected boolean mIsSafeModeEnabled; 63 64 private Runnable mOnStartCallback; 65 private RunnableList mOnResumeCallbacks = new RunnableList(); 66 67 private int mThemeRes = R.style.AppTheme; 68 69 @Override onCreate(Bundle savedInstanceState)70 protected void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 73 mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode", 74 () -> getPackageManager().isSafeMode()); 75 DisplayController.INSTANCE.get(this).addChangeListener(this); 76 77 // Update theme 78 if (Utilities.ATLEAST_P) { 79 getSystemService(WallpaperManager.class) 80 .addOnColorsChangedListener(this, MAIN_EXECUTOR.getHandler()); 81 } 82 int themeRes = Themes.getActivityThemeRes(this); 83 if (themeRes != mThemeRes) { 84 mThemeRes = themeRes; 85 setTheme(themeRes); 86 } 87 } 88 89 @Override onResume()90 protected void onResume() { 91 super.onResume(); 92 mOnResumeCallbacks.executeAllAndClear(); 93 } 94 addOnResumeCallback(Runnable callback)95 public void addOnResumeCallback(Runnable callback) { 96 mOnResumeCallbacks.add(callback); 97 } 98 99 @Override onColorsChanged(WallpaperColors wallpaperColors, int which)100 public void onColorsChanged(WallpaperColors wallpaperColors, int which) { 101 updateTheme(); 102 } 103 104 @Override onConfigurationChanged(Configuration newConfig)105 public void onConfigurationChanged(Configuration newConfig) { 106 super.onConfigurationChanged(newConfig); 107 updateTheme(); 108 } 109 updateTheme()110 private void updateTheme() { 111 if (mThemeRes != Themes.getActivityThemeRes(this)) { 112 recreate(); 113 } 114 } 115 116 @Override onActionModeStarted(ActionMode mode)117 public void onActionModeStarted(ActionMode mode) { 118 super.onActionModeStarted(mode); 119 mCurrentActionMode = mode; 120 } 121 122 @Override onActionModeFinished(ActionMode mode)123 public void onActionModeFinished(ActionMode mode) { 124 super.onActionModeFinished(mode); 125 mCurrentActionMode = null; 126 } 127 isInAutoCancelActionMode()128 protected boolean isInAutoCancelActionMode() { 129 return mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag(); 130 } 131 132 @Override finishAutoCancelActionMode()133 public boolean finishAutoCancelActionMode() { 134 if (isInAutoCancelActionMode()) { 135 mCurrentActionMode.finish(); 136 return true; 137 } 138 return false; 139 } 140 getOverviewPanel()141 public abstract <T extends View> T getOverviewPanel(); 142 getRootView()143 public abstract View getRootView(); 144 returnToHomescreen()145 public void returnToHomescreen() { 146 // no-op 147 } 148 149 @Override 150 @NonNull getActivityLaunchOptions(View v, @Nullable ItemInfo item)151 public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { 152 ActivityOptionsWrapper wrapper = super.getActivityLaunchOptions(v, item); 153 addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy); 154 return wrapper; 155 } 156 157 @Override onStart()158 protected void onStart() { 159 super.onStart(); 160 161 if (mOnStartCallback != null) { 162 mOnStartCallback.run(); 163 mOnStartCallback = null; 164 } 165 } 166 167 @Override onDestroy()168 protected void onDestroy() { 169 super.onDestroy(); 170 if (Utilities.ATLEAST_P) { 171 getSystemService(WallpaperManager.class).removeOnColorsChangedListener(this); 172 } 173 DisplayController.INSTANCE.get(this).removeChangeListener(this); 174 } 175 runOnceOnStart(Runnable action)176 public void runOnceOnStart(Runnable action) { 177 mOnStartCallback = action; 178 } 179 clearRunOnceOnStartCallback()180 public void clearRunOnceOnStartCallback() { 181 mOnStartCallback = null; 182 } 183 onDeviceProfileInitiated()184 protected void onDeviceProfileInitiated() { 185 if (mDeviceProfile.isVerticalBarLayout()) { 186 mDeviceProfile.updateIsSeascape(this); 187 } 188 } 189 190 @Override onDisplayInfoChanged(Context context, Info info, int flags)191 public void onDisplayInfoChanged(Context context, Info info, int flags) { 192 if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.updateIsSeascape(this)) { 193 reapplyUi(); 194 } 195 } 196 197 @Override getItemOnClickListener()198 public View.OnClickListener getItemOnClickListener() { 199 return ItemClickHandler.INSTANCE; 200 } 201 reapplyUi()202 protected abstract void reapplyUi(); 203 getMultiWindowDisplaySize()204 protected WindowBounds getMultiWindowDisplaySize() { 205 if (Utilities.ATLEAST_R) { 206 return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics()); 207 } 208 // Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return 209 // the app window size 210 Display display = getWindowManager().getDefaultDisplay(); 211 Point mwSize = new Point(); 212 display.getSize(mwSize); 213 return new WindowBounds(new Rect(0, 0, mwSize.x, mwSize.y), new Rect()); 214 } 215 216 @Override isAppBlockedForSafeMode()217 public boolean isAppBlockedForSafeMode() { 218 return mIsSafeModeEnabled; 219 } 220 } 221