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