1 /*
2  * Copyright (C) 2021 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 package com.android.launcher3.taskbar;
17 
18 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
19 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
20 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
21 
22 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
23 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
24 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
25 import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
26 import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
27 
28 import android.animation.AnimatorSet;
29 import android.app.ActivityOptions;
30 import android.content.ActivityNotFoundException;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.pm.ActivityInfo.Config;
34 import android.content.pm.LauncherApps;
35 import android.content.res.Resources;
36 import android.graphics.Insets;
37 import android.graphics.PixelFormat;
38 import android.graphics.Rect;
39 import android.os.Process;
40 import android.os.SystemProperties;
41 import android.provider.Settings;
42 import android.util.Log;
43 import android.view.ContextThemeWrapper;
44 import android.view.Display;
45 import android.view.Gravity;
46 import android.view.LayoutInflater;
47 import android.view.RoundedCorner;
48 import android.view.View;
49 import android.view.WindowManager;
50 import android.widget.FrameLayout;
51 import android.widget.Toast;
52 
53 import androidx.annotation.NonNull;
54 import androidx.annotation.Nullable;
55 
56 import com.android.launcher3.AbstractFloatingView;
57 import com.android.launcher3.DeviceProfile;
58 import com.android.launcher3.LauncherSettings.Favorites;
59 import com.android.launcher3.R;
60 import com.android.launcher3.folder.Folder;
61 import com.android.launcher3.folder.FolderIcon;
62 import com.android.launcher3.logger.LauncherAtom;
63 import com.android.launcher3.model.data.FolderInfo;
64 import com.android.launcher3.model.data.WorkspaceItemInfo;
65 import com.android.launcher3.touch.ItemClickHandler;
66 import com.android.launcher3.util.PackageManagerHelper;
67 import com.android.launcher3.util.SettingsCache;
68 import com.android.launcher3.util.Themes;
69 import com.android.launcher3.util.TraceHelper;
70 import com.android.launcher3.util.ViewCache;
71 import com.android.launcher3.views.ActivityContext;
72 import com.android.quickstep.SysUINavigationMode;
73 import com.android.quickstep.SysUINavigationMode.Mode;
74 import com.android.systemui.shared.recents.model.Task;
75 import com.android.systemui.shared.rotation.RotationButtonController;
76 import com.android.systemui.shared.system.ActivityManagerWrapper;
77 import com.android.systemui.shared.system.WindowManagerWrapper;
78 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
79 
80 /**
81  * The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
82  * that are used by both Launcher and Taskbar (such as Folder) to reference a generic
83  * ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer.
84  */
85 public class TaskbarActivityContext extends ContextThemeWrapper implements ActivityContext {
86 
87     private static final boolean ENABLE_THREE_BUTTON_TASKBAR =
88             SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
89     private static final String TAG = "TaskbarActivityContext";
90 
91     private static final String WINDOW_TITLE = "Taskbar";
92 
93     private final DeviceProfile mDeviceProfile;
94     private final LayoutInflater mLayoutInflater;
95     private final TaskbarDragLayer mDragLayer;
96     private final TaskbarControllers mControllers;
97 
98     private final WindowManager mWindowManager;
99     private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
100     private final int mTaskbarHeightForIme;
101     private WindowManager.LayoutParams mWindowLayoutParams;
102     private boolean mIsFullscreen;
103     // The size we should return to when we call setTaskbarWindowFullscreen(false)
104     private int mLastRequestedNonFullscreenHeight;
105 
106     private final SysUINavigationMode.Mode mNavMode;
107     private final ViewCache mViewCache = new ViewCache();
108 
109     private final boolean mIsSafeModeEnabled;
110     private final boolean mIsUserSetupComplete;
111     private boolean mIsDestroyed = false;
112     // The flag to know if the window is excluded from magnification region computation.
113     private boolean mIsExcludeFromMagnificationRegion = false;
114 
TaskbarActivityContext(Context windowContext, DeviceProfile dp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider)115     public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
116             TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
117             unfoldTransitionProgressProvider) {
118         super(windowContext, Themes.getActivityThemeRes(windowContext));
119         mDeviceProfile = dp;
120 
121         mNavMode = SysUINavigationMode.getMode(windowContext);
122         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
123                 () -> getPackageManager().isSafeMode());
124         mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue(
125                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
126 
127         final Resources resources = getResources();
128         float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size);
129         mDeviceProfile.updateIconSize(1, resources);
130         float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
131         mDeviceProfile.updateIconSize(iconScale, resources);
132 
133         mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size);
134 
135         mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
136 
137         // Inflate views.
138         mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(
139                 R.layout.taskbar, null, false);
140         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
141         TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
142         FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
143         StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
144 
145         Display display = windowContext.getDisplay();
146         Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
147                 ? windowContext.getApplicationContext()
148                 : windowContext.getApplicationContext().createDisplayContext(display);
149         mWindowManager = c.getSystemService(WindowManager.class);
150         mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
151         mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
152 
153         // Construct controllers.
154         mControllers = new TaskbarControllers(this,
155                 new TaskbarDragController(this),
156                 buttonController,
157                 new NavbarButtonsViewController(this, navButtonsView),
158                 new RotationButtonController(this,
159                         c.getColor(R.color.taskbar_nav_icon_light_color),
160                         c.getColor(R.color.taskbar_nav_icon_dark_color),
161                         R.drawable.ic_sysbar_rotate_button_ccw_start_0,
162                         R.drawable.ic_sysbar_rotate_button_ccw_start_90,
163                         R.drawable.ic_sysbar_rotate_button_cw_start_0,
164                         R.drawable.ic_sysbar_rotate_button_cw_start_90,
165                         () -> getDisplay().getRotation()),
166                 new TaskbarDragLayerController(this, mDragLayer),
167                 new TaskbarViewController(this, taskbarView),
168                 new TaskbarScrimViewController(this, taskbarScrimView),
169                 new TaskbarUnfoldAnimationController(unfoldTransitionProgressProvider,
170                         mWindowManager),
171                 new TaskbarKeyguardController(this),
172                 new StashedHandleViewController(this, stashedHandleView),
173                 new TaskbarStashController(this),
174                 new TaskbarEduController(this),
175                 new TaskbarAutohideSuspendController(this),
176                 new TaskbarPopupController());
177     }
178 
init(TaskbarSharedState sharedState)179     public void init(TaskbarSharedState sharedState) {
180         mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
181         mWindowLayoutParams = new WindowManager.LayoutParams(
182                 MATCH_PARENT,
183                 mLastRequestedNonFullscreenHeight,
184                 TYPE_NAVIGATION_BAR_PANEL,
185                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
186                         | WindowManager.LayoutParams.FLAG_SLIPPERY,
187                 PixelFormat.TRANSLUCENT);
188         mWindowLayoutParams.setTitle(WINDOW_TITLE);
189         mWindowLayoutParams.packageName = getPackageName();
190         mWindowLayoutParams.gravity = Gravity.BOTTOM;
191         mWindowLayoutParams.setFitInsetsTypes(0);
192         mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
193         mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
194         mWindowLayoutParams.privateFlags =
195                 WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
196 
197         WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance();
198         wmWrapper.setProvidesInsetsTypes(
199                 mWindowLayoutParams,
200                 new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT }
201         );
202         // Adjust the frame by the rounded corners (ie. leaving just the bar as the inset) when
203         // the IME is showing
204         mWindowLayoutParams.providedInternalImeInsets = Insets.of(0,
205                 getDefaultTaskbarWindowHeight() - mTaskbarHeightForIme, 0, 0);
206 
207         // Initialize controllers after all are constructed.
208         mControllers.init(sharedState);
209         updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
210 
211         mWindowManager.addView(mDragLayer, mWindowLayoutParams);
212     }
213 
onConfigurationChanged(@onfig int configChanges)214     public void onConfigurationChanged(@Config int configChanges) {
215         mControllers.onConfigurationChanged(configChanges);
216     }
217 
isThreeButtonNav()218     public boolean isThreeButtonNav() {
219         return mNavMode == Mode.THREE_BUTTONS;
220     }
221 
getLeftCornerRadius()222     public int getLeftCornerRadius() {
223         return mLeftCorner == null ? 0 : mLeftCorner.getRadius();
224     }
225 
getRightCornerRadius()226     public int getRightCornerRadius() {
227         return mRightCorner == null ? 0 : mRightCorner.getRadius();
228     }
229 
230     @Override
getLayoutInflater()231     public LayoutInflater getLayoutInflater() {
232         return mLayoutInflater;
233     }
234 
235     @Override
getDragLayer()236     public TaskbarDragLayer getDragLayer() {
237         return mDragLayer;
238     }
239 
240     @Override
getDeviceProfile()241     public DeviceProfile getDeviceProfile() {
242         return mDeviceProfile;
243     }
244 
245     @Override
getFolderBoundingBox()246     public Rect getFolderBoundingBox() {
247         return mControllers.taskbarDragLayerController.getFolderBoundingBox();
248     }
249 
250     @Override
getDragController()251     public TaskbarDragController getDragController() {
252         return mControllers.taskbarDragController;
253     }
254 
255     @Override
getViewCache()256     public ViewCache getViewCache() {
257         return mViewCache;
258     }
259 
260     @Override
supportsIme()261     public boolean supportsIme() {
262         // Currently we don't support IME because we have FLAG_NOT_FOCUSABLE. We can remove that
263         // flag when opening a floating view that needs IME (such as Folder), but then that means
264         // Taskbar will be below IME and thus users can't click the back button.
265         return false;
266     }
267 
268     @Override
getItemOnClickListener()269     public View.OnClickListener getItemOnClickListener() {
270         return this::onTaskbarIconClicked;
271     }
272 
273     /**
274      * Change from hotseat/predicted hotseat to taskbar container.
275      */
276     @Override
applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder)277     public void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) {
278         if (!itemInfoBuilder.hasContainerInfo()) {
279             return;
280         }
281         LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo();
282 
283         if (oldContainer.hasPredictedHotseatContainer()) {
284             LauncherAtom.PredictedHotseatContainer predictedHotseat =
285                     oldContainer.getPredictedHotseatContainer();
286             LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
287                     LauncherAtom.TaskBarContainer.newBuilder();
288 
289             if (predictedHotseat.hasIndex()) {
290                 taskbarBuilder.setIndex(predictedHotseat.getIndex());
291             }
292             if (predictedHotseat.hasCardinality()) {
293                 taskbarBuilder.setCardinality(predictedHotseat.getCardinality());
294             }
295 
296             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
297                     .setTaskBarContainer(taskbarBuilder));
298         } else if (oldContainer.hasHotseat()) {
299             LauncherAtom.HotseatContainer hotseat = oldContainer.getHotseat();
300             LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
301                     LauncherAtom.TaskBarContainer.newBuilder();
302 
303             if (hotseat.hasIndex()) {
304                 taskbarBuilder.setIndex(hotseat.getIndex());
305             }
306 
307             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
308                     .setTaskBarContainer(taskbarBuilder));
309         } else if (oldContainer.hasFolder() && oldContainer.getFolder().hasHotseat()) {
310             LauncherAtom.FolderContainer.Builder folderBuilder = oldContainer.getFolder()
311                     .toBuilder();
312             LauncherAtom.HotseatContainer hotseat = folderBuilder.getHotseat();
313             LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
314                     LauncherAtom.TaskBarContainer.newBuilder();
315 
316             if (hotseat.hasIndex()) {
317                 taskbarBuilder.setIndex(hotseat.getIndex());
318             }
319 
320             folderBuilder.setTaskbar(taskbarBuilder);
321             folderBuilder.clearHotseat();
322             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
323                     .setFolder(folderBuilder));
324         }
325     }
326 
327     /**
328      * Sets a new data-source for this taskbar instance
329      */
setUIController(@onNull TaskbarUIController uiController)330     public void setUIController(@NonNull TaskbarUIController uiController) {
331         mControllers.uiController.onDestroy();
332         mControllers.uiController = uiController;
333         mControllers.uiController.init(mControllers);
334     }
335 
336     /**
337      * Sets the flag indicating setup UI is visible
338      */
setSetupUIVisible(boolean isVisible)339     public void setSetupUIVisible(boolean isVisible) {
340         mControllers.taskbarStashController.setSetupUIVisible(isVisible);
341     }
342 
343     /**
344      * Called when this instance of taskbar is no longer needed
345      */
onDestroy()346     public void onDestroy() {
347         mIsDestroyed = true;
348         setUIController(TaskbarUIController.DEFAULT);
349         mControllers.onDestroy();
350         mWindowManager.removeViewImmediate(mDragLayer);
351     }
352 
updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit)353     public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
354         mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
355                 fromInit);
356         mControllers.taskbarViewController.setImeIsVisible(
357                 mControllers.navbarButtonsViewController.isImeVisible());
358         int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
359                 | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
360         onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0, fromInit);
361         mControllers.taskbarViewController.setRecentsButtonDisabled(
362                 mControllers.navbarButtonsViewController.isRecentsDisabled());
363         mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
364                 mControllers.navbarButtonsViewController.isHomeDisabled());
365         mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
366         mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
367         mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
368                 fromInit);
369         mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
370     }
371 
372     /**
373      * Hides the taskbar icons and background when the notication shade is expanded.
374      */
onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim)375     private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
376         float alpha = isExpanded ? 0 : 1;
377         AnimatorSet anim = new AnimatorSet();
378         anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().getProperty(
379                 TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
380         if (!isThreeButtonNav()) {
381             anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
382                     .animateToValue(alpha));
383         }
384         anim.start();
385         if (skipAnim) {
386             anim.end();
387         }
388     }
389 
onRotationProposal(int rotation, boolean isValid)390     public void onRotationProposal(int rotation, boolean isValid) {
391         mControllers.rotationButtonController.onRotationProposal(rotation, isValid);
392     }
393 
disableNavBarElements(int displayId, int state1, int state2, boolean animate)394     public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
395         if (displayId != getDisplayId()) {
396             return;
397         }
398         mControllers.rotationButtonController.onDisable2FlagChanged(state2);
399     }
400 
onSystemBarAttributesChanged(int displayId, int behavior)401     public void onSystemBarAttributesChanged(int displayId, int behavior) {
402         mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
403     }
404 
onNavButtonsDarkIntensityChanged(float darkIntensity)405     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
406         if (!isUserSetupComplete()) {
407             return;
408         }
409         mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
410                 .updateValue(darkIntensity);
411     }
412 
413     /**
414      * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
415      */
setTaskbarWindowFullscreen(boolean fullscreen)416     public void setTaskbarWindowFullscreen(boolean fullscreen) {
417         mControllers.taskbarAutohideSuspendController.updateFlag(
418                 TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
419         mIsFullscreen = fullscreen;
420         setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
421     }
422 
isTaskbarWindowFullscreen()423     public boolean isTaskbarWindowFullscreen() {
424         return mIsFullscreen;
425     }
426 
427     /**
428      * Updates the TaskbarContainer height (pass {@link #getDefaultTaskbarWindowHeight()} to reset).
429      */
setTaskbarWindowHeight(int height)430     public void setTaskbarWindowHeight(int height) {
431         if (mWindowLayoutParams.height == height || mIsDestroyed) {
432             return;
433         }
434         if (height == MATCH_PARENT) {
435             height = mDeviceProfile.heightPx;
436         } else {
437             mLastRequestedNonFullscreenHeight = height;
438             if (mIsFullscreen) {
439                 // We still need to be fullscreen, so defer any change to our height until we call
440                 // setTaskbarWindowFullscreen(false). For example, this could happen when dragging
441                 // from the gesture region, as the drag will cancel the gesture and reset launcher's
442                 // state, which in turn normally would reset the taskbar window height as well.
443                 return;
444             }
445         }
446         mWindowLayoutParams.height = height;
447         mWindowLayoutParams.providedInternalImeInsets =
448                 Insets.of(0, height - mTaskbarHeightForIme, 0, 0);
449         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
450     }
451 
452     /**
453      * Returns the default height of the window, including the static corner radii above taskbar.
454      */
getDefaultTaskbarWindowHeight()455     public int getDefaultTaskbarWindowHeight() {
456         return mDeviceProfile.taskbarSize + Math.max(getLeftCornerRadius(), getRightCornerRadius());
457     }
458 
459     /**
460      * Returns the bottom insets taskbar provides to the IME when IME is visible.
461      */
getTaskbarHeightForIme()462     public int getTaskbarHeightForIme() {
463         return mTaskbarHeightForIme;
464     }
465 
onTaskbarIconClicked(View view)466     protected void onTaskbarIconClicked(View view) {
467         Object tag = view.getTag();
468         if (tag instanceof Task) {
469             Task task = (Task) tag;
470             ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
471                     ActivityOptions.makeBasic());
472         } else if (tag instanceof FolderInfo) {
473             FolderIcon folderIcon = (FolderIcon) view;
474             Folder folder = folderIcon.getFolder();
475             setTaskbarWindowFullscreen(true);
476 
477             getDragLayer().post(() -> {
478                 folder.animateOpen();
479                 getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
480 
481                 folder.iterateOverItems((itemInfo, itemView) -> {
482                     mControllers.taskbarViewController
483                             .setClickAndLongClickListenersForIcon(itemView);
484                     // To play haptic when dragging, like other Taskbar items do.
485                     itemView.setHapticFeedbackEnabled(true);
486                     return false;
487                 });
488             });
489         } else if (tag instanceof WorkspaceItemInfo) {
490             WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
491             if (info.isDisabled()) {
492                 ItemClickHandler.handleDisabledItemClicked(info, this);
493             } else {
494                 Intent intent = new Intent(info.getIntent())
495                         .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
496                 try {
497                     if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
498                         Toast.makeText(this, R.string.safemode_shortcut_error,
499                                 Toast.LENGTH_SHORT).show();
500                     } else  if (info.isPromise()) {
501                         intent = new PackageManagerHelper(this)
502                                 .getMarketIntent(info.getTargetPackage())
503                                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
504                         startActivity(intent);
505 
506                     } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
507                         String id = info.getDeepShortcutId();
508                         String packageName = intent.getPackage();
509                         getSystemService(LauncherApps.class)
510                                 .startShortcut(packageName, id, null, null, info.user);
511                     } else if (info.user.equals(Process.myUserHandle())) {
512                         startActivity(intent);
513                     } else {
514                         getSystemService(LauncherApps.class).startMainActivity(
515                                 intent.getComponent(), info.user, intent.getSourceBounds(), null);
516                     }
517 
518                     mControllers.uiController.onTaskbarIconLaunched(info);
519                 } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
520                     Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
521                             .show();
522                     Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
523                 }
524             }
525         } else {
526             Log.e(TAG, "Unknown type clicked: " + tag);
527         }
528 
529         AbstractFloatingView.closeAllOpenViews(this);
530     }
531 
532     /**
533      * Called when we detect a long press in the nav region before passing the gesture slop.
534      * @return Whether taskbar handled the long press, and thus should cancel the gesture.
535      */
onLongPressToUnstashTaskbar()536     public boolean onLongPressToUnstashTaskbar() {
537         return mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
538     }
539 
540     /**
541      * Called when we detect a motion down or up/cancel in the nav region while stashed.
542      * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
543      */
startTaskbarUnstashHint(boolean animateForward)544     public void startTaskbarUnstashHint(boolean animateForward) {
545         mControllers.taskbarStashController.startUnstashHint(animateForward);
546     }
547 
isUserSetupComplete()548     protected boolean isUserSetupComplete() {
549         return mIsUserSetupComplete;
550     }
551 
552     /**
553      * Called when we determine the touchable region.
554      *
555      * @param exclude {@code true} then the magnification region computation will omit the window.
556      */
excludeFromMagnificationRegion(boolean exclude)557     public void excludeFromMagnificationRegion(boolean exclude) {
558         if (mIsExcludeFromMagnificationRegion == exclude) {
559             return;
560         }
561 
562         mIsExcludeFromMagnificationRegion = exclude;
563         if (exclude) {
564             mWindowLayoutParams.privateFlags |=
565                     WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
566         } else {
567             mWindowLayoutParams.privateFlags &=
568                     ~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
569         }
570         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
571     }
572 }
573