Merge change 5940 into donut
* changes:
Add CLDR data/formats for newly-translated locales.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 62dc651..5ee29ac 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3981,7 +3981,10 @@
ProviderRecord pr = mProviderMap.get(name);
if (pr.mProvider.asBinder() == provider.asBinder()) {
Log.i(TAG, "Removing dead content provider: " + name);
- mProviderMap.remove(name);
+ ProviderRecord removed = mProviderMap.remove(name);
+ if (removed != null) {
+ removed.mProvider.asBinder().unlinkToDeath(removed, 0);
+ }
}
}
}
@@ -3990,7 +3993,10 @@
ProviderRecord pr = mProviderMap.get(name);
if (pr.mProvider.asBinder() == provider.asBinder()) {
Log.i(TAG, "Removing dead content provider: " + name);
- mProviderMap.remove(name);
+ ProviderRecord removed = mProviderMap.remove(name);
+ if (removed != null) {
+ removed.mProvider.asBinder().unlinkToDeath(removed, 0);
+ }
}
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 44d1eaa..0785029 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -242,8 +242,15 @@
// Reset any stored values from last time dialog was shown.
mStoredComponentName = null;
mStoredAppSearchData = null;
-
- return doShow(initialQuery, selectInitialQuery, componentName, appSearchData, globalSearch);
+
+ boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData,
+ globalSearch);
+ if (success) {
+ // Display the drop down as soon as possible instead of waiting for the rest of the
+ // pending UI stuff to get done, so that things appear faster to the user.
+ mSearchAutoComplete.showDropDownAfterLayout();
+ }
+ return success;
}
/**
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index eca04b3..3660001 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -21,7 +21,9 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetService;
@@ -187,6 +189,8 @@
Context mContext;
+ private DisplayMetrics mDisplayMetrics;
+
/**
* Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
* Context} object.
@@ -213,6 +217,7 @@
private AppWidgetManager(Context context) {
mContext = context;
+ mDisplayMetrics = context.getResources().getDisplayMetrics();
}
/**
@@ -292,7 +297,15 @@
*/
public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
try {
- return sService.getAppWidgetInfo(appWidgetId);
+ AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
+ if (info != null) {
+ // Converting complex to dp.
+ info.minWidth =
+ TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
+ info.minHeight =
+ TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
+ }
+ return info;
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index e84e5b0..2182384 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -124,6 +124,7 @@
private boolean mBlockCompletion;
private AutoCompleteTextView.ListSelectorHider mHideSelector;
+ private Runnable mShowDropDownRunnable;
private AutoCompleteTextView.PassThroughClickListener mPassThroughClickListener;
@@ -1080,6 +1081,15 @@
}
/**
+ * Issues a runnable to show the dropdown as soon as possible.
+ *
+ * @hide internal used only by Search Dialog
+ */
+ public void showDropDownAfterLayout() {
+ post(mShowDropDownRunnable);
+ }
+
+ /**
* <p>Displays the drop down on screen.</p>
*/
public void showDropDown() {
@@ -1190,6 +1200,22 @@
mHideSelector = new ListSelectorHider();
+ /**
+ * This Runnable exists for the sole purpose of checking if the view layout has got
+ * completed and if so call showDropDown to display the drop down. This is used to show
+ * the drop down as soon as possible after user opens up the search dialog, without
+ * waiting for the normal UI pipeline to do it's job which is slower than this method.
+ */
+ mShowDropDownRunnable = new Runnable() {
+ public void run() {
+ // View layout should be all done before displaying the drop down.
+ View view = getDropDownAnchorView();
+ if (view != null && view.getWindowToken() != null) {
+ showDropDown();
+ }
+ }
+ };
+
mDropDownList = new DropDownListView(context);
mDropDownList.setSelector(mDropDownListHighlight);
mDropDownList.setAdapter(mAdapter);
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index edd1ea0..4a51e31 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -617,6 +617,9 @@
synchronized(mListeners) {
mListeners.remove(this);
}
+ if (mListener != null) {
+ mListener.asBinder().unlinkToDeath(this, 0);
+ }
}
}
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index bd7088c..4ae424a 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -53,6 +53,12 @@
}
}
+ public void unlinkProvider() {
+ if (mProvider != null) {
+ mProvider.asBinder().unlinkToDeath(this, 0);
+ }
+ }
+
public String getName() {
return mName;
}
@@ -255,5 +261,6 @@
public void binderDied() {
Log.w(TAG, "Location Provider " + mName + " died");
mDead = true;
+ mProvider.asBinder().unlinkToDeath(this, 0);
}
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index c50ae94..bd8b8ef 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -40,6 +40,7 @@
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.TypedValue;
import android.util.Xml;
import android.widget.RemoteViews;
@@ -695,10 +696,16 @@
TypedArray sa = mContext.getResources().obtainAttributes(attrs,
com.android.internal.R.styleable.AppWidgetProviderInfo);
- info.minWidth = sa.getDimensionPixelSize(
- com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth, 0);
- info.minHeight = sa.getDimensionPixelSize(
- com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight, 0);
+
+ // These dimensions has to be resolved in the application's context.
+ // We simply send back the raw complex data, which will be
+ // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
+ TypedValue value = sa.peekValue(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
+ info.minWidth = value != null ? value.data : 0;
+ value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
+ info.minHeight = value != null ? value.data : 0;
+
info.updatePeriodMillis = sa.getInt(
com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
info.initialLayout = sa.getResourceId(
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index ecdf926..b15c06b 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -33,6 +33,7 @@
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.net.Uri;
+import android.provider.Settings;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -42,7 +43,6 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.util.Log;
import android.util.SparseArray;
@@ -74,12 +74,13 @@
private static final String TAG = "BackupManagerService";
private static final boolean DEBUG = true;
- // Persistent properties
- private static final String BACKUP_TRANSPORT_PROPERTY = "persist.service.bkup.trans";
- private static final String BACKUP_ENABLED_PROPERTY = "persist.service.bkup.enabled";
+ // Secure settings
+ private static final String BACKUP_TRANSPORT_SETTING = "backup_transport";
+ private static final String BACKUP_ENABLED_SETTING = "backup_enabled";
- // Default time to wait after data changes before we back up the data
- private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
+ // How often we perform a backup pass. Privileged external callers can
+ // trigger an immediate pass.
+ private static final long BACKUP_INTERVAL = 60 * 60 * 1000;
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_FULL_BACKUP = 2;
@@ -166,7 +167,8 @@
// Set up our bookkeeping
// !!! STOPSHIP: make this disabled by default so that we then gate on
// setupwizard or other opt-out UI
- mEnabled = SystemProperties.getBoolean(BACKUP_ENABLED_PROPERTY, true);
+ mEnabled = (Settings.Secure.getInt(mContext.getContentResolver(),
+ BACKUP_ENABLED_SETTING, 1) != 0);
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mDataDir = Environment.getDownloadCacheDirectory();
@@ -191,8 +193,13 @@
mGoogleTransport = null;
// !!! TODO: set up the default transport name "the right way"
- mCurrentTransport = SystemProperties.get(BACKUP_TRANSPORT_PROPERTY,
- "com.google.android.backup/.BackupTransportService");
+ mCurrentTransport = Settings.Secure.getString(mContext.getContentResolver(),
+ BACKUP_TRANSPORT_SETTING);
+ if (mCurrentTransport == null) {
+ mCurrentTransport = "com.google.android.backup/.BackupTransportService";
+ Settings.Secure.putString(mContext.getContentResolver(),
+ BACKUP_TRANSPORT_SETTING, mCurrentTransport);
+ }
if (DEBUG) Log.v(TAG, "Starting with transport " + mCurrentTransport);
// Attach to the Google backup transport. When this comes up, it will set
@@ -204,7 +211,7 @@
context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
// Now that we know about valid backup participants, parse any
- // leftover journal files and schedule a new backup pass
+ // leftover journal files into the pending backup set
parseLeftoverJournals();
// Register for broadcasts about package install, etc., so we can
@@ -214,7 +221,13 @@
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
- }
+
+ // Schedule the first backup pass -- okay because no other threads are
+ // running yet
+ if (mEnabled) {
+ scheduleBackupPassLocked(BACKUP_INTERVAL);
+ }
+}
private void makeJournalLocked() {
try {
@@ -336,35 +349,39 @@
ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
File oldJournal = mJournal;
synchronized (mQueueLock) {
- if (mPendingBackups.size() == 0) {
- Log.v(TAG, "Backup requested but nothing pending");
- break;
- }
-
- for (BackupRequest b: mPendingBackups.values()) {
- queue.add(b);
- }
- Log.v(TAG, "clearing pending backups");
- mPendingBackups.clear();
-
- // Start a new backup-queue journal file too
- if (mJournalStream != null) {
- try {
- mJournalStream.close();
- } catch (IOException e) {
- // don't need to do anything
+ // Do we have any work to do?
+ if (mPendingBackups.size() > 0) {
+ for (BackupRequest b: mPendingBackups.values()) {
+ queue.add(b);
}
- makeJournalLocked();
- }
+ Log.v(TAG, "clearing pending backups");
+ mPendingBackups.clear();
- // At this point, we have started a new journal file, and the old
- // file identity is being passed to the backup processing thread.
- // When it completes successfully, that old journal file will be
- // deleted. If we crash prior to that, the old journal is parsed
- // at next boot and the journaled requests fulfilled.
+ // Start a new backup-queue journal file too
+ if (mJournalStream != null) {
+ try {
+ mJournalStream.close();
+ } catch (IOException e) {
+ // don't need to do anything
+ }
+ makeJournalLocked();
+ }
+
+ // At this point, we have started a new journal file, and the old
+ // file identity is being passed to the backup processing thread.
+ // When it completes successfully, that old journal file will be
+ // deleted. If we crash prior to that, the old journal is parsed
+ // at next boot and the journaled requests fulfilled.
+ (new PerformBackupThread(transport, queue, oldJournal)).start();
+ } else {
+ Log.v(TAG, "Backup requested but nothing pending");
+ }
}
- (new PerformBackupThread(transport, queue, oldJournal)).start();
+ // Schedule the next pass.
+ synchronized (mQueueLock) {
+ scheduleBackupPassLocked(BACKUP_INTERVAL);
+ }
break;
}
@@ -1109,10 +1126,6 @@
Log.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
}
}
- // Schedule a backup pass in a few minutes. As backup-eligible data
- // keeps changing, continue to defer the backup pass until things
- // settle down, to avoid extra overhead.
- scheduleBackupPassLocked(COLLECTION_INTERVAL);
}
} else {
Log.w(TAG, "dataChanged but no participant pkg " + packageName);
@@ -1148,20 +1161,21 @@
boolean wasEnabled = mEnabled;
synchronized (this) {
- SystemProperties.set(BACKUP_ENABLED_PROPERTY, enable ? "true" : "false");
+ Settings.Secure.putInt(mContext.getContentResolver(), BACKUP_ENABLED_SETTING,
+ enable ? 1 : 0);
mEnabled = enable;
}
- if (enable && !wasEnabled) {
- synchronized (mQueueLock) {
- if (mPendingBackups.size() > 0) {
- // !!! TODO: better policy around timing of the first backup pass
- if (DEBUG) Log.v(TAG, "Backup enabled with pending data changes, scheduling");
- this.scheduleBackupPassLocked(COLLECTION_INTERVAL);
- }
+ synchronized (mQueueLock) {
+ if (enable && !wasEnabled) {
+ // if we've just been enabled, start scheduling backup passes
+ scheduleBackupPassLocked(BACKUP_INTERVAL);
+ } else if (!enable) {
+ // No longer enabled, so stop running backups.
+ mBackupHandler.removeMessages(MSG_RUN_BACKUP);
}
}
-}
+ }
// Report whether the backup mechanism is currently enabled
public boolean isBackupEnabled() {
@@ -1206,7 +1220,8 @@
if (mTransports.get(transport) != null) {
prevTransport = mCurrentTransport;
mCurrentTransport = transport;
- SystemProperties.set(BACKUP_TRANSPORT_PROPERTY, transport);
+ Settings.Secure.putString(mContext.getContentResolver(), BACKUP_TRANSPORT_SETTING,
+ transport);
Log.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ " returning " + prevTransport);
} else {
@@ -1334,13 +1349,22 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
+ pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
+ boolean scheduled = mBackupHandler.hasMessages(MSG_RUN_BACKUP);
+ if (scheduled != mEnabled) {
+ if (mEnabled) {
+ pw.println("ERROR: backups enabled but none scheduled!");
+ } else {
+ pw.println("ERROR: backups are scheduled but not enabled!");
+ }
+ }
pw.println("Available transports:");
for (String t : listAllTransports()) {
String pad = (t.equals(mCurrentTransport)) ? " * " : " ";
pw.println(pad + t);
}
int N = mBackupParticipants.size();
- pw.println("Participants:");
+ pw.println("Participants: " + N);
for (int i=0; i<N; i++) {
int uid = mBackupParticipants.keyAt(i);
pw.print(" uid: ");
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index fc37290..0f5b3fd 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -507,6 +507,7 @@
private void removeProvider(LocationProviderProxy provider) {
mProviders.remove(provider);
+ provider.unlinkProvider();
mProvidersByName.remove(provider.getName());
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index c5ea5fa9..79d78ad1 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -709,7 +709,10 @@
p.awakeOnSet = true;
}
} else {
- mPokeLocks.remove(token);
+ PokeLock rLock = mPokeLocks.remove(token);
+ if (rLock != null) {
+ token.unlinkToDeath(rLock, 0);
+ }
}
int oldPokey = mPokey;
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5df88b2..f5e2e3d 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1875,7 +1875,9 @@
private WifiLock removeLock(IBinder binder) {
int index = findLockByBinder(binder);
if (index >= 0) {
- return mList.remove(index);
+ WifiLock ret = mList.remove(index);
+ ret.unlinkDeathRecipient();
+ return ret;
} else {
return null;
}
@@ -1987,6 +1989,10 @@
binderDied();
}
}
+
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
}
private class Multicaster extends DeathRecipient {
@@ -2054,7 +2060,10 @@
private void removeMulticasterLocked(int i, int uid)
{
- mMulticasters.remove(i);
+ Multicaster removed = mMulticasters.remove(i);
+ if (removed != null) {
+ removed.unlinkDeathRecipient();
+ }
if (mMulticasters.size() == 0) {
WifiNative.startPacketFiltering();
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9bad153..cfa625c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -3407,7 +3407,10 @@
synchronized (mWindowMap) {
for (int i=0; i<mRotationWatchers.size(); i++) {
if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
- mRotationWatchers.remove(i);
+ IRotationWatcher removed = mRotationWatchers.remove(i);
+ if (removed != null) {
+ removed.asBinder().unlinkToDeath(this, 0);
+ }
i--;
}
}
@@ -5442,6 +5445,7 @@
} catch (RemoteException e) {
}
synchronized(mWindowMap) {
+ mClient.asBinder().unlinkToDeath(this, 0);
mClientDead = true;
killSessionLocked();
}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 48cbace..b44168a 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -119,6 +119,7 @@
public void binderDied() {
Log.i(TAG, "binder died for pkg=" + pkg);
disable(0, token, pkg);
+ token.unlinkToDeath(this, 0);
}
}
@@ -494,6 +495,7 @@
if (what == 0 || !token.isBinderAlive()) {
if (tok != null) {
mDisableRecords.remove(i);
+ tok.token.unlinkToDeath(tok, 0);
}
} else {
if (tok == null) {