Merge "Optimize RTL properties resolution" into jb-mr2-dev
diff --git a/api/current.txt b/api/current.txt
index 1166546..21c1ef0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6061,8 +6061,6 @@
field public static final java.lang.String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
field public static final java.lang.String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
- field public static final java.lang.String ACTION_IDLE_MAINTENANCE_END = "android.intent.action.ACTION_IDLE_MAINTENANCE_END";
- field public static final java.lang.String ACTION_IDLE_MAINTENANCE_START = "android.intent.action.ACTION_IDLE_MAINTENANCE_START";
field public static final java.lang.String ACTION_INPUT_METHOD_CHANGED = "android.intent.action.INPUT_METHOD_CHANGED";
field public static final java.lang.String ACTION_INSERT = "android.intent.action.INSERT";
field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 67bd952..bfc7bf5 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2356,6 +2356,8 @@
* </p>
*
* @see #ACTION_IDLE_MAINTENANCE_END
+ *
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_IDLE_MAINTENANCE_START =
@@ -2383,6 +2385,8 @@
* by the system.
*
* @see #ACTION_IDLE_MAINTENANCE_START
+ *
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_IDLE_MAINTENANCE_END =
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 7189610..39078ca 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -598,11 +598,13 @@
mActionView = null;
mActionProvider = actionProvider;
mMenu.onItemsChanged(true); // Measurement can be changed
- mActionProvider.setVisibilityListener(new ActionProvider.VisibilityListener() {
- @Override public void onActionProviderVisibilityChanged(boolean isVisible) {
- mMenu.onItemVisibleChanged(MenuItemImpl.this);
- }
- });
+ if (mActionProvider != null) {
+ mActionProvider.setVisibilityListener(new ActionProvider.VisibilityListener() {
+ @Override public void onActionProviderVisibilityChanged(boolean isVisible) {
+ mMenu.onItemVisibleChanged(MenuItemImpl.this);
+ }
+ });
+ }
return this;
}
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 81982a1..ff2d27a 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -40,6 +40,10 @@
<span class="en">Google Maps</span></a>
</li>
+ <li><a href="<?cs var:toroot?>google/play-services/games.html">
+ <span class="en">Games</span></a>
+ </li>
+
<li id="gms-tree-list" class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>reference/gms-packages.html">
diff --git a/docs/html/google/play-services/games.jd b/docs/html/google/play-services/games.jd
new file mode 100644
index 0000000..8555b94
--- /dev/null
+++ b/docs/html/google/play-services/games.jd
@@ -0,0 +1,69 @@
+page.title=Google Play Games
+header.hide=1
+
+@jd:body
+
+<div class="landing-banner">
+
+<div class="col-6">
+ <img src="{@docRoot}images/google/game_services.png" alt="">
+</div>
+<div class="col-6">
+
+<h1 itemprop="name" style="margin-bottom:0;">Google Play Games Platform Services</h1>
+ <p itemprop="description">
+ Google Play Games Platform Services lets you integrate popular gaming features such as achievements, leaderboards, and real-time multiplayer gameplay in your apps. Players can sign in using their Google+ identities and share their gaming experience with friends.
+ </p>
+ <p>Visit <a class="external-link"
+ href="https://developers.google.com/games/services/">developers.google.com/games/services</a> for more information about integrating game services into your app.
+</p>
+</div>
+</div>
+
+<div class="landing-docs">
+ <div class="col-6 normal-links">
+ <h3 style="clear:left">Key Developer Features</h3>
+ <h4>Drive engagement with leaderboards</h4>
+ <p>Let players compare scores with friends using leaderboards or see how they rank against other players worldwide. Games Platform Services automatically maintains daily, weekly, and all-time high scores. <a class="external-link" href="https://developers.google.com/games/services/android/leaderboards">Build leaderboards</a>.</p>
+
+ <h4>Reward players with achievements</h4>
+ <p>Add hidden and incremental achievements to encourage users to explore your game in new and interesting ways. You can use the built-in UI for Android to display achievement progress.
+ <a class="external-link" href="https://developers.google.com/games/services/android/achievements">Add achievements to your game</a>.</p>
+ </a>
+
+ <h4>Create real-time multiplayer games</h4>
+ <p>Make your game more dynamic by letting multiple players compete or cooperate simultaneously. You can use the Games Platform Services API to invite game participants or auto-match players anonymously, and exchange data between game clients. <a class="external-link" href="https://developers.google.com/games/services/android/multiplayer">Develop real-time multiplayer games</a>.</p>
+
+ <h4>Save game progress to the cloud</h4>
+ <p>Store game data on Google servers using Cloud Save. Synchronize game progress seamlessly across all your users' devices. <a class="external-link" href="https://developers.google.com/games/services/android/cloudsave">Save games in the cloud</a>.</p>
+ </div>
+
+
+ <div class="col-6 normal-links">
+ <h3 style="clear:left">Getting Started</h3>
+ <h4>1. Get the Google Play services SDK</h4>
+ <p>The Games Platform Services API for Android is part of the Google Play services platform.</p>
+ <p>To use game services, <a href="{@docRoot}google/play-services/setup.html">set up</a>
+ the Google Play services SDK. Then, see the <a class="external-link"
+ href="https://developers.google.com/games/services/android/quickstart">
+ Getting Started guide</a> to set up your app.
+ </p>
+
+ <h4>2. Run the sample</h4>
+
+ <p>Once you've installed the Google Play services package, <a class="external-link"
+ href="https://developers.google.com/games/services/downloads/">download the game services samples</a> to learn how to use the major components of the Games Platform Services APIs.
+ </p>
+
+ <h4>3. Read the documentation</h4>
+
+ <p>Read the <a class="external-link" href="https://developers.google.com/games/services/terms">
+ API Terms of Service</a>.</p>
+ <p>Detailed documentation for the Games Platform Services is available at <a class="external-link"
+ href="https://developers.google.com/games/services/">developers.google.com/games/services</a>.
+ </p>
+ <p>For quick access while developing your Android apps, the
+ <a href="{@docRoot}reference/com/google/android/gms/games/package-summary.html">Games Platform Services API for Android reference</a> is available here on developer.android.com.</p>
+ </div>
+
+</div>
diff --git a/docs/html/images/google/game_services.png b/docs/html/images/google/game_services.png
new file mode 100644
index 0000000..f62d7f0
--- /dev/null
+++ b/docs/html/images/google/game_services.png
Binary files differ
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index dbffa97..1f2947d 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -236,6 +236,15 @@
}
}
+ /**
+ * Returns a non-zero value if an unsupported charger is attached.
+ */
+ public int getInvalidCharger() {
+ synchronized (mLock) {
+ return mInvalidCharger;
+ }
+ }
+
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/java/com/android/server/IdleMaintenanceService.java
index 0c90de4..584d4bc 100644
--- a/services/java/com/android/server/IdleMaintenanceService.java
+++ b/services/java/com/android/server/IdleMaintenanceService.java
@@ -17,11 +17,12 @@
package com.android.server;
import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.BatteryManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
@@ -40,7 +41,6 @@
* The current implementation is very simple. The start of a maintenance
* window is announced if: the screen is off or showing a dream AND the
* battery level is more than twenty percent AND at least one hour passed
- * since the screen went off or a dream started (i.e. since the last user
* activity).
*
* The end of a maintenance window is announced only if: a start was
@@ -48,27 +48,44 @@
*/
public class IdleMaintenanceService extends BroadcastReceiver {
- private final boolean DEBUG = false;
+ private static final boolean DEBUG = false;
private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName();
private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
- private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
+ private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day
private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent
private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 10; // percent
+ private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent
- private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 60 * 60 * 1000; // 1 hour
+ private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min
- private final Intent mIdleMaintenanceStartIntent =
- new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
+ private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min
- private final Intent mIdleMaintenanceEndIntent =
- new Intent(Intent.ACTION_IDLE_MAINTENANCE_END);
+ private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
+ "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
+
+ private static final Intent sIdleMaintenanceStartIntent;
+ static {
+ sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
+ sIdleMaintenanceStartIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ };
+
+ private static final Intent sIdleMaintenanceEndIntent;
+ static {
+ sIdleMaintenanceEndIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_END);
+ sIdleMaintenanceEndIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ }
+
+ private final AlarmManager mAlarmService;
+
+ private final BatteryService mBatteryService;
+
+ private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent;
private final Context mContext;
@@ -76,30 +93,37 @@
private final Handler mHandler;
- private long mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
+ private long mLastIdleMaintenanceStartTimeMillis;
private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
- private int mBatteryLevel;
-
- private boolean mBatteryCharging;
-
private boolean mIdleMaintenanceStarted;
- public IdleMaintenanceService(Context context) {
+ public IdleMaintenanceService(Context context, BatteryService batteryService) {
mContext = context;
+ mBatteryService = batteryService;
+
+ mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
mHandler = new Handler(mContext.getMainLooper());
+ Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
register(mContext.getMainLooper());
}
public void register(Looper looper) {
IntentFilter intentFilter = new IntentFilter();
+ // Alarm actions.
+ intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
+
// Battery actions.
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
@@ -115,67 +139,117 @@
intentFilter, null, new Handler(looper));
}
+ private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
+ final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
+ mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis,
+ mUpdateIdleMaintenanceStatePendingIntent);
+ }
+
+ private void unscheduleUpdateIdleMaintenanceState() {
+ mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
+ }
+
private void updateIdleMaintenanceState() {
if (mIdleMaintenanceStarted) {
- // Idle maintenance can be interrupted only by
- // a change of the device state.
- if (!deviceStatePermitsIdleMaintenanceRunning()) {
+ // Idle maintenance can be interrupted by user activity, or duration
+ // time out, or low battery.
+ if (!lastUserActivityPermitsIdleMaintenanceRunning()
+ || !batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) {
+ unscheduleUpdateIdleMaintenanceState();
mIdleMaintenanceStarted = false;
EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryLevel,
- mBatteryCharging ? 1 : 0);
+ mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
+ isBatteryCharging() ? 1 : 0);
sendIdleMaintenanceEndIntent();
+ // We stopped since we don't have enough battery or timed out but the
+ // user is not using the device, so we should be able to run maintenance
+ // in the next maintenance window since the battery may be charged
+ // without interaction and the min interval between maintenances passed.
+ if (!batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning()) {
+ scheduleUpdateIdleMaintenanceState(
+ getNextIdleMaintenanceIntervalStartFromNow());
+ }
}
} else if (deviceStatePermitsIdleMaintenanceStart()
&& lastUserActivityPermitsIdleMaintenanceStart()
&& lastRunPermitsIdleMaintenanceStart()) {
+ // Now that we started idle maintenance, we should schedule another
+ // update for the moment when the idle maintenance times out.
+ scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
mIdleMaintenanceStarted = true;
EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryLevel,
- mBatteryCharging ? 1 : 0);
+ mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
+ isBatteryCharging() ? 1 : 0);
mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
sendIdleMaintenanceStartIntent();
+ } else if (lastUserActivityPermitsIdleMaintenanceStart()) {
+ if (lastRunPermitsIdleMaintenanceStart()) {
+ // The user does not use the device and we did not run maintenance in more
+ // than the min interval between runs, so schedule an update - maybe the
+ // battery will be charged latter.
+ scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
+ } else {
+ // The user does not use the device but we have run maintenance in the min
+ // interval between runs, so schedule an update after the min interval ends.
+ scheduleUpdateIdleMaintenanceState(
+ getNextIdleMaintenanceIntervalStartFromNow());
+ }
}
}
+ private long getNextIdleMaintenanceIntervalStartFromNow() {
+ return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS
+ - SystemClock.elapsedRealtime();
+ }
+
private void sendIdleMaintenanceStartIntent() {
- if (DEBUG) {
- Log.i(LOG_TAG, "Broadcasting " + Intent.ACTION_IDLE_MAINTENANCE_START);
- }
mWakeLock.acquire();
- mContext.sendOrderedBroadcastAsUser(mIdleMaintenanceStartIntent, UserHandle.ALL,
+ mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
null, this, mHandler, Activity.RESULT_OK, null, null);
}
private void sendIdleMaintenanceEndIntent() {
- if (DEBUG) {
- Log.i(LOG_TAG, "Broadcasting " + Intent.ACTION_IDLE_MAINTENANCE_END);
- }
mWakeLock.acquire();
- mContext.sendOrderedBroadcastAsUser(mIdleMaintenanceEndIntent, UserHandle.ALL,
+ mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceEndIntent, UserHandle.ALL,
null, this, mHandler, Activity.RESULT_OK, null, null);
}
private boolean deviceStatePermitsIdleMaintenanceStart() {
- final int minBatteryLevel = mBatteryCharging
+ final int minBatteryLevel = isBatteryCharging()
? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
: MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
- && mBatteryLevel > minBatteryLevel);
- }
-
- private boolean deviceStatePermitsIdleMaintenanceRunning() {
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
- && mBatteryLevel > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING);
+ && mBatteryService.getBatteryLevel() > minBatteryLevel);
}
private boolean lastUserActivityPermitsIdleMaintenanceStart() {
- return (SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
- > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
+ // The last time the user poked the device is above the threshold.
+ return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
+ > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
}
private boolean lastRunPermitsIdleMaintenanceStart() {
- return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis > MILLIS_IN_DAY;
+ // Enough time passed since the last maintenance run.
+ return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
+ > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ }
+
+ private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
+ // The user is not using the device.
+ return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID);
+ }
+
+ private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() {
+ // Battery not too low and the maintenance duration did not timeout.
+ return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING
+ && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION
+ > SystemClock.elapsedRealtime());
+ }
+
+ private boolean isBatteryCharging() {
+ return mBatteryService.getPlugType() > 0
+ && mBatteryService.getInvalidCharger() == 0;
}
@Override
@@ -185,24 +259,38 @@
}
String action = intent.getAction();
if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- final int maxBatteryLevel = intent.getExtras().getInt(BatteryManager.EXTRA_SCALE);
- final int currBatteryLevel = intent.getExtras().getInt(BatteryManager.EXTRA_LEVEL);
- mBatteryLevel = (int) (((float) maxBatteryLevel / 100) * currBatteryLevel);
- final int pluggedState = intent.getExtras().getInt(BatteryManager.EXTRA_PLUGGED);
- final int chargerState = intent.getExtras().getInt(
- BatteryManager.EXTRA_INVALID_CHARGER, 0);
- mBatteryCharging = (pluggedState > 0 && chargerState == 0);
+ // We care about battery only if maintenance is in progress so we can
+ // stop it if battery is too low. Note that here we assume that the
+ // maintenance clients are properly holding a wake lock. We will
+ // refactor the maintenance to use services instead of intents for the
+ // next release. The only client for this for now is internal an holds
+ // a wake lock correctly.
+ if (mIdleMaintenanceStarted) {
+ updateIdleMaintenanceState();
+ }
} else if (Intent.ACTION_SCREEN_ON.equals(action)
|| Intent.ACTION_DREAMING_STOPPED.equals(action)) {
mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
+ // Unschedule any future updates since we already know that maintenance
+ // cannot be performed since the user is back.
+ unscheduleUpdateIdleMaintenanceState();
+ // If the screen went on/stopped dreaming, we know the user is using the
+ // device which means that idle maintenance should be stopped if running.
+ updateIdleMaintenanceState();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_DREAMING_STARTED.equals(action)) {
mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
+ // If screen went off/started dreaming, we may be able to start idle maintenance
+ // after the minimal user inactivity elapses. We schedule an alarm for when
+ // this timeout elapses since the device may go to sleep by then.
+ scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
+ } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
+ updateIdleMaintenanceState();
} else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
|| Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
+ // We were holding a wake lock while broadcasting the idle maintenance
+ // intents but now that we finished the broadcast release the wake lock.
mWakeLock.release();
- return;
}
- updateIdleMaintenanceState();
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7994b56..9455017 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -745,7 +745,7 @@
try {
Slog.i(TAG, "IdleMaintenanceService");
- new IdleMaintenanceService(context);
+ new IdleMaintenanceService(context, battery);
} catch (Throwable e) {
reportWtf("starting IdleMaintenanceService", e);
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 138c51b..4ae9eb5 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1711,6 +1711,8 @@
final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher();
+ boolean mWasConnectedAndDied;
+
// Handler only for dispatching accessibility events since we use event
// types as message types allowing us to remove messages per event type.
public Handler mEventDispatchHandler = new Handler(mMainHandler.getLooper()) {
@@ -1865,8 +1867,9 @@
mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
UserState userState = getUserStateLocked(mUserId);
addServiceLocked(this, userState);
- if (userState.mBindingServices.contains(mComponentName)) {
+ if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) {
userState.mBindingServices.remove(mComponentName);
+ mWasConnectedAndDied = false;
try {
mServiceInterface.setConnection(this, mId);
onUserStateChangedLocked(userState);
@@ -2220,7 +2223,7 @@
mServiceInterface = null;
}
- public boolean isInitializedLocked() {
+ public boolean isConnectedLocked() {
return (mService != null);
}
@@ -2230,9 +2233,10 @@
// whose handling the death recipient is unlinked and still get a call
// on binderDied since the call was made before we unlink but was
// waiting on the lock we held during the force stop handling.
- if (!isInitializedLocked()) {
+ if (!isConnectedLocked()) {
return;
}
+ mWasConnectedAndDied = true;
mKeyEventDispatcher.flush();
UserState userState = getUserStateLocked(mUserId);
// The death recipient is unregistered in removeServiceLocked
@@ -2245,7 +2249,6 @@
userState.mEnabledServices.remove(mComponentName);
userState.destroyUiAutomationService();
}
- onUserStateChangedLocked(userState);
}
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index fccaab5..9fdd293 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -371,15 +371,15 @@
return;
}
try {
- if (foregroundNoti.icon == 0) {
+ if (localForegroundNoti.icon == 0) {
// It is not correct for the caller to supply a notification
// icon, but this used to be able to slip through, so for
// those dirty apps give it the app's icon.
- foregroundNoti.icon = appInfo.icon;
+ localForegroundNoti.icon = appInfo.icon;
// Do not allow apps to present a sneaky invisible content view either.
- foregroundNoti.contentView = null;
- foregroundNoti.bigContentView = null;
+ localForegroundNoti.contentView = null;
+ localForegroundNoti.bigContentView = null;
CharSequence appName = appInfo.loadLabel(
ams.mContext.getPackageManager());
if (appName == null) {
@@ -395,7 +395,7 @@
appInfo.packageName, null));
PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- foregroundNoti.setLatestEventInfo(ctx,
+ localForegroundNoti.setLatestEventInfo(ctx,
ams.mContext.getString(
com.android.internal.R.string
.app_running_notification_title,
@@ -406,10 +406,10 @@
appName),
pi);
} catch (PackageManager.NameNotFoundException e) {
- foregroundNoti.icon = 0;
+ localForegroundNoti.icon = 0;
}
}
- if (foregroundNoti.icon == 0) {
+ if (localForegroundNoti.icon == 0) {
// Notifications whose icon is 0 are defined to not show
// a notification, silently ignoring it. We don't want to
// just ignore it, we want to prevent the service from