• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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