diff options
| author | 2018-09-14 15:46:24 -0700 | |
|---|---|---|
| committer | 2018-10-23 15:50:19 -0700 | |
| commit | edba98c1c8728189dfd14c34527b8445fdd146e0 (patch) | |
| tree | ebab72120d671fb0094c580f6f75cb201de42b67 | |
| parent | 0d541559af18191897104e0685f43a561b1e5ba5 (diff) | |
Adds automatic switching to Guest if user starts driving with the keyguard
up.
driving_on_keyguard_timeout_ms controlls the number of milliseconds we wait,
before switching to Guest. If this number is negative, feature is disabled.
Change-Id: Ic1357362a97cb14a4f221d53e17a30cd3fefc5ea
Fixes: 110228676
Test: manual testing on mojave and emulator. Toggling driving state and keyguard, and observing the timer logs and switching.
5 files changed, 278 insertions, 0 deletions
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 3725940f159c..fef9ae813f12 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -209,6 +209,9 @@ <!-- to read and change hvac values in a car --> <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" /> + <!-- to be able to detect the driving state in a car--> + <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" /> + <!-- Permission necessary to change car audio volume through CarAudioManager --> <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" /> diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/SystemUI/res/values/integers_car.xml index 7513fd4cd268..fc3623cb69fb 100644 --- a/packages/SystemUI/res/values/integers_car.xml +++ b/packages/SystemUI/res/values/integers_car.xml @@ -19,4 +19,9 @@ <integer name="car_user_switcher_anim_cascade_delay_ms">27</integer> <!-- Full screen user switcher column number TODO: move to support library--> <integer name="user_fullscreen_switcher_num_col">3</integer> + + <!-- Number of milliseconds user can spend driving with the keyguard up. After that, we switch to Guest. --> + <!-- If the number is negative, the feature is disabled. + If it's zero, we switch to guest immediately as we start driving. --> + <integer name="driving_on_keyguard_timeout_ms">30000</integer> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 24665eac76a7..7be0eab4f585 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.car; import android.app.ActivityTaskManager; +import android.car.drivingstate.CarDrivingStateEvent; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.util.Log; @@ -82,6 +83,8 @@ public class CarStatusBar extends StatusBar implements private DeviceProvisionedController mDeviceProvisionedController; private boolean mDeviceIsProvisioned = true; private HvacController mHvacController; + private DrivingStateHelper mDrivingStateHelper; + private SwitchToGuestTimer mSwitchToGuestTimer; @Override public void start() { @@ -111,6 +114,12 @@ public class CarStatusBar extends StatusBar implements } }); } + + // Register a listener for driving state changes. + mDrivingStateHelper = new DrivingStateHelper(mContext, this::onDrivingStateChanged); + mDrivingStateHelper.connectToCarService(); + + mSwitchToGuestTimer = new SwitchToGuestTimer(mContext); } /** @@ -205,6 +214,7 @@ public class CarStatusBar extends StatusBar implements mCarBatteryController.stopListening(); mConnectedDeviceSignalController.stopListening(); mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackListener); + mDrivingStateHelper.disconnectFromCarService(); if (mNavigationBarWindow != null) { mWindowManager.removeViewImmediate(mNavigationBarWindow); @@ -476,6 +486,20 @@ public class CarStatusBar extends StatusBar implements } } + private void onDrivingStateChanged(CarDrivingStateEvent notUsed) { + // Check if we need to start the timer every time driving state changes. + startSwitchToGuestTimerIfDrivingOnKeyguard(); + } + + private void startSwitchToGuestTimerIfDrivingOnKeyguard() { + if (mDrivingStateHelper.isCurrentlyDriving() && mState != StatusBarState.SHADE) { + // We're driving while keyguard is up. + mSwitchToGuestTimer.start(); + } else { + mSwitchToGuestTimer.cancel(); + } + } + @Override protected void createUserSwitcher() { UserSwitcherController userSwitcherController = @@ -491,6 +515,9 @@ public class CarStatusBar extends StatusBar implements @Override public void onStateChanged(int newState) { super.onStateChanged(newState); + + startSwitchToGuestTimerIfDrivingOnKeyguard(); + if (mFullscreenUserSwitcher == null) { return; // Not using the full screen user switcher. } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java new file mode 100644 index 000000000000..47941bf22941 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.car; + +import android.car.Car; +import android.car.CarNotConnectedException; +import android.car.drivingstate.CarDrivingStateEvent; +import android.car.drivingstate.CarDrivingStateManager; +import android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener; +import android.content.ComponentName; +import android.content.Context; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.util.Log; + +import androidx.annotation.NonNull; + +/** + * Helper class for connecting to the {@link CarDrivingStateManager} and listening for driving state + * changes. + */ +public class DrivingStateHelper { + public static final String TAG = "DrivingStateHelper"; + + private final Context mContext; + private CarDrivingStateManager mDrivingStateManager; + private Car mCar; + private CarDrivingStateEventListener mDrivingStateHandler; + + public DrivingStateHelper(Context context, + @NonNull CarDrivingStateEventListener drivingStateHandler) { + mContext = context; + mDrivingStateHandler = drivingStateHandler; + } + + /** + * Queries {@link CarDrivingStateManager} for current driving state. Returns {@code true} if car + * is idling or moving, {@code false} otherwise. + */ + public boolean isCurrentlyDriving() { + try { + CarDrivingStateEvent currentState = mDrivingStateManager.getCurrentCarDrivingState(); + if (currentState != null) { + return currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING + || currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING; + } + } catch (CarNotConnectedException e) { + Log.e(TAG, "Cannot determine current driving state. Car not connected", e); + } + + return false; // Default to false. + } + + /** + * Establishes connection with the Car service. + */ + public void connectToCarService() { + mCar = Car.createCar(mContext, mCarConnectionListener); + if (mCar != null) { + mCar.connect(); + } + } + + /** + * Disconnects from Car service and cleans up listeners. + */ + public void disconnectFromCarService() { + if (mCar != null) { + mCar.disconnect(); + } + } + + private final ServiceConnection mCarConnectionListener = + new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + logD("Car Service connected"); + try { + mDrivingStateManager = (CarDrivingStateManager) mCar.getCarManager( + Car.CAR_DRIVING_STATE_SERVICE); + if (mDrivingStateManager != null) { + mDrivingStateManager.registerListener(mDrivingStateHandler); + mDrivingStateHandler.onDrivingStateChanged( + mDrivingStateManager.getCurrentCarDrivingState()); + } else { + Log.e(TAG, "CarDrivingStateService service not available"); + } + } catch (CarNotConnectedException e) { + Log.e(TAG, "Car not connected", e); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + destroyDrivingStateManager(); + } + }; + + private void destroyDrivingStateManager() { + try { + if (mDrivingStateManager != null) { + mDrivingStateManager.unregisterListener(); + } + } catch (CarNotConnectedException e) { + Log.e(TAG, "Error unregistering listeners", e); + } + } + + private void logD(String message) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, message); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java new file mode 100644 index 000000000000..27a5d4bf2bf2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.car; + +import android.car.userlib.CarUserManagerHelper; +import android.content.Context; +import android.os.CountDownTimer; +import android.util.Log; + +import com.android.systemui.R; + +import androidx.annotation.GuardedBy; + +/** + * Wrapper for a countdown timer that switches to Guest if the user has been driving with + * the keyguard up for configurable number of seconds. + */ +public class SwitchToGuestTimer { + private static final String TAG = "SwitchToGuestTimer"; + + // After how many ms CountdownTimer.onTick gets triggered. + private static final int COUNTDOWN_INTERVAL_MS = 1000; + + private final CarUserManagerHelper mCarUserManagerHelper; + private final Object mTimerLock; + private final String mGuestName; + private final int mTimeoutMs; + private final boolean mEnabled; + + @GuardedBy("mTimerLock") + private CountDownTimer mSwitchToGuestTimer; + + public SwitchToGuestTimer(Context context) { + mCarUserManagerHelper = new CarUserManagerHelper(context); + mGuestName = context.getResources().getString(R.string.car_guest); + mTimeoutMs = context.getResources().getInteger(R.integer.driving_on_keyguard_timeout_ms); + + // Lock prevents multiple timers being started. + mTimerLock = new Object(); + + // If milliseconds to switch is a negative number, the feature is disabled. + mEnabled = mTimeoutMs >= 0; + } + + /** + * Starts the timer if it's not already running. + */ + public void start() { + if (!mEnabled) { + logD("Switching to guest after driving on keyguard is disabled."); + return; + } + + synchronized (mTimerLock) { + if (mSwitchToGuestTimer != null) { + logD("Timer is already running."); + return; + } + + mSwitchToGuestTimer = new CountDownTimer(mTimeoutMs, COUNTDOWN_INTERVAL_MS) { + @Override + public void onTick(long msUntilFinished) { + logD("Ms until switching to guest: " + Long.toString(msUntilFinished)); + } + + @Override + public void onFinish() { + mCarUserManagerHelper.startNewGuestSession(mGuestName); + cancel(); + } + }; + + logI("Starting timer"); + mSwitchToGuestTimer.start(); + } + } + + /** + * Cancels the running timer. + */ + public void cancel() { + synchronized (mTimerLock) { + if (mSwitchToGuestTimer != null) { + logI("Cancelling timer"); + mSwitchToGuestTimer.cancel(); + mSwitchToGuestTimer = null; + } + } + } + + private void logD(String message) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, message); + } + } + + private void logI(String message) { + if (Log.isLoggable(TAG, Log.INFO)) { + Log.i(TAG, message); + } + } +} |