From 6cc5b8a51ea9804fd39030fc7879a112cd7899f0 Mon Sep 17 00:00:00 2001 From: Yorke Lee Date: Fri, 4 Sep 2015 15:31:10 -0700 Subject: Disable AccelerometerListener when display is off Unregister the accelerometer listener when the screen is off to reduce power consumption. Slight refactor of component constructors to facilitate testing. Add test. Bug: 23498050 Change-Id: If1971a39e8a418253f6611116c855e3c6cf81b93 --- .../android/incallui/AccelerometerListener.java | 13 +++-- .../com/android/incallui/InCallServiceImpl.java | 5 +- .../src/com/android/incallui/ProximitySensor.java | 67 +++++++++++++++++++++- .../com/android/incallui/ProximitySensorTest.java | 64 +++++++++++++++++++++ 4 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 InCallUI/tests/src/com/android/incallui/ProximitySensorTest.java (limited to 'InCallUI') diff --git a/InCallUI/src/com/android/incallui/AccelerometerListener.java b/InCallUI/src/com/android/incallui/AccelerometerListener.java index ca8e7d0a4..b5ad29675 100644 --- a/InCallUI/src/com/android/incallui/AccelerometerListener.java +++ b/InCallUI/src/com/android/incallui/AccelerometerListener.java @@ -30,7 +30,7 @@ import android.util.Log; * orientation of the phone. The client of this class is notified when * the orientation changes between horizontal and vertical. */ -public final class AccelerometerListener { +public class AccelerometerListener { private static final String TAG = "AccelerometerListener"; private static final boolean DEBUG = true; private static final boolean VDEBUG = false; @@ -63,12 +63,15 @@ public final class AccelerometerListener { public void orientationChanged(int orientation); } - public AccelerometerListener(Context context, OrientationListener listener) { - mListener = listener; + public AccelerometerListener(Context context) { mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } + public void setListener(OrientationListener listener) { + mListener = listener; + } + public void enable(boolean enable) { if (DEBUG) Log.d(TAG, "enable(" + enable + ")"); synchronized (this) { @@ -155,7 +158,9 @@ public final class AccelerometerListener { : (mOrientation == ORIENTATION_VERTICAL ? "vertical" : "unknown"))); } - mListener.orientationChanged(mOrientation); + if (mListener != null) { + mListener.orientationChanged(mOrientation); + } } break; } diff --git a/InCallUI/src/com/android/incallui/InCallServiceImpl.java b/InCallUI/src/com/android/incallui/InCallServiceImpl.java index 89fa1326c..8e65f1af5 100644 --- a/InCallUI/src/com/android/incallui/InCallServiceImpl.java +++ b/InCallUI/src/com/android/incallui/InCallServiceImpl.java @@ -68,7 +68,10 @@ public class InCallServiceImpl extends InCallService { AudioModeProvider.getInstance(), new StatusBarNotifier(context, contactInfoCache), contactInfoCache, - new ProximitySensor(context, AudioModeProvider.getInstance()) + new ProximitySensor( + context, + AudioModeProvider.getInstance(), + new AccelerometerListener(context)) ); InCallPresenter.getInstance().onServiceBind(); InCallPresenter.getInstance().maybeStartRevealAnimation(intent); diff --git a/InCallUI/src/com/android/incallui/ProximitySensor.java b/InCallUI/src/com/android/incallui/ProximitySensor.java index 05a86d35c..401ebd129 100644 --- a/InCallUI/src/com/android/incallui/ProximitySensor.java +++ b/InCallUI/src/com/android/incallui/ProximitySensor.java @@ -18,8 +18,11 @@ package com.android.incallui; import android.content.Context; import android.content.res.Configuration; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.os.PowerManager; import android.telecom.CallAudioState; +import android.view.Display; import com.android.incallui.AudioModeProvider.AudioModeListener; import com.android.incallui.InCallPresenter.InCallState; @@ -44,6 +47,7 @@ public class ProximitySensor implements AccelerometerListener.OrientationListene private final PowerManager.WakeLock mProximityWakeLock; private final AudioModeProvider mAudioModeProvider; private final AccelerometerListener mAccelerometerListener; + private final ProximityDisplayListener mDisplayListener; private int mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN; private boolean mUiShowing = false; private boolean mIsPhoneOffhook = false; @@ -53,7 +57,8 @@ public class ProximitySensor implements AccelerometerListener.OrientationListene // Gets updated whenever there is a Configuration change private boolean mIsHardKeyboardOpen; - public ProximitySensor(Context context, AudioModeProvider audioModeProvider) { + public ProximitySensor(Context context, AudioModeProvider audioModeProvider, + AccelerometerListener accelerometerListener) { mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); if (mPowerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { mProximityWakeLock = mPowerManager.newWakeLock( @@ -62,7 +67,13 @@ public class ProximitySensor implements AccelerometerListener.OrientationListene Log.w(TAG, "Device does not support proximity wake lock."); mProximityWakeLock = null; } - mAccelerometerListener = new AccelerometerListener(context, this); + mAccelerometerListener = accelerometerListener; + mAccelerometerListener.setListener(this); + + mDisplayListener = new ProximityDisplayListener( + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE)); + mDisplayListener.register(); + mAudioModeProvider = audioModeProvider; mAudioModeProvider.addListener(this); } @@ -71,6 +82,7 @@ public class ProximitySensor implements AccelerometerListener.OrientationListene mAudioModeProvider.removeListener(this); mAccelerometerListener.enable(false); + mDisplayListener.unregister(); turnOffProximitySensor(true); } @@ -151,10 +163,16 @@ public class ProximitySensor implements AccelerometerListener.OrientationListene updateProximitySensorMode(); } + void onDisplayStateChanged(boolean isDisplayOn) { + Log.i(this, "isDisplayOn: " + isDisplayOn); + mAccelerometerListener.enable(isDisplayOn); + } + /** * TODO: There is no way to determine if a screen is off due to proximity or if it is * legitimately off, but if ever we can do that in the future, it would be useful here. * Until then, this function will simply return true of the screen is off. + * TODO: Investigate whether this can be replaced with the ProximityDisplayListener. */ public boolean isScreenReallyOff() { return !mPowerManager.isScreenOn(); @@ -251,4 +269,49 @@ public class ProximitySensor implements AccelerometerListener.OrientationListene turnOffProximitySensor(screenOnImmediately); } } + + /** + * Implementation of a {@link DisplayListener} that maintains a binary state: + * Screen on vs screen off. Used by the proximity sensor manager to decide whether or not + * it needs to listen to accelerometer events. + */ + public class ProximityDisplayListener implements DisplayListener { + private DisplayManager mDisplayManager; + private boolean mIsDisplayOn = true; + + ProximityDisplayListener(DisplayManager displayManager) { + mDisplayManager = displayManager; + } + + void register() { + mDisplayManager.registerDisplayListener(this, null); + } + + void unregister() { + mDisplayManager.unregisterDisplayListener(this); + } + + @Override + public void onDisplayRemoved(int displayId) { + } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == Display.DEFAULT_DISPLAY) { + final Display display = mDisplayManager.getDisplay(displayId); + + final boolean isDisplayOn = display.getState() != Display.STATE_OFF; + // For call purposes, we assume that as long as the screen is not truly off, it is + // considered on, even if it is in an unknown or low power idle state. + if (isDisplayOn != mIsDisplayOn) { + mIsDisplayOn = isDisplayOn; + onDisplayStateChanged(mIsDisplayOn); + } + } + } + + @Override + public void onDisplayAdded(int displayId) { + } + } } diff --git a/InCallUI/tests/src/com/android/incallui/ProximitySensorTest.java b/InCallUI/tests/src/com/android/incallui/ProximitySensorTest.java new file mode 100644 index 000000000..d7b2f64b6 --- /dev/null +++ b/InCallUI/tests/src/com/android/incallui/ProximitySensorTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 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.incallui; + +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.test.InstrumentationTestCase; + +import com.android.incallui.InCallPresenter.InCallState; + +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +public class ProximitySensorTest extends InstrumentationTestCase { + @Mock private AccelerometerListener mAccelerometerListener; + private MockCallListWrapper mCallList; + + @Override + protected void setUp() throws Exception { + super.setUp(); + System.setProperty("dexmaker.dexcache", + getInstrumentation().getTargetContext().getCacheDir().getPath()); + MockitoAnnotations.initMocks(this); + mCallList = new MockCallListWrapper(); + } + + public void testAccelerometerBehaviorOnDisplayChange() { + final ProximitySensor proximitySensor = + new ProximitySensor( + getInstrumentation().getContext(), + new AudioModeProvider(), + mAccelerometerListener); + verify(mAccelerometerListener, never()).enable(anyBoolean()); + proximitySensor.onStateChange(null, InCallState.OUTGOING, mCallList.getCallList()); + verify(mAccelerometerListener).enable(true); + verify(mAccelerometerListener, never()).enable(false); + + proximitySensor.onDisplayStateChanged(false); + verify(mAccelerometerListener).enable(true); + verify(mAccelerometerListener).enable(false); + + proximitySensor.onDisplayStateChanged(true); + verify(mAccelerometerListener, times(2)).enable(true); + verify(mAccelerometerListener).enable(false); + } +} -- cgit v1.2.3