1 /* 2 * Copyright (C) 2014 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.systemui.recents; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 22 23 import android.annotation.Nullable; 24 import android.app.ActivityManager; 25 import android.app.trust.TrustManager; 26 import android.content.Context; 27 import android.graphics.Point; 28 import android.graphics.Rect; 29 import android.hardware.display.DisplayManager; 30 import android.os.Handler; 31 import android.os.RemoteException; 32 import android.util.Log; 33 import android.view.Display; 34 import android.widget.Toast; 35 36 import com.android.systemui.Dependency; 37 import com.android.systemui.R; 38 import com.android.systemui.shared.recents.IOverviewProxy; 39 import com.android.systemui.shared.system.ActivityManagerWrapper; 40 import com.android.systemui.stackdivider.Divider; 41 import com.android.systemui.statusbar.phone.StatusBar; 42 43 import java.util.Optional; 44 45 import javax.inject.Inject; 46 import javax.inject.Singleton; 47 48 import dagger.Lazy; 49 50 /** 51 * An implementation of the Recents interface which proxies to the OverviewProxyService. 52 */ 53 @Singleton 54 public class OverviewProxyRecentsImpl implements RecentsImplementation { 55 56 private final static String TAG = "OverviewProxyRecentsImpl"; 57 @Nullable 58 private final Lazy<StatusBar> mStatusBarLazy; 59 private final Optional<Divider> mDividerOptional; 60 61 private Context mContext; 62 private Handler mHandler; 63 private TrustManager mTrustManager; 64 private OverviewProxyService mOverviewProxyService; 65 66 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") 67 @Inject OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy, Optional<Divider> dividerOptional)68 public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy, 69 Optional<Divider> dividerOptional) { 70 mStatusBarLazy = statusBarLazy.orElse(null); 71 mDividerOptional = dividerOptional; 72 } 73 74 @Override onStart(Context context)75 public void onStart(Context context) { 76 mContext = context; 77 mHandler = new Handler(); 78 mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); 79 mOverviewProxyService = Dependency.get(OverviewProxyService.class); 80 } 81 82 @Override showRecentApps(boolean triggeredFromAltTab)83 public void showRecentApps(boolean triggeredFromAltTab) { 84 IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); 85 if (overviewProxy != null) { 86 try { 87 overviewProxy.onOverviewShown(triggeredFromAltTab); 88 return; 89 } catch (RemoteException e) { 90 Log.e(TAG, "Failed to send overview show event to launcher.", e); 91 } 92 } else { 93 // Do nothing 94 } 95 } 96 97 @Override hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)98 public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { 99 IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); 100 if (overviewProxy != null) { 101 try { 102 overviewProxy.onOverviewHidden(triggeredFromAltTab, triggeredFromHomeKey); 103 return; 104 } catch (RemoteException e) { 105 Log.e(TAG, "Failed to send overview hide event to launcher.", e); 106 } 107 } else { 108 // Do nothing 109 } 110 } 111 112 @Override toggleRecentApps()113 public void toggleRecentApps() { 114 // If connected to launcher service, let it handle the toggle logic 115 IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); 116 if (overviewProxy != null) { 117 final Runnable toggleRecents = () -> { 118 try { 119 if (mOverviewProxyService.getProxy() != null) { 120 mOverviewProxyService.getProxy().onOverviewToggle(); 121 mOverviewProxyService.notifyToggleRecentApps(); 122 } 123 } catch (RemoteException e) { 124 Log.e(TAG, "Cannot send toggle recents through proxy service.", e); 125 } 126 }; 127 // Preload only if device for current user is unlocked 128 if (mStatusBarLazy != null && mStatusBarLazy.get().isKeyguardShowing()) { 129 mStatusBarLazy.get().executeRunnableDismissingKeyguard(() -> { 130 // Flush trustmanager before checking device locked per user 131 mTrustManager.reportKeyguardShowingChanged(); 132 mHandler.post(toggleRecents); 133 }, null, true /* dismissShade */, false /* afterKeyguardGone */, 134 true /* deferred */); 135 } else { 136 toggleRecents.run(); 137 } 138 return; 139 } else { 140 // Do nothing 141 } 142 } 143 144 @Override splitPrimaryTask(int stackCreateMode, Rect initialBounds, int metricsDockAction)145 public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds, 146 int metricsDockAction) { 147 Point realSize = new Point(); 148 if (initialBounds == null) { 149 mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY) 150 .getRealSize(realSize); 151 initialBounds = new Rect(0, 0, realSize.x, realSize.y); 152 } 153 154 ActivityManager.RunningTaskInfo runningTask = 155 ActivityManagerWrapper.getInstance().getRunningTask(); 156 final int activityType = runningTask != null 157 ? runningTask.configuration.windowConfiguration.getActivityType() 158 : ACTIVITY_TYPE_UNDEFINED; 159 boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive(); 160 boolean isRunningTaskInHomeOrRecentsStack = 161 activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS; 162 if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) { 163 if (runningTask.supportsSplitScreenMultiWindow) { 164 if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary( 165 runningTask.id, stackCreateMode, initialBounds)) { 166 mDividerOptional.ifPresent(Divider::onDockedTopTask); 167 168 // The overview service is handling split screen, so just skip the wait for the 169 // first draw and notify the divider to start animating now 170 mDividerOptional.ifPresent(Divider::onRecentsDrawn); 171 172 return true; 173 } 174 } else { 175 Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, 176 Toast.LENGTH_SHORT).show(); 177 } 178 } 179 return false; 180 } 181 } 182