1 /* 2 * Copyright (C) 2023 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.car.taskview; 18 19 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 20 21 import android.app.ActivityManager; 22 import android.app.ActivityTaskManager; 23 import android.car.Car; 24 import android.car.app.CarActivityManager; 25 import android.car.app.CarSystemUIProxy; 26 import android.car.app.CarTaskViewClient; 27 import android.car.app.CarTaskViewHost; 28 import android.content.Context; 29 import android.content.pm.PackageManager; 30 import android.hardware.display.DisplayManager; 31 import android.os.Process; 32 import android.util.Slog; 33 import android.view.Display; 34 35 import androidx.annotation.NonNull; 36 37 import com.android.systemui.Dumpable; 38 import com.android.systemui.R; 39 import com.android.systemui.car.CarServiceProvider; 40 import com.android.systemui.dump.DumpManager; 41 import com.android.wm.shell.ShellTaskOrganizer; 42 import com.android.wm.shell.common.SyncTransactionQueue; 43 import com.android.wm.shell.dagger.WMSingleton; 44 import com.android.wm.shell.taskview.TaskViewTransitions; 45 46 import java.io.PrintWriter; 47 import java.util.HashSet; 48 import java.util.List; 49 import java.util.Set; 50 51 import javax.inject.Inject; 52 53 /** 54 * This class provides a concrete implementation for {@link CarSystemUIProxy}. It hosts all the 55 * system ui interaction that is required by other apps. 56 */ 57 @WMSingleton 58 public final class CarSystemUIProxyImpl 59 implements CarSystemUIProxy, CarServiceProvider.CarServiceOnConnectedListener, Dumpable { 60 private static final String TAG = CarSystemUIProxyImpl.class.getSimpleName(); 61 62 private final Context mContext; 63 private final SyncTransactionQueue mSyncQueue; 64 private final ShellTaskOrganizer mTaskOrganizer; 65 private final TaskViewTransitions mTaskViewTransitions; 66 private final Set<RemoteCarTaskViewServerImpl> mRemoteCarTaskViewServerSet = new HashSet<>(); 67 private final DisplayManager mDisplayManager; 68 69 private boolean mConnected; 70 private CarActivityManager mCarActivityManager; 71 72 /** 73 * Returns true if {@link CarSystemUIProxyImpl} should be registered, false otherwise. 74 * This could be false because of reasons like: 75 * <ul> 76 * <li>Current user is not a system user.</li> 77 * <li>Or {@code config_registerCarSystemUIProxy} is disabled.</li> 78 * </ul> 79 */ shouldRegisterCarSystemUIProxy(Context context)80 public static boolean shouldRegisterCarSystemUIProxy(Context context) { 81 if (!Process.myUserHandle().isSystem()) { 82 Slog.i(TAG, "Non system user."); 83 return false; 84 } 85 if (!context.getResources().getBoolean(R.bool.config_registerCarSystemUIProxy)) { 86 Slog.i(TAG, "config_registerCarSystemUIProxy disabled"); 87 return false; 88 } 89 return true; 90 } 91 92 @Inject CarSystemUIProxyImpl( Context context, CarServiceProvider carServiceProvider, SyncTransactionQueue syncTransactionQueue, ShellTaskOrganizer taskOrganizer, TaskViewTransitions taskViewTransitions, DumpManager dumpManager)93 CarSystemUIProxyImpl( 94 Context context, 95 CarServiceProvider carServiceProvider, 96 SyncTransactionQueue syncTransactionQueue, 97 ShellTaskOrganizer taskOrganizer, 98 TaskViewTransitions taskViewTransitions, 99 DumpManager dumpManager) { 100 mContext = context; 101 mTaskOrganizer = taskOrganizer; 102 mSyncQueue = syncTransactionQueue; 103 mTaskViewTransitions = taskViewTransitions; 104 mDisplayManager = mContext.getSystemService(DisplayManager.class); 105 dumpManager.registerDumpable(this); 106 107 if (!shouldRegisterCarSystemUIProxy(mContext)) { 108 Slog.i(TAG, "Not registering CarSystemUIProxy."); 109 return; 110 } 111 carServiceProvider.addListener(this); 112 } 113 isLaunchRootTaskPresent(int displayId)114 boolean isLaunchRootTaskPresent(int displayId) { 115 for (RemoteCarTaskViewServerImpl remoteCarTaskViewServer : mRemoteCarTaskViewServerSet) { 116 if (remoteCarTaskViewServer.hasLaunchRootTaskOnDisplay(displayId)) { 117 return true; 118 } 119 } 120 return false; 121 } 122 123 @Override createControlledCarTaskView(CarTaskViewClient carTaskViewClient)124 public CarTaskViewHost createControlledCarTaskView(CarTaskViewClient carTaskViewClient) { 125 return createCarTaskView(carTaskViewClient); 126 } 127 128 @Override createCarTaskView(CarTaskViewClient carTaskViewClient)129 public CarTaskViewHost createCarTaskView(CarTaskViewClient carTaskViewClient) { 130 ensurePermission(Car.PERMISSION_MANAGE_CAR_SYSTEM_UI); 131 RemoteCarTaskViewServerImpl remoteCarTaskViewServerImpl = 132 new RemoteCarTaskViewServerImpl( 133 mContext, 134 mTaskOrganizer, 135 mSyncQueue, 136 carTaskViewClient, 137 this, 138 mTaskViewTransitions, mCarActivityManager); 139 mRemoteCarTaskViewServerSet.add(remoteCarTaskViewServerImpl); 140 return remoteCarTaskViewServerImpl.getHostImpl(); 141 } 142 onCarTaskViewReleased(RemoteCarTaskViewServerImpl remoteCarTaskViewServer)143 void onCarTaskViewReleased(RemoteCarTaskViewServerImpl remoteCarTaskViewServer) { 144 mRemoteCarTaskViewServerSet.remove(remoteCarTaskViewServer); 145 } 146 147 @Override onConnected(Car car)148 public void onConnected(Car car) { 149 mConnected = true; 150 removeExistingTaskViewTasks(); 151 152 mCarActivityManager = car.getCarManager(CarActivityManager.class); 153 mCarActivityManager.registerTaskMonitor(); 154 mCarActivityManager.registerCarSystemUIProxy(this); 155 } 156 157 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)158 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 159 pw.println(" user:" + mContext.getUserId()); 160 pw.println(" shouldRegisterCarSystemUiProxy:" + shouldRegisterCarSystemUIProxy(mContext)); 161 pw.println(" mConnected:" + mConnected); 162 pw.println(" mRemoteCarTaskViewServerSet size:" + mRemoteCarTaskViewServerSet.size()); 163 pw.println(" mRemoteCarTaskViewServerSet:"); 164 for (RemoteCarTaskViewServerImpl remoteCarTaskViewServer : mRemoteCarTaskViewServerSet) { 165 pw.println(" " + remoteCarTaskViewServer); 166 } 167 } 168 removeExistingTaskViewTasks()169 private void removeExistingTaskViewTasks() { 170 Display[] displays = mDisplayManager.getDisplays(); 171 for (int i = 0; i < displays.length; i++) { 172 List<ActivityManager.RunningTaskInfo> taskInfos = 173 mTaskOrganizer.getRunningTasks(displays[i].getDisplayId()); 174 removeMultiWindowTasks(taskInfos); 175 } 176 } 177 removeMultiWindowTasks(List<ActivityManager.RunningTaskInfo> taskInfos)178 private static void removeMultiWindowTasks(List<ActivityManager.RunningTaskInfo> taskInfos) { 179 ActivityTaskManager atm = ActivityTaskManager.getInstance(); 180 for (ActivityManager.RunningTaskInfo taskInfo : taskInfos) { 181 // In Auto, only TaskView tasks have WINDOWING_MODE_MULTI_WINDOW as of now. 182 if (taskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { 183 Slog.d(TAG, "Found a dangling task, removing: " + taskInfo.taskId); 184 atm.removeTask(taskInfo.taskId); 185 } 186 } 187 } 188 ensurePermission(String permission)189 private void ensurePermission(String permission) { 190 if (mContext.checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) { 191 throw new SecurityException("requires permission " + permission); 192 } 193 } 194 } 195