• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.systembar;
18 
19 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
20 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
21 import static android.view.Display.INVALID_DISPLAY;
22 
23 import static com.android.car.dockutil.events.DockCompatUtils.isDockSupportedOnDisplay;
24 
25 import android.car.Car;
26 import android.car.user.CarUserManager;
27 import android.content.Context;
28 import android.os.Build;
29 import android.os.UserManager;
30 import android.util.Log;
31 
32 import androidx.annotation.NonNull;
33 
34 import com.android.car.docklib.DockViewController;
35 import com.android.car.docklib.data.DockProtoDataController;
36 import com.android.car.docklib.view.DockView;
37 import com.android.systemui.R;
38 import com.android.systemui.car.CarServiceProvider;
39 import com.android.systemui.car.systembar.element.CarSystemBarElementController;
40 import com.android.systemui.car.systembar.element.CarSystemBarElementStateController;
41 import com.android.systemui.car.systembar.element.CarSystemBarElementStatusBarDisableController;
42 import com.android.systemui.car.systembar.element.layout.CarSystemBarFrameLayout;
43 import com.android.systemui.settings.UserFileManager;
44 import com.android.systemui.settings.UserTracker;
45 
46 import dagger.assisted.Assisted;
47 import dagger.assisted.AssistedFactory;
48 import dagger.assisted.AssistedInject;
49 
50 import java.io.File;
51 
52 /** Wrapper controller class for instantiating {@link DockViewController} inside CarSystemUI */
53 public class DockViewControllerWrapper extends
54         CarSystemBarElementController<CarSystemBarFrameLayout> {
55     private static final boolean DEBUG = Build.IS_ENG || Build.IS_USERDEBUG;
56 
57     private static final String TAG = DockViewControllerWrapper.class.getSimpleName();
58 
59     private final Context mContext;
60     private final UserManager mUserManager;
61     private final UserTracker mUserTracker;
62     private final UserFileManager mUserFileManager;
63     private final CarServiceProvider mCarServiceProvider;
64 
65     private DockViewController mDockViewController;
66     private CarUserManager mCarUserManager;
67     private int mActiveUnlockedUserId = -1;
68 
69     private final CarUserManager.UserLifecycleListener mUserLifecycleListener =
70             new CarUserManager.UserLifecycleListener() {
71                 @Override
72                 public void onEvent(@NonNull CarUserManager.UserLifecycleEvent event) {
73                     if (event.getUserHandle().isSystem()) {
74                         return;
75                     }
76 
77                     switch (event.getEventType()) {
78                         case USER_LIFECYCLE_EVENT_TYPE_UNLOCKED -> {
79                             if (event.getUserId() == mUserTracker.getUserId()) {
80                                 setupDock();
81                             }
82                         }
83                         case USER_LIFECYCLE_EVENT_TYPE_SWITCHING -> {
84                             if (event.getPreviousUserId() == mActiveUnlockedUserId) {
85                                 destroyDock();
86                             }
87                         }
88                     }
89                 }
90             };
91 
92     private final CarServiceProvider.CarServiceOnConnectedListener mCarOnConnectedListener =
93             new CarServiceProvider.CarServiceOnConnectedListener() {
94                 @Override
95                 public void onConnected(Car car) {
96                     mCarUserManager = car.getCarManager(CarUserManager.class);
97                     if (mCarUserManager != null) {
98                         mCarUserManager.addListener(mContext.getMainExecutor(),
99                                 mUserLifecycleListener);
100                     }
101                 }
102             };
103 
104     @AssistedInject
DockViewControllerWrapper(@ssisted CarSystemBarFrameLayout view, CarSystemBarElementStatusBarDisableController disableController, CarSystemBarElementStateController stateController, Context context, UserTracker userTracker, UserFileManager userFileManager, CarServiceProvider carServiceProvider)105     DockViewControllerWrapper(@Assisted CarSystemBarFrameLayout view,
106             CarSystemBarElementStatusBarDisableController disableController,
107             CarSystemBarElementStateController stateController, Context context,
108             UserTracker userTracker, UserFileManager userFileManager,
109             CarServiceProvider carServiceProvider) {
110         super(view, disableController, stateController);
111         mContext = context;
112         mUserManager = context.getSystemService(UserManager.class);
113         mUserTracker = userTracker;
114         mUserFileManager = userFileManager;
115         mCarServiceProvider = carServiceProvider;
116     }
117 
118     @AssistedFactory
119     public interface Factory extends
120             CarSystemBarElementController.Factory<CarSystemBarFrameLayout,
121                     DockViewControllerWrapper> {
122     }
123 
124     @Override
onViewAttached()125     protected void onViewAttached() {
126         super.onViewAttached();
127         setupDock();
128         mCarServiceProvider.addListener(mCarOnConnectedListener);
129     }
130 
131     @Override
onViewDetached()132     protected void onViewDetached() {
133         super.onViewDetached();
134         mCarServiceProvider.removeListener(mCarOnConnectedListener);
135         if (mCarUserManager != null) {
136             mCarUserManager.removeListener(mUserLifecycleListener);
137             mCarUserManager = null;
138         }
139         destroyDock();
140     }
141 
createDockViewController(DockView dockView, Context userContext, File dataFile)142     protected DockViewController createDockViewController(DockView dockView, Context userContext,
143             File dataFile) {
144         return new DockViewController(dockView, userContext, dataFile);
145     }
146 
setupDock()147     private void setupDock() {
148         if (mDockViewController != null) {
149             if (mDockViewController.getUserContext().getUserId() == mUserTracker.getUserId()) {
150                 if (DEBUG) {
151                     Log.d(TAG, "Dock already initialized for user: " + mUserTracker.getUserId());
152                 }
153                 return;
154             }
155             if (DEBUG) {
156                 // This is unexpected. We should not have a leaked instance of
157                 // DockViewController for a different user. This indicates a potential
158                 // issue with how we're managing the DockViewController lifecycle.
159                 Log.w(TAG, "DockViewController: Leaked instance detected for user "
160                         + mDockViewController.getUserContext().getUserId() + ". Destroying now.");
161             }
162             mDockViewController.destroy();
163         }
164         int currentDisplayId = mView.getDisplay() != null ? mView.getDisplay().getDisplayId()
165                 : INVALID_DISPLAY;
166         if (!isDockSupportedOnDisplay(mContext, currentDisplayId)) {
167             Log.e(TAG, "Dock cannot be initialised: Tried to launch on unsupported display "
168                     + currentDisplayId);
169             return;
170         }
171         DockView dockView = mView.findViewById(R.id.dock);
172         if (dockView == null) {
173             if (DEBUG) {
174                 Log.d(TAG, "Dock cannot be initialised: Cannot find dock view");
175             }
176             return;
177         }
178         if (!mUserManager.isUserUnlocked(mUserTracker.getUserId())) {
179             if (DEBUG) {
180                 Log.d(TAG, "Dock cannot be initialised: User not unlocked");
181             }
182             return;
183         }
184         mDockViewController = createDockViewController(
185                 dockView,
186                 mUserTracker.getUserContext(),
187                 mUserFileManager.getFile(
188                         DockProtoDataController.FILE_NAME,
189                         mUserTracker.getUserId()
190                 )
191         );
192         mActiveUnlockedUserId = mUserTracker.getUserId();
193     }
194 
destroyDock()195     private void destroyDock() {
196         if (mDockViewController != null) {
197             mDockViewController.destroy();
198             mDockViewController = null;
199         }
200     }
201 }
202