• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.FlagDebugUtils.appendFlag;
20 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
21 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
22 
23 import static java.lang.annotation.RetentionPolicy.SOURCE;
24 
25 import android.app.Activity;
26 import android.content.Context;
27 import android.content.ContextWrapper;
28 import android.content.Intent;
29 import android.content.res.Configuration;
30 import android.os.Bundle;
31 import android.util.Log;
32 import android.view.View;
33 import android.window.OnBackInvokedDispatcher;
34 
35 import androidx.annotation.IntDef;
36 
37 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
38 import com.android.launcher3.logging.StatsLogManager;
39 import com.android.launcher3.testing.TestLogging;
40 import com.android.launcher3.testing.shared.TestProtocol;
41 import com.android.launcher3.util.SystemUiController;
42 import com.android.launcher3.util.ViewCache;
43 import com.android.launcher3.views.ActivityContext;
44 import com.android.launcher3.views.ScrimView;
45 
46 import java.io.PrintWriter;
47 import java.lang.annotation.Retention;
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.StringJoiner;
51 
52 /**
53  * Launcher BaseActivity
54  */
55 public abstract class BaseActivity extends Activity implements ActivityContext {
56 
57     private static final String TAG = "BaseActivity";
58     static final boolean DEBUG = false;
59 
60     public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
61     public static final int INVISIBLE_BY_APP_TRANSITIONS = 1 << 1;
62     public static final int INVISIBLE_BY_PENDING_FLAGS = 1 << 2;
63 
64     // This is not treated as invisibility flag, but adds as a hint for an incomplete transition.
65     // When the wallpaper animation runs, it replaces this flag with a proper invisibility
66     // flag, INVISIBLE_BY_PENDING_FLAGS only for the duration of that animation.
67     public static final int PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION = 1 << 3;
68 
69     private static final int INVISIBLE_FLAGS =
70             INVISIBLE_BY_STATE_HANDLER | INVISIBLE_BY_APP_TRANSITIONS | INVISIBLE_BY_PENDING_FLAGS;
71     public static final int STATE_HANDLER_INVISIBILITY_FLAGS =
72             INVISIBLE_BY_STATE_HANDLER | PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
73     public static final int INVISIBLE_ALL =
74             INVISIBLE_FLAGS | PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
75 
76     @Retention(SOURCE)
77     @IntDef(
78             flag = true,
79             value = {INVISIBLE_BY_STATE_HANDLER, INVISIBLE_BY_APP_TRANSITIONS,
80                     INVISIBLE_BY_PENDING_FLAGS, PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION})
81     public @interface InvisibilityFlags {
82     }
83 
84     private final ArrayList<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
85     private final ArrayList<MultiWindowModeChangedListener> mMultiWindowModeChangedListeners =
86             new ArrayList<>();
87 
88     protected DeviceProfile mDeviceProfile;
89     protected SystemUiController mSystemUiController;
90     private StatsLogManager mStatsLogManager;
91 
92 
93     public static final int ACTIVITY_STATE_STARTED = 1 << 0;
94     public static final int ACTIVITY_STATE_RESUMED = 1 << 1;
95 
96     /**
97      * State flags indicating that the activity has received one frame after resume, and was
98      * not immediately paused.
99      */
100     public static final int ACTIVITY_STATE_DEFERRED_RESUMED = 1 << 2;
101 
102     public static final int ACTIVITY_STATE_WINDOW_FOCUSED = 1 << 3;
103 
104     /**
105      * State flag indicating if the user is active or the activity when to background as a result
106      * of user action.
107      *
108      * @see #isUserActive()
109      */
110     public static final int ACTIVITY_STATE_USER_ACTIVE = 1 << 4;
111 
112     /**
113      * State flag indicating if the user will be active shortly.
114      */
115     public static final int ACTIVITY_STATE_USER_WILL_BE_ACTIVE = 1 << 5;
116 
117     /**
118      * State flag indicating that a state transition is in progress
119      */
120     public static final int ACTIVITY_STATE_TRANSITION_ACTIVE = 1 << 6;
121 
122     @Retention(SOURCE)
123     @IntDef(
124             flag = true,
125             value = {ACTIVITY_STATE_STARTED,
126                     ACTIVITY_STATE_RESUMED,
127                     ACTIVITY_STATE_DEFERRED_RESUMED,
128                     ACTIVITY_STATE_WINDOW_FOCUSED,
129                     ACTIVITY_STATE_USER_ACTIVE,
130                     ACTIVITY_STATE_TRANSITION_ACTIVE})
131     public @interface ActivityFlags {
132     }
133 
134     /** Returns a human-readable string for the specified {@link ActivityFlags}. */
getActivityStateString(@ctivityFlags int flags)135     public static String getActivityStateString(@ActivityFlags int flags) {
136         StringJoiner result = new StringJoiner("|");
137         appendFlag(result, flags, ACTIVITY_STATE_STARTED, "state_started");
138         appendFlag(result, flags, ACTIVITY_STATE_RESUMED, "state_resumed");
139         appendFlag(result, flags, ACTIVITY_STATE_DEFERRED_RESUMED, "state_deferred_resumed");
140         appendFlag(result, flags, ACTIVITY_STATE_WINDOW_FOCUSED, "state_window_focused");
141         appendFlag(result, flags, ACTIVITY_STATE_USER_ACTIVE, "state_user_active");
142         appendFlag(result, flags, ACTIVITY_STATE_TRANSITION_ACTIVE, "state_transition_active");
143         return result.toString();
144     }
145 
146     @ActivityFlags
147     private int mActivityFlags;
148 
149     // When the recents animation is running, the visibility of the Launcher is managed by the
150     // animation
151     @InvisibilityFlags
152     private int mForceInvisible;
153 
154     private final ViewCache mViewCache = new ViewCache();
155 
156     @Override
getViewCache()157     public ViewCache getViewCache() {
158         return mViewCache;
159     }
160 
161     @Override
getDeviceProfile()162     public DeviceProfile getDeviceProfile() {
163         return mDeviceProfile;
164     }
165 
166     @Override
getOnDeviceProfileChangeListeners()167     public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() {
168         return mDPChangeListeners;
169     }
170 
171     /**
172      * Returns {@link StatsLogManager} for user event logging.
173      */
174     @Override
getStatsLogManager()175     public StatsLogManager getStatsLogManager() {
176         if (mStatsLogManager == null) {
177             mStatsLogManager = StatsLogManager.newInstance(this);
178         }
179         return mStatsLogManager;
180     }
181 
getSystemUiController()182     public SystemUiController getSystemUiController() {
183         if (mSystemUiController == null) {
184             mSystemUiController = new SystemUiController(getWindow());
185         }
186         return mSystemUiController;
187     }
188 
getScrimView()189     public ScrimView getScrimView() {
190         return null;
191     }
192 
193     @Override
onActivityResult(int requestCode, int resultCode, Intent data)194     public void onActivityResult(int requestCode, int resultCode, Intent data) {
195         super.onActivityResult(requestCode, resultCode, data);
196     }
197 
198     @Override
onCreate(Bundle savedInstanceState)199     protected void onCreate(Bundle savedInstanceState) {
200         super.onCreate(savedInstanceState);
201         registerBackDispatcher();
202     }
203 
204     @Override
onStart()205     protected void onStart() {
206         addActivityFlags(ACTIVITY_STATE_STARTED);
207         super.onStart();
208     }
209 
210     @Override
onResume()211     protected void onResume() {
212         setResumed();
213         super.onResume();
214     }
215 
216     @Override
onUserLeaveHint()217     protected void onUserLeaveHint() {
218         removeActivityFlags(ACTIVITY_STATE_USER_ACTIVE);
219         super.onUserLeaveHint();
220     }
221 
222     @Override
onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig)223     public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
224         super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
225         for (int i = mMultiWindowModeChangedListeners.size() - 1; i >= 0; i--) {
226             mMultiWindowModeChangedListeners.get(i).onMultiWindowModeChanged(isInMultiWindowMode);
227         }
228     }
229 
230     @Override
onStop()231     protected void onStop() {
232         removeActivityFlags(ACTIVITY_STATE_STARTED | ACTIVITY_STATE_USER_ACTIVE);
233         mForceInvisible = 0;
234         super.onStop();
235 
236         // Reset the overridden sysui flags used for the task-swipe launch animation, this is a
237         // catch all for if we do not get resumed (and therefore not paused below)
238         getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
239     }
240 
241     @Override
onPause()242     protected void onPause() {
243         setPaused();
244         super.onPause();
245 
246         // Reset the overridden sysui flags used for the task-swipe launch animation, we do this
247         // here instead of at the end of the animation because the start of the new activity does
248         // not happen immediately, which would cause us to reset to launcher's sysui flags and then
249         // back to the new app (causing a flash)
250         getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
251     }
252 
253     @Override
onWindowFocusChanged(boolean hasFocus)254     public void onWindowFocusChanged(boolean hasFocus) {
255         super.onWindowFocusChanged(hasFocus);
256         if (hasFocus) {
257             addActivityFlags(ACTIVITY_STATE_WINDOW_FOCUSED);
258         } else {
259             removeActivityFlags(ACTIVITY_STATE_WINDOW_FOCUSED);
260         }
261 
262     }
263 
registerBackDispatcher()264     protected void registerBackDispatcher() {
265         if (Utilities.ATLEAST_T) {
266             getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
267                     OnBackInvokedDispatcher.PRIORITY_DEFAULT,
268                     () -> {
269                         onBackPressed();
270                         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
271                     });
272         }
273     }
274 
isStarted()275     public boolean isStarted() {
276         return (mActivityFlags & ACTIVITY_STATE_STARTED) != 0;
277     }
278 
279     /**
280      * isResumed in already defined as a hidden final method in Activity.java
281      */
hasBeenResumed()282     public boolean hasBeenResumed() {
283         return (mActivityFlags & ACTIVITY_STATE_RESUMED) != 0;
284     }
285 
286     /**
287      * Sets the activity to appear as paused.
288      */
setPaused()289     public void setPaused() {
290         removeActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_DEFERRED_RESUMED);
291     }
292 
293     /**
294      * Sets the activity to appear as resumed.
295      */
setResumed()296     public void setResumed() {
297         addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
298         removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
299     }
300 
isUserActive()301     public boolean isUserActive() {
302         return (mActivityFlags & ACTIVITY_STATE_USER_ACTIVE) != 0;
303     }
304 
getActivityFlags()305     public int getActivityFlags() {
306         return mActivityFlags;
307     }
308 
addActivityFlags(int toAdd)309     protected void addActivityFlags(int toAdd) {
310         final int oldFlags = mActivityFlags;
311         mActivityFlags |= toAdd;
312         if (DEBUG) {
313             Log.d(TAG, "Launcher flags updated: " + formatFlagChange(mActivityFlags, oldFlags,
314                     BaseActivity::getActivityStateString));
315         }
316         onActivityFlagsChanged(toAdd);
317     }
318 
removeActivityFlags(int toRemove)319     protected void removeActivityFlags(int toRemove) {
320         final int oldFlags = mActivityFlags;
321         mActivityFlags &= ~toRemove;
322         if (DEBUG) {
323             Log.d(TAG, "Launcher flags updated: " + formatFlagChange(mActivityFlags, oldFlags,
324                     BaseActivity::getActivityStateString));
325         }
326 
327         onActivityFlagsChanged(toRemove);
328     }
329 
onActivityFlagsChanged(int changeBits)330     protected void onActivityFlagsChanged(int changeBits) {
331     }
332 
addMultiWindowModeChangedListener(MultiWindowModeChangedListener listener)333     public void addMultiWindowModeChangedListener(MultiWindowModeChangedListener listener) {
334         mMultiWindowModeChangedListeners.add(listener);
335     }
336 
removeMultiWindowModeChangedListener(MultiWindowModeChangedListener listener)337     public void removeMultiWindowModeChangedListener(MultiWindowModeChangedListener listener) {
338         mMultiWindowModeChangedListeners.remove(listener);
339     }
340 
341     /**
342      * Used to set the override visibility state, used only to handle the transition home with the
343      * recents animation.
344      *
345      * @see QuickstepTransitionManager#createWallpaperOpenRunner
346      */
addForceInvisibleFlag(@nvisibilityFlags int flag)347     public void addForceInvisibleFlag(@InvisibilityFlags int flag) {
348         mForceInvisible |= flag;
349     }
350 
clearForceInvisibleFlag(@nvisibilityFlags int flag)351     public void clearForceInvisibleFlag(@InvisibilityFlags int flag) {
352         mForceInvisible &= ~flag;
353     }
354 
355     /**
356      * @return Wether this activity should be considered invisible regardless of actual visibility.
357      */
isForceInvisible()358     public boolean isForceInvisible() {
359         return hasSomeInvisibleFlag(INVISIBLE_FLAGS);
360     }
361 
hasSomeInvisibleFlag(int mask)362     public boolean hasSomeInvisibleFlag(int mask) {
363         return (mForceInvisible & mask) != 0;
364     }
365 
366     /**
367      * Attempts to clear accessibility focus on {@param view}.
368      */
tryClearAccessibilityFocus(View view)369     public void tryClearAccessibilityFocus(View view) {
370     }
371 
372     public interface MultiWindowModeChangedListener {
onMultiWindowModeChanged(boolean isInMultiWindowMode)373         void onMultiWindowModeChanged(boolean isInMultiWindowMode);
374     }
375 
dumpMisc(String prefix, PrintWriter writer)376     protected void dumpMisc(String prefix, PrintWriter writer) {
377         writer.println(prefix + "deviceProfile isTransposed="
378                 + getDeviceProfile().isVerticalBarLayout());
379         writer.println(prefix + "orientation=" + getResources().getConfiguration().orientation);
380         writer.println(prefix + "mSystemUiController: " + mSystemUiController);
381         writer.println(prefix + "mActivityFlags: " + getActivityStateString(mActivityFlags));
382         writer.println(prefix + "mForceInvisible: " + mForceInvisible);
383     }
384 
fromContext(Context context)385     public static <T extends BaseActivity> T fromContext(Context context) {
386         if (context instanceof BaseActivity) {
387             return (T) context;
388         } else if (context instanceof ContextWrapper) {
389             return fromContext(((ContextWrapper) context).getBaseContext());
390         } else {
391             throw new IllegalArgumentException("Cannot find BaseActivity in parent tree");
392         }
393     }
394 }
395