blob: 48278ed1ebfba92298968ad64dd0036c682e94b3 [file] [log] [blame]
Rakesh Iyer1186faa2015-12-07 16:48:46 -08001/*
2 * Copyright (C) 2015 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
17package com.android.systemui.statusbar.car;
18
Victor Chan1c6d0582016-01-09 16:26:37 -080019import android.app.ActivityManager;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080020import android.app.ActivityManagerNative;
21import android.app.ActivityOptions;
Rakesh Iyer9f831f62016-02-16 20:06:22 -080022import android.content.BroadcastReceiver;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080023import android.content.Context;
Rakesh Iyer9f831f62016-02-16 20:06:22 -080024import android.content.Intent;
25import android.content.IntentFilter;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080026import android.graphics.PixelFormat;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080027import android.os.Bundle;
Victor Chan1c6d0582016-01-09 16:26:37 -080028import android.os.Handler;
29import android.os.Looper;
Jorim Jaggi2adba072016-03-03 13:43:39 +010030import android.os.RemoteException;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080031import android.os.UserHandle;
32import android.util.Log;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080033import android.view.View;
34import android.view.ViewGroup.LayoutParams;
Rakesh Iyer2790a372016-01-22 15:33:39 -080035import android.view.ViewStub;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080036import android.view.WindowManager;
Anthony Chen1c59e9f2016-04-11 11:05:48 -070037import android.widget.LinearLayout;
Anthony Chenda62fdcd52016-04-06 16:15:14 -070038import com.android.systemui.BatteryMeterView;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080039import com.android.systemui.R;
Victor Chan1c6d0582016-01-09 16:26:37 -080040import com.android.systemui.recents.Recents;
41import com.android.systemui.recents.misc.SystemServicesProxy;
Jaewan Kim938a50b2016-03-14 17:35:43 +090042import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
Rakesh Iyer2790a372016-01-22 15:33:39 -080043import com.android.systemui.statusbar.StatusBarState;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080044import com.android.systemui.statusbar.phone.PhoneStatusBar;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080045import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
Anthony Chenda62fdcd52016-04-06 16:15:14 -070046import com.android.systemui.statusbar.phone.PhoneStatusBarView;
47import com.android.systemui.statusbar.policy.BatteryController;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080048
49/**
50 * A status bar (and navigation bar) tailored for the automotive use case.
51 */
Anthony Chenda62fdcd52016-04-06 16:15:14 -070052public class CarStatusBar extends PhoneStatusBar implements
53 CarBatteryController.BatteryViewHandler {
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080054 private static final String TAG = "CarStatusBar";
55
56 private SystemServicesProxy mSystemServicesProxy;
Victor Chan1c6d0582016-01-09 16:26:37 -080057 private TaskStackListenerImpl mTaskStackListener;
Victor Chan1c6d0582016-01-09 16:26:37 -080058
59 private CarNavigationBarView mCarNavigationBar;
60 private CarNavigationBarController mController;
Rakesh Iyer2790a372016-01-22 15:33:39 -080061 private FullscreenUserSwitcher mFullscreenUserSwitcher;
Victor Chan1c6d0582016-01-09 16:26:37 -080062
Anthony Chenda62fdcd52016-04-06 16:15:14 -070063 private CarBatteryController mCarBatteryController;
64 private BatteryMeterView mBatteryMeterView;
65
Anthony Chen1c59e9f2016-04-11 11:05:48 -070066 private ConnectedDeviceSignalController mConnectedDeviceSignalController;
67 private View mSignalsView;
68
Victor Chan1c6d0582016-01-09 16:26:37 -080069 @Override
70 public void start() {
71 super.start();
Jaewan Kim938a50b2016-03-14 17:35:43 +090072 mTaskStackListener = new TaskStackListenerImpl();
73 SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
Rakesh Iyer9f831f62016-02-16 20:06:22 -080074 registerPackageChangeReceivers();
Anthony Chenda62fdcd52016-04-06 16:15:14 -070075
76 mCarBatteryController.startListening();
Anthony Chen1c59e9f2016-04-11 11:05:48 -070077 mConnectedDeviceSignalController.startListening();
Anthony Chenda62fdcd52016-04-06 16:15:14 -070078 }
79
80 @Override
81 public void destroy() {
82 mCarBatteryController.stopListening();
Anthony Chen1c59e9f2016-04-11 11:05:48 -070083 mConnectedDeviceSignalController.stopListening();
84
Anthony Chenda62fdcd52016-04-06 16:15:14 -070085 super.destroy();
86 }
87
88 @Override
89 protected PhoneStatusBarView makeStatusBarView() {
90 PhoneStatusBarView statusBarView = super.makeStatusBarView();
91
92 mBatteryMeterView = ((BatteryMeterView) statusBarView.findViewById(R.id.battery));
93
94 // By default, the BatteryMeterView should not be visible. It will be toggled visible
95 // when a device has connected by bluetooth.
96 mBatteryMeterView.setVisibility(View.GONE);
97
Anthony Chen1c59e9f2016-04-11 11:05:48 -070098 ViewStub stub = (ViewStub) statusBarView.findViewById(R.id.connected_device_signals_stub);
99 mSignalsView = stub.inflate();
100
101 // When a ViewStub if inflated, it does not respect the margins on the inflated view.
102 // As a result, manually add the ending margin.
103 ((LinearLayout.LayoutParams) mSignalsView.getLayoutParams()).setMarginEnd(
104 mContext.getResources().getDimensionPixelOffset(
105 R.dimen.status_bar_connected_device_signal_margin_end));
106
107 mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
108 mSignalsView);
109
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700110 if (Log.isLoggable(TAG, Log.DEBUG)) {
111 Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
112 }
113
114 return statusBarView;
115 }
116
117 @Override
118 protected BatteryController createBatteryController() {
119 mCarBatteryController = new CarBatteryController(mContext);
120 mCarBatteryController.addBatteryViewHandler(this);
121 return mCarBatteryController;
Victor Chan1c6d0582016-01-09 16:26:37 -0800122 }
123
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800124 @Override
125 protected void addNavigationBar() {
126 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
127 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
128 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
Victor Chan1c6d0582016-01-09 16:26:37 -0800129 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
130 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
131 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
132 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
133 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
134 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800135 PixelFormat.TRANSLUCENT);
136 lp.setTitle("CarNavigationBar");
137 lp.windowAnimations = 0;
138 mWindowManager.addView(mNavigationBarView, lp);
139 }
140
141 @Override
142 protected void createNavigationBarView(Context context) {
143 if (mNavigationBarView != null) {
144 return;
145 }
Victor Chan1c6d0582016-01-09 16:26:37 -0800146 mCarNavigationBar =
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800147 (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null);
Victor Chan1c6d0582016-01-09 16:26:37 -0800148 mController = new CarNavigationBarController(context, mCarNavigationBar,
149 this /* ActivityStarter*/);
150 mNavigationBarView = mCarNavigationBar;
Rakesh Iyer9f831f62016-02-16 20:06:22 -0800151
152 }
153
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700154 @Override
155 public void showBatteryView() {
156 if (Log.isLoggable(TAG, Log.DEBUG)) {
157 Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
158 }
159
160 if (mBatteryMeterView != null) {
161 mBatteryMeterView.setVisibility(View.VISIBLE);
162 }
163 }
164
165 @Override
166 public void hideBatteryView() {
167 if (Log.isLoggable(TAG, Log.DEBUG)) {
168 Log.d(TAG, "hideBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
169 }
170
171 if (mBatteryMeterView != null) {
172 mBatteryMeterView.setVisibility(View.GONE);
173 }
174 }
175
Rakesh Iyer9f831f62016-02-16 20:06:22 -0800176 private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
177 @Override
178 public void onReceive(Context context, Intent intent) {
179 if (intent.getData() == null || mController == null) {
180 return;
181 }
182 String packageName = intent.getData().getSchemeSpecificPart();
183 mController.onPackageChange(packageName);
184 }
185 };
186
187 private void registerPackageChangeReceivers() {
188 IntentFilter filter = new IntentFilter();
189 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
190 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
191 filter.addDataScheme("package");
192 mContext.registerReceiver(mPackageChangeReceiver, filter);
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800193 }
Victor Chanecdb8b02016-01-07 18:32:43 -0800194
195 @Override
196 protected void repositionNavigationBar() {
197 // The navigation bar for a vehicle will not need to be repositioned, as it is always
198 // set at the bottom.
199 }
Victor Chan1c6d0582016-01-09 16:26:37 -0800200
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800201 public boolean hasDockedTask() {
202 return Recents.getSystemServices().hasDockedTask();
203 }
204
Victor Chan1c6d0582016-01-09 16:26:37 -0800205 /**
Jaewan Kim938a50b2016-03-14 17:35:43 +0900206 * An implementation of TaskStackListener, that listens for changes in the system task
Victor Chan1c6d0582016-01-09 16:26:37 -0800207 * stack and notifies the navigation bar.
208 */
Jaewan Kim938a50b2016-03-14 17:35:43 +0900209 private class TaskStackListenerImpl extends TaskStackListener {
Wale Ogunwale480dca02016-02-06 13:58:29 -0800210 @Override
Victor Chan1c6d0582016-01-09 16:26:37 -0800211 public void onTaskStackChanged() {
Victor Chan1c6d0582016-01-09 16:26:37 -0800212 SystemServicesProxy ssp = Recents.getSystemServices();
213 ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800214 if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
215 mController.taskChanged(runningTaskInfo.baseActivity.getPackageName());
216 }
Victor Chan1c6d0582016-01-09 16:26:37 -0800217 }
Victor Chan1c6d0582016-01-09 16:26:37 -0800218 }
Rakesh Iyer2790a372016-01-22 15:33:39 -0800219
220 @Override
221 protected void createUserSwitcher() {
222 if (mUserSwitcherController.useFullscreenUserSwitcher()) {
223 mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, mUserSwitcherController,
224 (ViewStub) mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
225 } else {
226 super.createUserSwitcher();
227 }
228 }
229
230 @Override
231 public void userSwitched(int newUserId) {
232 super.userSwitched(newUserId);
233 if (mFullscreenUserSwitcher != null) {
234 mFullscreenUserSwitcher.onUserSwitched(newUserId);
235 }
236 }
237
238 @Override
239 public void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
240 super.updateKeyguardState(goingToFullShade, fromShadeLocked);
241 if (mFullscreenUserSwitcher != null) {
242 if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
243 mFullscreenUserSwitcher.show();
244 } else {
245 mFullscreenUserSwitcher.hide();
246 }
247 }
248 }
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800249
250 private int startActivityWithOptions(Intent intent, Bundle options) {
251 int result = ActivityManager.START_CANCELED;
252 try {
253 result = ActivityManagerNative.getDefault().startActivityAsUser(null /* caller */,
254 mContext.getBasePackageName(),
255 intent,
256 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
257 null /* resultTo*/,
258 null /* resultWho*/,
259 0 /* requestCode*/,
260 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP,
261 null /* profilerInfo*/,
262 options,
263 UserHandle.CURRENT.getIdentifier());
264 } catch (RemoteException e) {
265 Log.w(TAG, "Unable to start activity", e);
266 }
267
268 return result;
269 }
270
271 public int startActivityOnStack(Intent intent, int stackId) {
272 ActivityOptions options = ActivityOptions.makeBasic();
273 options.setLaunchStackId(stackId);
274 return startActivityWithOptions(intent, options.toBundle());
275 }
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800276}