Merge "Refactor printing"
diff --git a/Android.mk b/Android.mk
index 642d8b9..573f46a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -232,6 +232,7 @@
core/java/android/view/IWindowId.aidl \
core/java/android/view/IWindowManager.aidl \
core/java/android/view/IWindowSession.aidl \
+ core/java/android/view/IWindowSessionCallback.aidl \
core/java/android/speech/IRecognitionListener.aidl \
core/java/android/speech/IRecognitionService.aidl \
core/java/android/speech/tts/ITextToSpeechCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 2c13f90..d29580b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21473,12 +21473,14 @@
public final class PowerManager {
method public void goToSleep(long);
method public boolean isInteractive();
+ method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
method public void userActivity(long, boolean);
method public void wakeUp(long);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
+ field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 61194e9..658180b 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -41,6 +41,7 @@
void goToSleep(long time, int reason, int flags);
void nap(long time);
boolean isInteractive();
+ boolean isPowerSaveMode();
void reboot(boolean confirm, String reason, boolean wait);
void shutdown(boolean confirm, boolean wait);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d5177e8..92e80a5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.SdkConstant;
import android.content.Context;
import android.util.Log;
@@ -685,6 +686,30 @@
}
/**
+ * Returns true if the device is currently in power save mode. When in this mode,
+ * applications should reduce their functionality in order to conserve battery as
+ * much as possible. You can monitor for changes to this state with
+ * {@link #ACTION_POWER_SAVE_MODE_CHANGED}.
+ *
+ * @return Returns true if currently in low power mode, else false.
+ */
+ public boolean isPowerSaveMode() {
+ try {
+ return mService.isPowerSaveMode();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
+ * This broadcast is only sent to registered receivers.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_POWER_SAVE_MODE_CHANGED
+ = "android.os.action.POWER_SAVE_MODE_CHANGED";
+
+ /**
* A wake lock is a mechanism to indicate that your application needs
* to have the device stay on.
* <p>
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index f06ae71..48122d6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -48,10 +48,11 @@
import android.text.style.UnderlineSpan;
import android.util.Log;
import android.util.Printer;
-
import android.view.View;
+
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+
import libcore.icu.ICU;
import java.lang.reflect.Array;
@@ -229,7 +230,12 @@
public static boolean regionMatches(CharSequence one, int toffset,
CharSequence two, int ooffset,
int len) {
- char[] temp = obtain(2 * len);
+ int tempLen = 2 * len;
+ if (tempLen < len) {
+ // Integer overflow; len is unreasonably large
+ throw new IndexOutOfBoundsException();
+ }
+ char[] temp = obtain(tempLen);
getChars(one, toffset, toffset + len, temp, 0);
getChars(two, ooffset, ooffset + len, temp, len);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a52ccdf..ae59bbc 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -30,6 +30,7 @@
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IWindowSession;
+import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
import android.view.InputEvent;
import android.view.MagnificationSpec;
@@ -56,7 +57,7 @@
boolean stopViewServer(); // Transaction #2
boolean isViewServerRunning(); // Transaction #3
- IWindowSession openSession(in IInputMethodClient client,
+ IWindowSession openSession(in IWindowSessionCallback callback, in IInputMethodClient client,
in IInputContext inputContext);
boolean inputMethodClientHasFocus(IInputMethodClient client);
@@ -130,6 +131,8 @@
void setAnimationScale(int which, float scale);
void setAnimationScales(in float[] scales);
+ float getCurrentAnimatorScale();
+
// For testing
void setInTouchMode(boolean showFocus);
diff --git a/core/java/android/view/IWindowSessionCallback.aidl b/core/java/android/view/IWindowSessionCallback.aidl
new file mode 100644
index 0000000..88931ce
--- /dev/null
+++ b/core/java/android/view/IWindowSessionCallback.aidl
@@ -0,0 +1,27 @@
+/*
+** Copyright 2014, 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 android.view;
+
+/**
+ * Callback to active sessions of the window manager
+ *
+ * {@hide}
+ */
+oneway interface IWindowSessionCallback
+{
+ void onAnimatorScaleChanged(float scale);
+}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index b4779f4..0ebf2e1 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -147,9 +147,14 @@
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
+ new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float scale) {
+ ValueAnimator.setDurationScale(scale);
+ }
+ },
imm.getClient(), imm.getInputContext());
- float animatorScale = windowManager.getAnimationScale(2);
- ValueAnimator.setDurationScale(animatorScale);
+ ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dfe2a58..e4cbf5f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -74,6 +74,8 @@
<protected-broadcast android:name="android.intent.action.USER_FOREGROUND" />
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
+
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index c2c671c..ac9866c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -87,6 +87,8 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -400,6 +402,9 @@
private boolean mSettingsClosing;
private boolean mVisible;
+ private Interpolator mAlphaOut = new PathInterpolator(0f, 0.4f, 1f, 1f);
+ private Interpolator mAlphaIn = new PathInterpolator(0f, 0f, 0.8f, 1f);
+
private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
new OnChildLocationsChangedListener() {
@Override
@@ -408,6 +413,8 @@
}
};
+ private int mDisabledUnmodified;
+
public void setOnFlipRunnable(Runnable onFlipRunnable) {
mOnFlipRunnable = onFlipRunnable;
}
@@ -677,10 +684,6 @@
mDateTimeView.setEnabled(true);
}
- mNotificationPanel.setSystemUiVisibility(
- View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
- View.STATUS_BAR_DISABLE_CLOCK);
-
mTicker = new MyTicker(context, mStatusBarView);
TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText);
@@ -1415,10 +1418,20 @@
}
}
+ private int adjustDisableFlags(int state) {
+ if (mExpandedVisible) {
+ state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+ state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+ }
+ return state;
+ }
+
/**
* State is one or more of the DISABLE constants from StatusBarManager.
*/
public void disable(int state) {
+ mDisabledUnmodified = state;
+ state = adjustDisableFlags(state);
final int old = mDisabled;
final int diff = state ^ old;
mDisabled = state;
@@ -1456,20 +1469,17 @@
if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
mSystemIconArea.animate()
.alpha(0f)
- .translationY(mNaturalBarHeight*0.5f)
- .setDuration(175)
- .setInterpolator(new DecelerateInterpolator(1.5f))
- .setListener(mMakeIconsInvisible)
- .start();
+ .withLayer()
+ .setDuration(160)
+ .setInterpolator(mAlphaIn)
+ .setListener(mMakeIconsInvisible);
} else {
mSystemIconArea.setVisibility(View.VISIBLE);
mSystemIconArea.animate()
.alpha(1f)
- .translationY(0)
- .setStartDelay(0)
- .setInterpolator(new DecelerateInterpolator(1.5f))
- .setDuration(175)
- .start();
+ .withLayer()
+ .setInterpolator(mAlphaOut)
+ .setDuration(320);
}
}
@@ -1505,20 +1515,18 @@
mNotificationIcons.animate()
.alpha(0f)
- .translationY(mNaturalBarHeight*0.5f)
- .setDuration(175)
- .setInterpolator(new DecelerateInterpolator(1.5f))
+ .withLayer()
+ .setDuration(160)
+ .setInterpolator(mAlphaIn)
.setListener(mMakeIconsInvisible)
.start();
} else {
mNotificationIcons.setVisibility(View.VISIBLE);
mNotificationIcons.animate()
.alpha(1f)
- .translationY(0)
- .setStartDelay(0)
- .setInterpolator(new DecelerateInterpolator(1.5f))
- .setDuration(175)
- .start();
+ .withLayer()
+ .setInterpolator(mAlphaOut)
+ .setDuration(320);
}
}
}
@@ -1618,7 +1626,7 @@
mStatusBarWindowManager.setStatusBarExpanded(true);
visibilityChanged(true);
-
+ disable(mDisabledUnmodified);
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
@@ -1769,10 +1777,6 @@
mStatusBarView.collapseAllPanels(true);
}
- void makeExpandedInvisibleSoon() {
- mHandler.postDelayed(new Runnable() { public void run() { makeExpandedInvisible(); }}, 50);
- }
-
void makeExpandedInvisible() {
if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
+ " mExpandedVisible=" + mExpandedVisible);
@@ -1816,7 +1820,7 @@
}
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-
+ disable(mDisabledUnmodified);
showBouncer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 910d88c..3a17177 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -111,8 +111,7 @@
@Override
public void onAllPanelsCollapsed() {
super.onAllPanelsCollapsed();
- // give animations time to settle
- mBar.makeExpandedInvisibleSoon();
+ mBar.makeExpandedInvisible();
mLastFullyOpenedPanel = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 4d86213..20caed8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -264,6 +264,13 @@
: mPaddingBetweenElementsNormal;
mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
updateContentHeight();
+ notifyHeightChangeListener(null);
+ }
+
+ private void notifyHeightChangeListener(ExpandableView view) {
+ if (mOnHeightChangedListener != null) {
+ mOnHeightChangedListener.onHeightChanged(view);
+ }
}
@Override
@@ -402,9 +409,7 @@
mNeedsAnimation = true;
}
requestChildrenUpdate();
- if (mOnHeightChangedListener != null) {
- mOnHeightChangedListener.onHeightChanged(null);
- }
+ notifyHeightChangeListener(null);
}
}
@@ -1725,9 +1730,7 @@
public void onHeightChanged(ExpandableView view) {
updateContentHeight();
updateScrollPositionIfNecessary();
- if (mOnHeightChangedListener != null) {
- mOnHeightChangedListener.onHeightChanged(view);
- }
+ notifyHeightChangeListener(view);
requestChildrenUpdate();
}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index cb5946a..fe5c2ef 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -128,6 +128,8 @@
private int mPlugType;
private int mLastPlugType = -1; // Extra state so we can detect first run
+ private boolean mBatteryLevelLow;
+
private long mDischargeStartTime;
private int mDischargeStartLevel;
@@ -222,14 +224,30 @@
}
/**
- * Returns true if battery level is below the first warning threshold.
+ * Returns whether we currently consider the battery level to be low.
*/
- public boolean isBatteryLow() {
+ public boolean getBatteryLevelLow() {
synchronized (mLock) {
- return mBatteryProps.batteryPresent && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel;
+ return mBatteryLevelLow;
}
}
+ public boolean isBatteryLowLocked() {
+ final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
+ final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
+
+ /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
+ * - is just un-plugged (previously was plugged) and battery level is
+ * less than or equal to WARNING, or
+ * - is not plugged and battery level falls to WARNING boundary
+ * (becomes <= mLowBatteryWarningLevel).
+ */
+ return !plugged
+ && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
+ && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
+ }
+
/**
* Returns a non-zero value if an unsupported charger is attached.
*/
@@ -382,19 +400,7 @@
logOutlier = true;
}
- final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
- final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
-
- /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
- * - is just un-plugged (previously was plugged) and battery level is
- * less than or equal to WARNING, or
- * - is not plugged and battery level falls to WARNING boundary
- * (becomes <= mLowBatteryWarningLevel).
- */
- final boolean sendBatteryLow = !plugged
- && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
- && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
- && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
+ mBatteryLevelLow = isBatteryLowLocked();
sendIntentLocked();
@@ -422,7 +428,7 @@
});
}
- if (sendBatteryLow) {
+ if (mBatteryLevelLow) {
mSentLowBatteryBroadcast = true;
mHandler.post(new Runnable() {
@Override
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 06dd3ed..fdaf55e 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -28,6 +28,7 @@
import android.os.Handler;
import android.os.IVibratorService;
import android.os.PowerManager;
+import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.IBinder;
@@ -64,6 +65,7 @@
private final PowerManager.WakeLock mWakeLock;
private final IAppOpsService mAppOpsService;
private final IBatteryStats mBatteryStatsService;
+ private PowerManagerInternal mPowerManagerInternal;
private InputManager mIm;
volatile VibrateThread mThread;
@@ -169,14 +171,19 @@
mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
mSettingObserver = new SettingsObserver(mH);
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ updateInputDeviceVibrators();
+ }
+ });
+
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
true, mSettingObserver, UserHandle.USER_ALL);
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), false,
- mSettingObserver, UserHandle.USER_ALL);
-
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -448,8 +455,7 @@
} catch (SettingNotFoundException snfe) {
}
- mLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE, 0) != 0;
+ mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
if (mVibrateInputDevicesSetting) {
if (!mInputDeviceListenerRegistered) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index aca17bf..d8671d9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -406,6 +406,12 @@
// If true, the device is in low power mode.
private boolean mLowPowerModeEnabled;
+ // Current state of the low power mode setting.
+ private boolean mLowPowerModeSetting;
+
+ // True if the battery level is currently considered low.
+ private boolean mBatteryLevelLow;
+
private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
= new ArrayList<PowerManagerInternal.LowPowerModeListener>();
@@ -502,6 +508,7 @@
// Register for broadcasts from other components of the system.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
filter = new IntentFilter();
@@ -638,7 +645,18 @@
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
- if (lowPowerModeEnabled != mLowPowerModeEnabled) {
+ if (lowPowerModeEnabled != mLowPowerModeSetting) {
+ mLowPowerModeSetting = lowPowerModeEnabled;
+ updateLowPowerModeLocked();
+ }
+
+ mDirty |= DIRTY_SETTINGS;
+ }
+
+ void updateLowPowerModeLocked() {
+ final boolean lowPowerModeEnabled = mLowPowerModeSetting || mBatteryLevelLow;
+ if (mLowPowerModeEnabled != lowPowerModeEnabled) {
+ mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
mLowPowerModeEnabled = lowPowerModeEnabled;
BackgroundThread.getHandler().post(new Runnable() {
@@ -652,11 +670,12 @@
for (int i=0; i<listeners.size(); i++) {
listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
}
+ Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(intent);
}
});
}
-
- mDirty |= DIRTY_SETTINGS;
}
private void handleSettingsChangedLocked() {
@@ -1137,9 +1156,11 @@
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
+ final boolean oldLevelLow = mBatteryLevelLow;
mIsPowered = mBatteryService.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryService.getPlugType();
mBatteryLevel = mBatteryService.getBatteryLevel();
+ mBatteryLevelLow = mBatteryService.getBatteryLevelLow();
if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
@@ -1175,6 +1196,10 @@
mNotifier.onWirelessChargingStarted();
}
}
+
+ if (oldLevelLow != mBatteryLevelLow) {
+ updateLowPowerModeLocked();
+ }
}
}
@@ -1896,6 +1921,12 @@
}
}
+ private boolean isLowPowerModeInternal() {
+ synchronized (mLock) {
+ return mLowPowerModeEnabled;
+ }
+ }
+
private void handleBatteryStateChangedLocked() {
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
@@ -2764,6 +2795,16 @@
}
}
+ @Override // Binder call
+ public boolean isPowerSaveMode() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isLowPowerModeInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
/**
* Reboots the device.
*
diff --git a/services/core/java/com/android/server/task/controllers/BatteryController.java b/services/core/java/com/android/server/task/controllers/BatteryController.java
index 585b41f..4727e9a 100644
--- a/services/core/java/com/android/server/task/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/task/controllers/BatteryController.java
@@ -151,7 +151,7 @@
// Initialise tracker state.
BatteryService batteryService = (BatteryService) ServiceManager.getService("battery");
if (batteryService != null) {
- mBatteryHealthy = !batteryService.isBatteryLow();
+ mBatteryHealthy = !batteryService.getBatteryLevelLow();
mCharging = batteryService.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
} else {
// Unavailable for some reason, we default to false and let ACTION_BATTERY_[OK,LOW]
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 35b7f99..cfd09e5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -541,7 +541,7 @@
if (isMagnifyingLocked()) {
setMagnifiedRegionBorderShownLocked(false, false);
final long delay = (long) (mLongAnimationDuration
- * mWindowManagerService.mWindowAnimationScale);
+ * mWindowManagerService.getWindowAnimationScaleLocked());
Message message = mHandler.obtainMessage(
MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
mHandler.sendMessageDelayed(message, delay);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 7fe895b..63ae98e 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -87,7 +87,7 @@
anim.initialize(width, height, width, height);
}
anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
- anim.scaleCurrentDuration(mService.mTransitionAnimationScale);
+ anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
int zorder = anim.getZAdjustment();
int adj = 0;
if (zorder == Animation.ZORDER_TOP) {
@@ -227,7 +227,8 @@
if (!animating) {
if (WindowManagerService.DEBUG_ANIM) Slog.v(
TAG, "Starting animation in " + mAppToken +
- " @ " + currentTime + " scale=" + mService.mTransitionAnimationScale
+ " @ " + currentTime + " scale="
+ + mService.getTransitionAnimationScaleLocked()
+ " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
animation.setStartTime(currentTime);
animating = true;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index ca9076f..3200b54 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.view.IWindowId;
+import android.view.IWindowSessionCallback;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
@@ -54,6 +55,7 @@
final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
final WindowManagerService mService;
+ final IWindowSessionCallback mCallback;
final IInputMethodClient mClient;
final IInputContext mInputContext;
final int mUid;
@@ -62,14 +64,17 @@
SurfaceSession mSurfaceSession;
int mNumWindow = 0;
boolean mClientDead = false;
+ float mLastReportedAnimatorScale;
- public Session(WindowManagerService service, IInputMethodClient client,
- IInputContext inputContext) {
+ public Session(WindowManagerService service, IWindowSessionCallback callback,
+ IInputMethodClient client, IInputContext inputContext) {
mService = service;
+ mCallback = callback;
mClient = client;
mInputContext = inputContext;
mUid = Binder.getCallingUid();
mPid = Binder.getCallingPid();
+ mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
StringBuilder sb = new StringBuilder();
sb.append("Session{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
@@ -464,6 +469,9 @@
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
WindowManagerService.TAG, " NEW SURFACE SESSION " + mSurfaceSession);
mService.mSessions.add(this);
+ if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
+ mService.dispatchNewAnimatorScaleLocked(this);
+ }
}
mNumWindow++;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 616db42..2d15dab 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -24,6 +24,7 @@
import android.util.TimeUtils;
import android.view.IWindowId;
+import android.view.IWindowSessionCallback;
import android.view.WindowContentFrameStats;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
@@ -339,7 +340,7 @@
/**
* All currently active sessions with clients.
*/
- final HashSet<Session> mSessions = new HashSet<Session>();
+ final ArraySet<Session> mSessions = new ArraySet<Session>();
/**
* Mapping from an IWindow IBinder to the server's Window object.
@@ -562,9 +563,10 @@
PowerManager mPowerManager;
PowerManagerInternal mPowerManagerInternal;
- float mWindowAnimationScale = 1.0f;
- float mTransitionAnimationScale = 1.0f;
- float mAnimatorDurationScale = 1.0f;
+ float mWindowAnimationScaleSetting = 1.0f;
+ float mTransitionAnimationScaleSetting = 1.0f;
+ float mAnimatorDurationScaleSetting = 1.0f;
+ boolean mAnimationsDisabled = false;
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
@@ -780,6 +782,19 @@
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.setPolicy(mPolicy); // TODO: register as local service instead
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ new PowerManagerInternal.LowPowerModeListener() {
+ @Override
+ public void onLowPowerModeChanged(boolean enabled) {
+ synchronized (mWindowMap) {
+ if (mAnimationsDisabled != enabled) {
+ mAnimationsDisabled = enabled;
+ dispatchNewAnimatorScaleLocked(null);
+ }
+ }
+ }
+ });
+ mAnimationsDisabled = mPowerManagerInternal.getLowPowerModeEnabled();
mScreenFrozenLock = mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
mScreenFrozenLock.setReferenceCounted(false);
@@ -799,12 +814,12 @@
);
// Get persisted window scale setting
- mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
- Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
- mTransitionAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+ mWindowAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
+ Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScaleSetting);
setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
- Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale));
+ Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
@@ -5188,9 +5203,9 @@
scale = fixScale(scale);
switch (which) {
- case 0: mWindowAnimationScale = scale; break;
- case 1: mTransitionAnimationScale = scale; break;
- case 2: mAnimatorDurationScale = scale; break;
+ case 0: mWindowAnimationScaleSetting = scale; break;
+ case 1: mTransitionAnimationScaleSetting = scale; break;
+ case 2: mAnimatorDurationScaleSetting = scale; break;
}
// Persist setting
@@ -5206,13 +5221,14 @@
if (scales != null) {
if (scales.length >= 1) {
- mWindowAnimationScale = fixScale(scales[0]);
+ mWindowAnimationScaleSetting = fixScale(scales[0]);
}
if (scales.length >= 2) {
- mTransitionAnimationScale = fixScale(scales[1]);
+ mTransitionAnimationScaleSetting = fixScale(scales[1]);
}
if (scales.length >= 3) {
- setAnimatorDurationScale(fixScale(scales[2]));
+ mAnimatorDurationScaleSetting = fixScale(scales[2]);
+ dispatchNewAnimatorScaleLocked(null);
}
}
@@ -5221,24 +5237,43 @@
}
private void setAnimatorDurationScale(float scale) {
- mAnimatorDurationScale = scale;
+ mAnimatorDurationScaleSetting = scale;
ValueAnimator.setDurationScale(scale);
}
+ public float getWindowAnimationScaleLocked() {
+ return mAnimationsDisabled ? 0 : mWindowAnimationScaleSetting;
+ }
+
+ public float getTransitionAnimationScaleLocked() {
+ return mAnimationsDisabled ? 0 : mTransitionAnimationScaleSetting;
+ }
+
@Override
public float getAnimationScale(int which) {
switch (which) {
- case 0: return mWindowAnimationScale;
- case 1: return mTransitionAnimationScale;
- case 2: return mAnimatorDurationScale;
+ case 0: return mWindowAnimationScaleSetting;
+ case 1: return mTransitionAnimationScaleSetting;
+ case 2: return mAnimatorDurationScaleSetting;
}
return 0;
}
@Override
public float[] getAnimationScales() {
- return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
- mAnimatorDurationScale };
+ return new float[] { mWindowAnimationScaleSetting, mTransitionAnimationScaleSetting,
+ mAnimatorDurationScaleSetting };
+ }
+
+ @Override
+ public float getCurrentAnimatorScale() {
+ synchronized(mWindowMap) {
+ return mAnimationsDisabled ? 0 : mAnimatorDurationScaleSetting;
+ }
+ }
+
+ void dispatchNewAnimatorScaleLocked(Session session) {
+ mH.obtainMessage(H.NEW_ANIMATOR_SCALE, session).sendToTarget();
}
@Override
@@ -6096,7 +6131,7 @@
&& screenRotationAnimation.hasScreenshot()) {
if (screenRotationAnimation.setRotationInTransaction(
rotation, mFxSession,
- MAX_ANIMATION_DURATION, mTransitionAnimationScale,
+ MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(),
displayInfo.logicalWidth, displayInfo.logicalHeight)) {
scheduleAnimationLocked();
}
@@ -7181,6 +7216,8 @@
public static final int SHOW_DISPLAY_MASK = 33;
public static final int ALL_WINDOWS_DRAWN = 34;
+ public static final int NEW_ANIMATOR_SCALE = 35;
+
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7431,11 +7468,12 @@
case PERSIST_ANIMATION_SCALE: {
Settings.Global.putFloat(mContext.getContentResolver(),
- Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
+ Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
Settings.Global.putFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mTransitionAnimationScaleSetting);
Settings.Global.putFloat(mContext.getContentResolver(),
- Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
+ Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting);
break;
}
@@ -7638,6 +7676,33 @@
}
}
}
+ case NEW_ANIMATOR_SCALE: {
+ float scale = getCurrentAnimatorScale();
+ ValueAnimator.setDurationScale(scale);
+ Session session = (Session)msg.obj;
+ if (session != null) {
+ try {
+ session.mCallback.onAnimatorScaleChanged(scale);
+ } catch (RemoteException e) {
+ }
+ } else {
+ ArrayList<IWindowSessionCallback> callbacks
+ = new ArrayList<IWindowSessionCallback>();
+ synchronized (mWindowMap) {
+ for (int i=0; i<mSessions.size(); i++) {
+ callbacks.add(mSessions.valueAt(i).mCallback);
+ }
+
+ }
+ for (int i=0; i<callbacks.size(); i++) {
+ try {
+ callbacks.get(i).onAnimatorScaleChanged(scale);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
@@ -7650,11 +7715,11 @@
// -------------------------------------------------------------
@Override
- public IWindowSession openSession(IInputMethodClient client,
+ public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
- Session session = new Session(this, client, inputContext);
+ Session session = new Session(this, callback, client, inputContext);
return session;
}
@@ -8764,7 +8829,7 @@
displayInfo.appWidth, displayInfo.appHeight, transit);
appAnimator.thumbnailAnimation = anim;
anim.restrictDuration(MAX_ANIMATION_DURATION);
- anim.scaleCurrentDuration(mTransitionAnimationScale);
+ anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());
Point p = new Point();
mAppTransition.getStartingPoint(p);
appAnimator.thumbnailX = p.x;
@@ -10072,7 +10137,7 @@
mExitAnimId = mEnterAnimId = 0;
}
if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
- mTransitionAnimationScale, displayInfo.logicalWidth,
+ getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
scheduleAnimationLocked();
} else {
@@ -10407,13 +10472,10 @@
void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
- if (mSessions.size() > 0) {
- Iterator<Session> it = mSessions.iterator();
- while (it.hasNext()) {
- Session s = it.next();
- pw.print(" Session "); pw.print(s); pw.println(':');
- s.dump(pw, " ");
- }
+ for (int i=0; i<mSessions.size(); i++) {
+ Session s = mSessions.valueAt(i);
+ pw.print(" Session "); pw.print(s); pw.println(':');
+ s.dump(pw, " ");
}
}
@@ -10617,9 +10679,10 @@
pw.print(" mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
- pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
- pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
- pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
+ pw.print(" Animation settings: disabled="); pw.print(mAnimationsDisabled);
+ pw.print(" window="); pw.print(mWindowAnimationScaleSetting);
+ pw.print(" transition="); pw.print(mTransitionAnimationScaleSetting);
+ pw.print(" animator="); pw.println(mAnimatorDurationScaleSetting);
pw.print(" mTraversalScheduled="); pw.println(mTraversalScheduled);
pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e257ebc..bda10de 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -207,7 +207,7 @@
mLocalAnimating = false;
mAnimation = anim;
mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
- mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale);
+ mAnimation.scaleCurrentDuration(mService.getWindowAnimationScaleLocked());
// Start out animation gone if window is gone, or visible if window is visible.
mTransformation.clear();
mTransformation.setAlpha(mLastHidden ? 0 : 1);
@@ -283,7 +283,7 @@
" @ " + currentTime + ": ww=" + mWin.mFrame.width() +
" wh=" + mWin.mFrame.height() +
" dw=" + mAnimDw + " dh=" + mAnimDh +
- " scale=" + mService.mWindowAnimationScale);
+ " scale=" + mService.getWindowAnimationScaleLocked());
mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
mAnimDw, mAnimDh);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index cfe8e15..2f40003 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -195,8 +195,8 @@
}
@Override
- public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
- throws RemoteException {
+ public IWindowSession openSession(IWindowSessionCallback argn1, IInputMethodClient arg0,
+ IInputContext arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@@ -276,6 +276,11 @@
}
@Override
+ public float getCurrentAnimatorScale() throws RemoteException {
+ return 0;
+ }
+
+ @Override
public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub