blob: dd5832b886ee3be462a731c63bae976532666868 [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.ActivityOptions;
Rakesh Iyer9f831f62016-02-16 20:06:22 -080021import android.content.BroadcastReceiver;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080022import android.content.Context;
Rakesh Iyer9f831f62016-02-16 20:06:22 -080023import android.content.Intent;
24import android.content.IntentFilter;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080025import android.graphics.PixelFormat;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080026import android.os.Bundle;
Victor Chan1c6d0582016-01-09 16:26:37 -080027import android.os.Handler;
28import android.os.Looper;
Jorim Jaggi2adba072016-03-03 13:43:39 +010029import android.os.RemoteException;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080030import android.os.UserHandle;
31import android.util.Log;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080032import android.view.View;
33import android.view.ViewGroup.LayoutParams;
Rakesh Iyer2790a372016-01-22 15:33:39 -080034import android.view.ViewStub;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080035import android.view.WindowManager;
Anthony Chen1c59e9f2016-04-11 11:05:48 -070036import android.widget.LinearLayout;
Anthony Chenda62fdcd52016-04-06 16:15:14 -070037import com.android.systemui.BatteryMeterView;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080038import com.android.systemui.R;
Victor Chan1c6d0582016-01-09 16:26:37 -080039import com.android.systemui.recents.Recents;
40import com.android.systemui.recents.misc.SystemServicesProxy;
Jaewan Kim938a50b2016-03-14 17:35:43 +090041import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
Rakesh Iyer2790a372016-01-22 15:33:39 -080042import com.android.systemui.statusbar.StatusBarState;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080043import com.android.systemui.statusbar.phone.PhoneStatusBar;
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080044import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
Anthony Chenda62fdcd52016-04-06 16:15:14 -070045import com.android.systemui.statusbar.phone.PhoneStatusBarView;
46import com.android.systemui.statusbar.policy.BatteryController;
Rakesh Iyer1186faa2015-12-07 16:48:46 -080047
48/**
49 * A status bar (and navigation bar) tailored for the automotive use case.
50 */
Anthony Chenda62fdcd52016-04-06 16:15:14 -070051public class CarStatusBar extends PhoneStatusBar implements
52 CarBatteryController.BatteryViewHandler {
Rakesh Iyer74ebabe2016-03-11 10:10:43 -080053 private static final String TAG = "CarStatusBar";
54
55 private SystemServicesProxy mSystemServicesProxy;
Victor Chan1c6d0582016-01-09 16:26:37 -080056 private TaskStackListenerImpl mTaskStackListener;
Victor Chan1c6d0582016-01-09 16:26:37 -080057
58 private CarNavigationBarView mCarNavigationBar;
59 private CarNavigationBarController mController;
Rakesh Iyer2790a372016-01-22 15:33:39 -080060 private FullscreenUserSwitcher mFullscreenUserSwitcher;
Victor Chan1c6d0582016-01-09 16:26:37 -080061
Anthony Chenda62fdcd52016-04-06 16:15:14 -070062 private CarBatteryController mCarBatteryController;
63 private BatteryMeterView mBatteryMeterView;
64
Anthony Chen1c59e9f2016-04-11 11:05:48 -070065 private ConnectedDeviceSignalController mConnectedDeviceSignalController;
66 private View mSignalsView;
67
Victor Chan1c6d0582016-01-09 16:26:37 -080068 @Override
69 public void start() {
70 super.start();
Jaewan Kim938a50b2016-03-14 17:35:43 +090071 mTaskStackListener = new TaskStackListenerImpl();
72 SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
Rakesh Iyer9f831f62016-02-16 20:06:22 -080073 registerPackageChangeReceivers();
Anthony Chenda62fdcd52016-04-06 16:15:14 -070074
75 mCarBatteryController.startListening();
Anthony Chen1c59e9f2016-04-11 11:05:48 -070076 mConnectedDeviceSignalController.startListening();
Anthony Chenda62fdcd52016-04-06 16:15:14 -070077 }
78
79 @Override
80 public void destroy() {
81 mCarBatteryController.stopListening();
Anthony Chen1c59e9f2016-04-11 11:05:48 -070082 mConnectedDeviceSignalController.stopListening();
83
Anthony Chenda62fdcd52016-04-06 16:15:14 -070084 super.destroy();
85 }
86
87 @Override
88 protected PhoneStatusBarView makeStatusBarView() {
89 PhoneStatusBarView statusBarView = super.makeStatusBarView();
90
91 mBatteryMeterView = ((BatteryMeterView) statusBarView.findViewById(R.id.battery));
92
93 // By default, the BatteryMeterView should not be visible. It will be toggled visible
94 // when a device has connected by bluetooth.
95 mBatteryMeterView.setVisibility(View.GONE);
96
Anthony Chen1c59e9f2016-04-11 11:05:48 -070097 ViewStub stub = (ViewStub) statusBarView.findViewById(R.id.connected_device_signals_stub);
98 mSignalsView = stub.inflate();
99
100 // When a ViewStub if inflated, it does not respect the margins on the inflated view.
101 // As a result, manually add the ending margin.
102 ((LinearLayout.LayoutParams) mSignalsView.getLayoutParams()).setMarginEnd(
103 mContext.getResources().getDimensionPixelOffset(
104 R.dimen.status_bar_connected_device_signal_margin_end));
105
106 mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
Anthony Chen13e1b672016-09-26 11:01:05 -0700107 mSignalsView, mBluetoothController);
Anthony Chen1c59e9f2016-04-11 11:05:48 -0700108
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700109 if (Log.isLoggable(TAG, Log.DEBUG)) {
110 Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
111 }
112
113 return statusBarView;
114 }
115
116 @Override
117 protected BatteryController createBatteryController() {
118 mCarBatteryController = new CarBatteryController(mContext);
119 mCarBatteryController.addBatteryViewHandler(this);
120 return mCarBatteryController;
Victor Chan1c6d0582016-01-09 16:26:37 -0800121 }
122
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800123 @Override
124 protected void addNavigationBar() {
125 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
126 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
127 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
Victor Chan1c6d0582016-01-09 16:26:37 -0800128 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
129 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
130 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
131 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
132 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
133 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800134 PixelFormat.TRANSLUCENT);
135 lp.setTitle("CarNavigationBar");
136 lp.windowAnimations = 0;
137 mWindowManager.addView(mNavigationBarView, lp);
138 }
139
140 @Override
141 protected void createNavigationBarView(Context context) {
142 if (mNavigationBarView != null) {
143 return;
144 }
Victor Chan1c6d0582016-01-09 16:26:37 -0800145 mCarNavigationBar =
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800146 (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null);
Victor Chan1c6d0582016-01-09 16:26:37 -0800147 mController = new CarNavigationBarController(context, mCarNavigationBar,
148 this /* ActivityStarter*/);
149 mNavigationBarView = mCarNavigationBar;
Rakesh Iyer3e142542016-09-02 12:01:02 -0700150 mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true);
Rakesh Iyer9f831f62016-02-16 20:06:22 -0800151 }
152
Anthony Chenda62fdcd52016-04-06 16:15:14 -0700153 @Override
154 public void showBatteryView() {
155 if (Log.isLoggable(TAG, Log.DEBUG)) {
156 Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
157 }
158
159 if (mBatteryMeterView != null) {
160 mBatteryMeterView.setVisibility(View.VISIBLE);
161 }
162 }
163
164 @Override
165 public void hideBatteryView() {
166 if (Log.isLoggable(TAG, Log.DEBUG)) {
167 Log.d(TAG, "hideBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
168 }
169
170 if (mBatteryMeterView != null) {
171 mBatteryMeterView.setVisibility(View.GONE);
172 }
173 }
174
Rakesh Iyer9f831f62016-02-16 20:06:22 -0800175 private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
176 @Override
177 public void onReceive(Context context, Intent intent) {
178 if (intent.getData() == null || mController == null) {
179 return;
180 }
181 String packageName = intent.getData().getSchemeSpecificPart();
182 mController.onPackageChange(packageName);
183 }
184 };
185
186 private void registerPackageChangeReceivers() {
187 IntentFilter filter = new IntentFilter();
188 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
189 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
190 filter.addDataScheme("package");
191 mContext.registerReceiver(mPackageChangeReceiver, filter);
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800192 }
Victor Chanecdb8b02016-01-07 18:32:43 -0800193
194 @Override
195 protected void repositionNavigationBar() {
196 // The navigation bar for a vehicle will not need to be repositioned, as it is always
197 // set at the bottom.
198 }
Victor Chan1c6d0582016-01-09 16:26:37 -0800199
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800200 public boolean hasDockedTask() {
201 return Recents.getSystemServices().hasDockedTask();
202 }
203
Victor Chan1c6d0582016-01-09 16:26:37 -0800204 /**
Jaewan Kim938a50b2016-03-14 17:35:43 +0900205 * An implementation of TaskStackListener, that listens for changes in the system task
Victor Chan1c6d0582016-01-09 16:26:37 -0800206 * stack and notifies the navigation bar.
207 */
Jaewan Kim938a50b2016-03-14 17:35:43 +0900208 private class TaskStackListenerImpl extends TaskStackListener {
Wale Ogunwale480dca02016-02-06 13:58:29 -0800209 @Override
Victor Chan1c6d0582016-01-09 16:26:37 -0800210 public void onTaskStackChanged() {
Victor Chan1c6d0582016-01-09 16:26:37 -0800211 SystemServicesProxy ssp = Recents.getSystemServices();
Winsond46b7272016-04-20 11:54:27 -0700212 ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800213 if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
Rakesh Iyer02ee8852016-05-05 16:02:21 -0700214 mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
215 runningTaskInfo.stackId);
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800216 }
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
Victor Chanc87554c2016-08-24 14:58:14 -0700250 @Override
251 public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
252 // Do nothing, we don't want to display media art in the lock screen for a car.
253 }
254
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800255 private int startActivityWithOptions(Intent intent, Bundle options) {
256 int result = ActivityManager.START_CANCELED;
257 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800258 result = ActivityManager.getService().startActivityAsUser(null /* caller */,
Rakesh Iyer74ebabe2016-03-11 10:10:43 -0800259 mContext.getBasePackageName(),
260 intent,
261 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
262 null /* resultTo*/,
263 null /* resultWho*/,
264 0 /* requestCode*/,
265 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP,
266 null /* profilerInfo*/,
267 options,
268 UserHandle.CURRENT.getIdentifier());
269 } catch (RemoteException e) {
270 Log.w(TAG, "Unable to start activity", e);
271 }
272
273 return result;
274 }
275
276 public int startActivityOnStack(Intent intent, int stackId) {
277 ActivityOptions options = ActivityOptions.makeBasic();
278 options.setLaunchStackId(stackId);
279 return startActivityWithOptions(intent, options.toBundle());
280 }
Rakesh Iyer1186faa2015-12-07 16:48:46 -0800281}