Home | History | Annotate | Download | only in quickstep
      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 package com.android.quickstep;
     17 
     18 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
     19 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
     20 
     21 import static com.android.launcher3.LauncherAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
     22 import static com.android.launcher3.LauncherAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION;
     23 import static com.android.quickstep.TaskUtils.getRecentsWindowAnimator;
     24 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
     25 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
     26 
     27 import android.animation.Animator;
     28 import android.animation.AnimatorListenerAdapter;
     29 import android.animation.AnimatorSet;
     30 import android.app.ActivityOptions;
     31 import android.content.Intent;
     32 import android.content.res.Configuration;
     33 import android.os.Bundle;
     34 import android.os.Handler;
     35 import android.os.Looper;
     36 import android.view.View;
     37 
     38 import com.android.launcher3.AbstractFloatingView;
     39 import com.android.launcher3.BaseDraggingActivity;
     40 import com.android.launcher3.DeviceProfile;
     41 import com.android.launcher3.InvariantDeviceProfile;
     42 import com.android.launcher3.ItemInfo;
     43 import com.android.launcher3.LauncherAnimationRunner;
     44 import com.android.launcher3.LauncherAppState;
     45 import com.android.launcher3.R;
     46 import com.android.launcher3.anim.Interpolators;
     47 import com.android.launcher3.badge.BadgeInfo;
     48 import com.android.launcher3.uioverrides.UiFactory;
     49 import com.android.launcher3.util.SystemUiController;
     50 import com.android.launcher3.util.Themes;
     51 import com.android.launcher3.views.BaseDragLayer;
     52 import com.android.quickstep.fallback.FallbackRecentsView;
     53 import com.android.quickstep.fallback.RecentsRootView;
     54 import com.android.quickstep.util.ClipAnimationHelper;
     55 import com.android.quickstep.views.RecentsViewContainer;
     56 import com.android.quickstep.views.TaskView;
     57 import com.android.systemui.shared.system.ActivityOptionsCompat;
     58 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
     59 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
     60 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
     61 
     62 import java.io.FileDescriptor;
     63 import java.io.PrintWriter;
     64 
     65 /**
     66  * A simple activity to show the recently launched tasks
     67  */
     68 public class RecentsActivity extends BaseDraggingActivity {
     69 
     70     private Handler mUiHandler = new Handler(Looper.getMainLooper());
     71     private RecentsRootView mRecentsRootView;
     72     private FallbackRecentsView mFallbackRecentsView;
     73     private RecentsViewContainer mOverviewPanelContainer;
     74 
     75     private Configuration mOldConfig;
     76 
     77     @Override
     78     protected void onCreate(Bundle savedInstanceState) {
     79         super.onCreate(savedInstanceState);
     80 
     81         mOldConfig = new Configuration(getResources().getConfiguration());
     82         initDeviceProfile();
     83 
     84         setContentView(R.layout.fallback_recents_activity);
     85         mRecentsRootView = findViewById(R.id.drag_layer);
     86         mFallbackRecentsView = findViewById(R.id.overview_panel);
     87         mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
     88 
     89         mRecentsRootView.setup();
     90 
     91         getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
     92                 Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
     93         RecentsActivityTracker.onRecentsActivityCreate(this);
     94     }
     95 
     96     @Override
     97     public void onConfigurationChanged(Configuration newConfig) {
     98         int diff = newConfig.diff(mOldConfig);
     99         if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
    100             onHandleConfigChanged();
    101         }
    102         mOldConfig.setTo(newConfig);
    103         super.onConfigurationChanged(newConfig);
    104     }
    105 
    106     @Override
    107     public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
    108         onHandleConfigChanged();
    109         super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
    110     }
    111 
    112     public void onRootViewSizeChanged() {
    113         if (isInMultiWindowModeCompat()) {
    114             onHandleConfigChanged();
    115         }
    116     }
    117 
    118     private void onHandleConfigChanged() {
    119         mUserEventDispatcher = null;
    120         initDeviceProfile();
    121 
    122         AbstractFloatingView.closeOpenViews(this, true,
    123                 AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
    124         dispatchDeviceProfileChanged();
    125 
    126         mRecentsRootView.setup();
    127         reapplyUi();
    128     }
    129 
    130     @Override
    131     protected void reapplyUi() {
    132         mRecentsRootView.dispatchInsets();
    133     }
    134 
    135     private void initDeviceProfile() {
    136         // In case we are reusing IDP, create a copy so that we dont conflict with Launcher
    137         // activity.
    138         LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
    139         if (isInMultiWindowModeCompat()) {
    140             InvariantDeviceProfile idp = appState == null
    141                     ? new InvariantDeviceProfile(this) : appState.getInvariantDeviceProfile();
    142             DeviceProfile dp = idp.getDeviceProfile(this);
    143             mDeviceProfile = mRecentsRootView == null ? dp.copy(this)
    144                     : dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize());
    145         } else {
    146             // If we are reusing the Invariant device profile, make a copy.
    147             mDeviceProfile = appState == null
    148                     ? new InvariantDeviceProfile(this).getDeviceProfile(this)
    149                     : appState.getInvariantDeviceProfile().getDeviceProfile(this).copy(this);
    150         }
    151         onDeviceProfileInitiated();
    152     }
    153 
    154     @Override
    155     public BaseDragLayer getDragLayer() {
    156         return mRecentsRootView;
    157     }
    158 
    159     @Override
    160     public View getRootView() {
    161         return mRecentsRootView;
    162     }
    163 
    164     @Override
    165     public <T extends View> T getOverviewPanel() {
    166         return (T) mFallbackRecentsView;
    167     }
    168 
    169     public RecentsViewContainer getOverviewPanelContainer() {
    170         return mOverviewPanelContainer;
    171     }
    172 
    173     @Override
    174     public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
    175         return null;
    176     }
    177 
    178     @Override
    179     public ActivityOptions getActivityLaunchOptions(final View v) {
    180         if (!(v instanceof TaskView)) {
    181             return null;
    182         }
    183 
    184         final TaskView taskView = (TaskView) v;
    185         RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler,
    186                 true /* startAtFrontOfQueue */) {
    187 
    188             @Override
    189             public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
    190                     AnimationResult result) {
    191                 result.setAnimation(composeRecentsLaunchAnimator(taskView, targetCompats));
    192             }
    193         };
    194         return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
    195                 runner, RECENTS_LAUNCH_DURATION,
    196                 RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION));
    197     }
    198 
    199     /**
    200      * Composes the animations for a launch from the recents list if possible.
    201      */
    202     private AnimatorSet composeRecentsLaunchAnimator(TaskView taskView,
    203             RemoteAnimationTargetCompat[] targets) {
    204         AnimatorSet target = new AnimatorSet();
    205         boolean activityClosing = taskIsATargetWithMode(targets, getTaskId(), MODE_CLOSING);
    206         ClipAnimationHelper helper = new ClipAnimationHelper();
    207         target.play(getRecentsWindowAnimator(taskView, !activityClosing, targets, helper)
    208                 .setDuration(RECENTS_LAUNCH_DURATION));
    209 
    210         // Found a visible recents task that matches the opening app, lets launch the app from there
    211         if (activityClosing) {
    212             Animator adjacentAnimation = mFallbackRecentsView
    213                     .createAdjacentPageAnimForTaskLaunch(taskView, helper);
    214             adjacentAnimation.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
    215             adjacentAnimation.setDuration(RECENTS_LAUNCH_DURATION);
    216             adjacentAnimation.addListener(new AnimatorListenerAdapter() {
    217                 @Override
    218                 public void onAnimationEnd(Animator animation) {
    219                     mFallbackRecentsView.resetTaskVisuals();
    220                 }
    221             });
    222             target.play(adjacentAnimation);
    223         }
    224         return target;
    225     }
    226 
    227     @Override
    228     public void invalidateParent(ItemInfo info) { }
    229 
    230     @Override
    231     protected void onStart() {
    232         // Set the alpha to 1 before calling super, as it may get set back to 0 due to
    233         // onActivityStart callback.
    234         mFallbackRecentsView.setContentAlpha(1);
    235         super.onStart();
    236         UiFactory.onStart(this);
    237         mFallbackRecentsView.resetTaskVisuals();
    238     }
    239 
    240     @Override
    241     protected void onStop() {
    242         super.onStop();
    243 
    244         // Workaround for b/78520668, explicitly trim memory once UI is hidden
    245         onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
    246     }
    247 
    248     @Override
    249     public void onTrimMemory(int level) {
    250         super.onTrimMemory(level);
    251         UiFactory.onTrimMemory(this, level);
    252     }
    253 
    254     @Override
    255     protected void onNewIntent(Intent intent) {
    256         super.onNewIntent(intent);
    257         RecentsActivityTracker.onRecentsActivityNewIntent(this);
    258     }
    259 
    260     @Override
    261     protected void onDestroy() {
    262         super.onDestroy();
    263         RecentsActivityTracker.onRecentsActivityDestroy(this);
    264     }
    265 
    266     @Override
    267     public void onBackPressed() {
    268         // TODO: Launch the task we came from
    269         startHome();
    270     }
    271 
    272     public void startHome() {
    273         startActivity(new Intent(Intent.ACTION_MAIN)
    274                 .addCategory(Intent.CATEGORY_HOME)
    275                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
    276     }
    277 
    278     @Override
    279     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
    280         super.dump(prefix, fd, writer, args);
    281         writer.println(prefix + "Misc:");
    282         dumpMisc(writer);
    283     }
    284 }
    285