Merge "Skip any number of leading ID3v2 tags (instead of just the first), also simplify/fix the find-consecutive-mp3-frames functionality." into froyo
diff --git a/CleanSpec.mk b/CleanSpec.mk
index de0fd2f..417f764 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -49,6 +49,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/backup)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/backup)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/app)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.xml b/api/current.xml
index aea02e5..6477fc4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26785,59 +26785,6 @@
</package>
<package name="android.app.backup"
>
-<class name="AbsoluteFileBackupHelper"
- extends="android.app.backup.FileBackupHelperBase"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<implements name="android.app.backup.BackupHelper">
-</implements>
-<constructor name="AbsoluteFileBackupHelper"
- type="android.app.backup.AbsoluteFileBackupHelper"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="files" type="java.lang.String...">
-</parameter>
-</constructor>
-<method name="performBackup"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="oldState" type="android.os.ParcelFileDescriptor">
-</parameter>
-<parameter name="data" type="android.app.backup.BackupDataOutput">
-</parameter>
-<parameter name="newState" type="android.os.ParcelFileDescriptor">
-</parameter>
-</method>
-<method name="restoreEntity"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="data" type="android.app.backup.BackupDataInputStream">
-</parameter>
-</method>
-</class>
<class name="BackupAgent"
extends="android.content.ContextWrapper"
abstract="true"
@@ -30050,8 +29997,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="thread" type="java.lang.Thread">
-</parameter>
</method>
<field name="LOG_SYNC_DETAILS"
type="int"
@@ -30065,48 +30010,6 @@
>
</field>
</class>
-<class name="ActiveSyncInfo"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="getAccount"
- return="android.accounts.Account"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getAuthority"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getStartTime"
- return="long"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
<class name="ActivityNotFoundException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -32142,8 +32045,8 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
-<method name="getActiveSync"
- return="android.content.ActiveSyncInfo"
+<method name="getCurrentSync"
+ return="android.content.SyncInfo"
abstract="false"
native="false"
synchronized="false"
@@ -34728,17 +34631,6 @@
visibility="public"
>
</field>
-<field name="STORAGE_SERVICE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""storage""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="TELEPHONY_SERVICE"
type="java.lang.String"
transient="false"
@@ -36195,6 +36087,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.util.Iterator">
+</implements>
<method name="close"
return="void"
abstract="true"
@@ -36206,32 +36100,6 @@
visibility="public"
>
</method>
-<method name="hasNext"
- return="boolean"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
-<method name="next"
- return="android.content.Entity"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
-</method>
<method name="reset"
return="void"
abstract="true"
@@ -36242,8 +36110,6 @@
deprecated="not deprecated"
visibility="public"
>
-<exception name="RemoteException" type="android.os.RemoteException">
-</exception>
</method>
</interface>
<class name="Intent"
@@ -41676,6 +41542,45 @@
</parameter>
</method>
</class>
+<class name="SyncInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="account"
+ type="android.accounts.Account"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="authority"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="startTime"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="SyncResult"
extends="java.lang.Object"
abstract="false"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 74cfbfa..b07b690 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2148,31 +2148,7 @@
}
@Override public Drawable getApplicationIcon(ApplicationInfo info) {
- final int icon = info.icon;
- if (icon != 0) {
- ResourceName name = new ResourceName(info, icon);
- Drawable dr = getCachedIcon(name);
- if (dr != null) {
- return dr;
- }
- try {
- Resources r = getResourcesForApplication(info);
- dr = r.getDrawable(icon);
- if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
- + Integer.toHexString(icon) + " from " + r
- + ": " + dr);
- putCachedIcon(name, dr);
- return dr;
- } catch (NameNotFoundException e) {
- Log.w("PackageManager", "Failure retrieving resources for"
- + info.packageName);
- } catch (RuntimeException e) {
- // If an exception was thrown, fall through to return
- // default icon.
- Log.w("PackageManager", "Failure retrieving app icon", e);
- }
- }
- return getDefaultActivityIcon();
+ return info.loadIcon(this);
}
@Override public Drawable getApplicationIcon(String packageName)
@@ -2413,25 +2389,6 @@
}
}
- private CharSequence getLabel(ResourceName name, ApplicationInfo app, int id) {
- CharSequence cs = getCachedString(name);
- if (cs != null) {
- return cs;
- }
- try {
- Resources r = getResourcesForApplication(app);
- cs = r.getText(id);
- putCachedString(name, cs);
- } catch (NameNotFoundException e) {
- Log.w("PackageManager", "Failure retrieving resources for"
- + app.packageName);
- } catch (RuntimeException e) {
- // If an exception was thrown, fall through to return null
- Log.w("ApplicationInfo", "Failure retrieving activity name", e);
- }
- return cs;
- }
-
@Override
public CharSequence getText(String packageName, int resid,
ApplicationInfo appInfo) {
@@ -2493,17 +2450,7 @@
@Override
public CharSequence getApplicationLabel(ApplicationInfo info) {
- if (info.nonLocalizedLabel != null) {
- return info.nonLocalizedLabel;
- }
- final int id = info.labelRes;
- if (id != 0) {
- CharSequence cs = getLabel(new ResourceName(info, id), info, id);
- if (cs != null) {
- return cs;
- }
- }
- return info.packageName;
+ return info.loadLabel(this);
}
@Override
diff --git a/core/java/android/app/backup/AbsoluteFileBackupHelper.java b/core/java/android/app/backup/AbsoluteFileBackupHelper.java
index 677224c..a4d99cf 100644
--- a/core/java/android/app/backup/AbsoluteFileBackupHelper.java
+++ b/core/java/android/app/backup/AbsoluteFileBackupHelper.java
@@ -26,7 +26,7 @@
* Like FileBackupHelper, but takes absolute paths for the files instead of
* subpaths of getFilesDir()
*
- * STOPSHIP: document!
+ * @hide
*/
public class AbsoluteFileBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "AbsoluteFileBackupHelper";
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 14bc5dd..9dd7b9f 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -17,12 +17,10 @@
package android.content;
import android.accounts.Account;
-import android.net.TrafficStats;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
-import android.util.EventLog;
import java.util.concurrent.atomic.AtomicInteger;
@@ -113,12 +111,13 @@
public void cancelSync(ISyncContext syncContext) {
// synchronize to make sure that mSyncThread doesn't change between when we
// check it and when we use it
+ final SyncThread syncThread;
synchronized (mSyncThreadLock) {
- if (mSyncThread != null
- && mSyncThread.mSyncContext.getSyncContextBinder()
- == syncContext.asBinder()) {
- onSyncCanceled(mSyncThread);
- }
+ syncThread = mSyncThread;
+ }
+ if (syncThread != null
+ && syncThread.mSyncContext.getSyncContextBinder() == syncContext.asBinder()) {
+ onSyncCanceled();
}
}
@@ -213,9 +212,14 @@
* thread than the sync thread and so you must consider the multi-threaded implications
* of the work that you do in this method.
*
- * @param thread the thread that is running the sync operation to cancel
*/
- public void onSyncCanceled(Thread thread) {
- thread.interrupt();
+ public void onSyncCanceled() {
+ final SyncThread syncThread;
+ synchronized (mSyncThreadLock) {
+ syncThread = mSyncThread;
+ }
+ if (syncThread != null) {
+ syncThread.interrupt();
+ }
}
}
diff --git a/core/java/android/content/ActiveSyncInfo.java b/core/java/android/content/ActiveSyncInfo.java
deleted file mode 100644
index b0c90a1..0000000
--- a/core/java/android/content/ActiveSyncInfo.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2009 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.content;
-
-import android.accounts.Account;
-import android.os.Parcel;
-import android.os.Parcelable.Creator;
-
-/**
- * Information about the sync operation that is currently underway.
- */
-public class ActiveSyncInfo {
- private final int authorityId;
- private final Account account;
- private final String authority;
- private final long startTime;
-
- /**
- * Get the {@link Account} that is currently being synced.
- * @return the account
- */
- public Account getAccount() {
- return new Account(account.name, account.type);
- }
-
- /** @hide */
- public int getAuthorityId() {
- return authorityId;
- }
-
- /**
- * Get the authority of the provider that is currently being synced.
- * @return the authority
- */
- public String getAuthority() {
- return authority;
- }
-
- /**
- * Get the start time of the current sync operation. This is represented in elapsed real time.
- * See {@link android.os.SystemClock#elapsedRealtime()}.
- * @return the start time in milliseconds since boot
- */
- public long getStartTime() {
- return startTime;
- }
-
- /** @hide */
- ActiveSyncInfo(int authorityId, Account account, String authority,
- long startTime) {
- this.authorityId = authorityId;
- this.account = account;
- this.authority = authority;
- this.startTime = startTime;
- }
-
- /** @hide */
- public int describeContents() {
- return 0;
- }
-
- /** @hide */
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(authorityId);
- account.writeToParcel(parcel, 0);
- parcel.writeString(authority);
- parcel.writeLong(startTime);
- }
-
- /** @hide */
- ActiveSyncInfo(Parcel parcel) {
- authorityId = parcel.readInt();
- account = new Account(parcel);
- authority = parcel.readString();
- startTime = parcel.readLong();
- }
-
- /** @hide */
- public static final Creator<ActiveSyncInfo> CREATOR = new Creator<ActiveSyncInfo>() {
- public ActiveSyncInfo createFromParcel(Parcel in) {
- return new ActiveSyncInfo(in);
- }
-
- public ActiveSyncInfo[] newArray(int size) {
- return new ActiveSyncInfo[size];
- }
- };
-}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index d3cc4df..1cb2353 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1179,11 +1179,11 @@
/**
* If a sync is active returns the information about it, otherwise returns false.
- * @return the ActiveSyncInfo for the currently active sync or null if one is not active.
+ * @return the SyncInfo for the currently active sync or null if one is not active.
*/
- public static ActiveSyncInfo getActiveSync() {
+ public static SyncInfo getCurrentSync() {
try {
- return getContentService().getActiveSync();
+ return getContentService().getCurrentSync();
} catch (RemoteException e) {
throw new RuntimeException("the ContentService should always be reachable", e);
}
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 0477d6d..377e383 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -386,14 +386,14 @@
return false;
}
- public ActiveSyncInfo getActiveSync() {
+ public SyncInfo getCurrentSync() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getActiveSync();
+ return syncManager.getSyncStorageEngine().getCurrentSync();
}
} finally {
restoreCallingIdentity(identityToken);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2b0e7e7..ee87290 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -417,7 +417,7 @@
/**
* Returns the absolute path to the directory on the external filesystem
* (that is somewhere on {@link android.os.Environment#getExternalStorageDirectory()
- * Environment.getExternalStorageDirectory()} where the application can
+ * Environment.getExternalStorageDirectory()}) where the application can
* place persistent files it owns. These files are private to the
* applications, and not typically visible to the user as media.
*
@@ -439,7 +439,7 @@
* {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
* private_file}
*
- * <p>If you install a non-null <var>type</var> to this function, the returned
+ * <p>If you supply a non-null <var>type</var> to this function, the returned
* file will be a path to a sub-directory of the given type. Though these files
* are not automatically scanned by the media scanner, you can explicitly
* add them to the media database with
@@ -450,7 +450,7 @@
* Environment.getExternalStoragePublicDirectory()}, which provides
* directories of media shared by all applications. The
* directories returned here are
- * owned by the application, and its contents will be removed when the
+ * owned by the application, and their contents will be removed when the
* application is uninstalled. Unlike
* {@link android.os.Environment#getExternalStoragePublicDirectory
* Environment.getExternalStoragePublicDirectory()}, the directory
@@ -479,6 +479,7 @@
* this method again when it is available.
*
* @see #getFilesDir
+ * @see android.os.Environment#getExternalStoragePublicDirectory
*/
public abstract File getExternalFilesDir(String type);
@@ -1372,6 +1373,7 @@
public static final String SENSOR_SERVICE = "sensor";
/**
+ * @hide
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.storage.StorageManager} for accesssing system storage
* functions.
diff --git a/core/java/android/content/CursorEntityIterator.java b/core/java/android/content/CursorEntityIterator.java
index 54619a3..18437e5 100644
--- a/core/java/android/content/CursorEntityIterator.java
+++ b/core/java/android/content/CursorEntityIterator.java
@@ -53,9 +53,9 @@
* iterator is positioned in front of an element.
*
* @return {@code true} if there are more elements, {@code false} otherwise.
- * @see #next
+ * @see EntityIterator#next()
*/
- public final boolean hasNext() throws RemoteException {
+ public final boolean hasNext() {
if (mIsClosed) {
throw new IllegalStateException("calling hasNext() when the iterator is closed");
}
@@ -70,9 +70,9 @@
* @return the next object.
* @throws java.util.NoSuchElementException
* if there are no more elements.
- * @see #hasNext
+ * @see EntityIterator#hasNext()
*/
- public Entity next() throws RemoteException {
+ public Entity next() {
if (mIsClosed) {
throw new IllegalStateException("calling next() when the iterator is closed");
}
@@ -80,10 +80,18 @@
throw new IllegalStateException("you may only call next() if hasNext() is true");
}
- return getEntityAndIncrementCursor(mCursor);
+ try {
+ return getEntityAndIncrementCursor(mCursor);
+ } catch (RemoteException e) {
+ throw new RuntimeException("caught a remote exception, this process will die soon", e);
+ }
}
- public final void reset() throws RemoteException {
+ public void remove() {
+ throw new UnsupportedOperationException("remove not supported by EntityIterators");
+ }
+
+ public final void reset() {
if (mIsClosed) {
throw new IllegalStateException("calling reset() when the iterator is closed");
}
diff --git a/core/java/android/content/EntityIterator.java b/core/java/android/content/EntityIterator.java
index 3cc1040..55c47ba 100644
--- a/core/java/android/content/EntityIterator.java
+++ b/core/java/android/content/EntityIterator.java
@@ -16,32 +16,20 @@
package android.content;
-import android.os.RemoteException;
+import java.util.Iterator;
-public interface EntityIterator {
+/**
+ * A specialization of {@link Iterator} that allows iterating over a collection of
+ * {@link Entity} objects. In addition to the iteration functionality it also allows
+ * resetting the iterator back to the beginning and provides for an explicit {@link #close()}
+ * method to indicate that the iterator is no longer needed and that its resources
+ * can be released.
+ */
+public interface EntityIterator extends Iterator<Entity> {
/**
- * Returns whether there are more elements to iterate, i.e. whether the
- * iterator is positioned in front of an element.
- *
- * @return {@code true} if there are more elements, {@code false} otherwise.
- * @see #next
- * @since Android 1.0
+ * Reset the iterator back to the beginning.
*/
- public boolean hasNext() throws RemoteException;
-
- /**
- * Returns the next object in the iteration, i.e. returns the element in
- * front of the iterator and advances the iterator by one position.
- *
- * @return the next object.
- * @throws java.util.NoSuchElementException
- * if there are no more elements.
- * @see #hasNext
- * @since Android 1.0
- */
- public Entity next() throws RemoteException;
-
- public void reset() throws RemoteException;
+ public void reset();
/**
* Indicates that this iterator is no longer needed and that any associated resources
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 2d906ed..a6368d5 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -17,7 +17,7 @@
package android.content;
import android.accounts.Account;
-import android.content.ActiveSyncInfo;
+import android.content.SyncInfo;
import android.content.ISyncStatusObserver;
import android.content.SyncAdapterType;
import android.content.SyncStatusInfo;
@@ -104,7 +104,7 @@
*/
boolean isSyncActive(in Account account, String authority);
- ActiveSyncInfo getActiveSync();
+ SyncInfo getCurrentSync();
/**
* Returns the types of the SyncAdapters that are registered with the system.
diff --git a/core/java/android/content/ActiveSyncInfo.aidl b/core/java/android/content/SyncInfo.aidl
similarity index 95%
rename from core/java/android/content/ActiveSyncInfo.aidl
rename to core/java/android/content/SyncInfo.aidl
index 1142206..0737429 100644
--- a/core/java/android/content/ActiveSyncInfo.aidl
+++ b/core/java/android/content/SyncInfo.aidl
@@ -16,4 +16,4 @@
package android.content;
-parcelable ActiveSyncInfo;
+parcelable SyncInfo;
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
new file mode 100644
index 0000000..616b05f
--- /dev/null
+++ b/core/java/android/content/SyncInfo.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2009 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.content;
+
+import android.accounts.Account;
+import android.os.Parcel;
+import android.os.Parcelable.Creator;
+
+/**
+ * Information about the sync operation that is currently underway.
+ */
+public class SyncInfo {
+ /** @hide */
+ public final int authorityId;
+
+ /**
+ * The {@link Account} that is currently being synced.
+ */
+ public final Account account;
+
+ /**
+ * The authority of the provider that is currently being synced.
+ */
+ public final String authority;
+
+ /**
+ * The start time of the current sync operation in milliseconds since boot.
+ * This is represented in elapsed real time.
+ * See {@link android.os.SystemClock#elapsedRealtime()}.
+ */
+ public final long startTime;
+
+ /** @hide */
+ SyncInfo(int authorityId, Account account, String authority,
+ long startTime) {
+ this.authorityId = authorityId;
+ this.account = account;
+ this.authority = authority;
+ this.startTime = startTime;
+ }
+
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(authorityId);
+ account.writeToParcel(parcel, 0);
+ parcel.writeString(authority);
+ parcel.writeLong(startTime);
+ }
+
+ /** @hide */
+ SyncInfo(Parcel parcel) {
+ authorityId = parcel.readInt();
+ account = new Account(parcel);
+ authority = parcel.readString();
+ startTime = parcel.readLong();
+ }
+
+ /** @hide */
+ public static final Creator<SyncInfo> CREATOR = new Creator<SyncInfo>() {
+ public SyncInfo createFromParcel(Parcel in) {
+ return new SyncInfo(in);
+ }
+
+ public SyncInfo[] newArray(int size) {
+ return new SyncInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 5c8ee18..455815f 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -398,10 +398,6 @@
return minValue + random.nextInt((int)spread);
}
- public ActiveSyncContext getActiveSyncContext() {
- return mActiveSyncContext;
- }
-
public SyncStorageEngine getSyncStorageEngine() {
return mSyncStorageEngine;
}
@@ -412,11 +408,6 @@
}
}
- public Account getSyncingAccount() {
- ActiveSyncContext activeSyncContext = mActiveSyncContext;
- return (activeSyncContext != null) ? activeSyncContext.mSyncOperation.account : null;
- }
-
private void initializeSyncAdapter(Account account, String authority) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "initializeSyncAdapter: " + account + ", authority " + authority);
@@ -425,7 +416,8 @@
RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
mSyncAdapters.getServiceInfo(syncAdapterType);
if (syncAdapterInfo == null) {
- Log.w(TAG, "can't find a sync adapter for " + syncAdapterType);
+ Log.w(TAG, "can't find a sync adapter for " + syncAdapterType + ", removing");
+ mSyncStorageEngine.removeAuthority(account, authority);
return;
}
@@ -466,6 +458,8 @@
}
} catch (RemoteException e) {
// doesn't matter, we will retry again later
+ Log.d(TAG, "error while initializing: " + mAccount + ", authority " + mAuthority,
+ e);
} finally {
// give the sync adapter time to initialize before unbinding from it
// TODO: change this API to not rely on this timing, http://b/2500805
@@ -602,16 +596,12 @@
continue;
}
- // initialize the SyncAdapter if the isSyncable state is unknown
- if (isSyncable < 0) {
- initializeSyncAdapter(account, authority);
- continue;
- }
-
- final boolean syncAutomatically = masterSyncAutomatically
- && mSyncStorageEngine.getSyncAutomatically(account, authority);
+ // always allow if the isSyncable state is unknown
boolean syncAllowed =
- ignoreSettings || (backgroundDataUsageAllowed && syncAutomatically);
+ (isSyncable < 0)
+ || ignoreSettings
+ || (backgroundDataUsageAllowed && masterSyncAutomatically
+ && mSyncStorageEngine.getSyncAutomatically(account, authority));
if (!syncAllowed) {
if (isLoggable) {
Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
@@ -1026,11 +1016,11 @@
pw.println(sb.toString());
}
- ActiveSyncInfo active = mSyncStorageEngine.getActiveSync();
+ SyncInfo active = mSyncStorageEngine.getCurrentSync();
if (active != null) {
SyncStorageEngine.AuthorityInfo authority
- = mSyncStorageEngine.getAuthority(active.getAuthorityId());
- final long durationInSeconds = (now - active.getStartTime()) / 1000;
+ = mSyncStorageEngine.getAuthority(active.authorityId);
+ final long durationInSeconds = (now - active.startTime) / 1000;
pw.print("Active sync: ");
pw.print(authority != null ? authority.account : "<no account>");
pw.print(" ");
@@ -1061,7 +1051,7 @@
pw.println(op.expedited);
if (op.extras != null && op.extras.size() > 0) {
sb.setLength(0);
- SyncOperation.extrasToStringBuilder(op.extras, sb);
+ SyncOperation.extrasToStringBuilder(op.extras, sb, false /* asKey */);
pw.print(" extras: "); pw.println(sb.toString());
}
}
@@ -1376,8 +1366,14 @@
}
public void handleMessage(Message msg) {
+ Long earliestFuturePollTime = null;
try {
waitUntilReadyToRun();
+ // Always do this first so that we be sure that any periodic syncs that
+ // are ready to run have been converted into pending syncs. This allows the
+ // logic that considers the next steps to take based on the set of pending syncs
+ // to also take into account the periodic syncs.
+ earliestFuturePollTime = scheduleReadyPeriodicSyncs();
switch (msg.what) {
case SyncHandler.MESSAGE_SYNC_FINISHED:
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1486,48 +1482,90 @@
}
manageSyncNotification();
manageErrorNotification();
- manageSyncAlarm();
+ manageSyncAlarm(earliestFuturePollTime);
mSyncTimeTracker.update();
}
}
- private boolean isSyncAllowed(Account account, String authority, boolean ignoreSettings,
- boolean backgroundDataUsageAllowed) {
- Account[] accounts = mAccounts;
+ /**
+ * Turn any periodic sync operations that are ready to run into pending sync operations.
+ * @return the desired start time of the earliest future periodic sync operation,
+ * in milliseconds since boot
+ */
+ private Long scheduleReadyPeriodicSyncs() {
+ final boolean backgroundDataUsageAllowed =
+ getConnectivityManager().getBackgroundDataSetting();
+ Long earliestFuturePollTime = null;
+ if (!backgroundDataUsageAllowed || !mSyncStorageEngine.getMasterSyncAutomatically()) {
+ return earliestFuturePollTime;
+ }
+ final long nowAbsolute = System.currentTimeMillis();
+ ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
+ for (SyncStorageEngine.AuthorityInfo info : infos) {
+ // skip the sync if the account of this operation no longer exists
+ if (!ArrayUtils.contains(mAccounts, info.account)) {
+ continue;
+ }
- // skip the sync if the account of this operation no longer exists
- if (!ArrayUtils.contains(accounts, account)) {
- return false;
+ if (!mSyncStorageEngine.getSyncAutomatically(info.account, info.authority)) {
+ continue;
+ }
+
+ if (mSyncStorageEngine.getIsSyncable(info.account, info.authority) == 0) {
+ continue;
+ }
+
+ SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(info);
+ for (int i = 0, N = info.periodicSyncs.size(); i < N; i++) {
+ final Bundle extras = info.periodicSyncs.get(i).first;
+ final Long periodInSeconds = info.periodicSyncs.get(i).second;
+ // find when this periodic sync was last scheduled to run
+ final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
+ // compute when this periodic sync should next run
+ long nextPollTimeAbsolute = lastPollTimeAbsolute + periodInSeconds * 1000;
+ // if it is ready to run then schedule it and mark it as having been scheduled
+ if (nextPollTimeAbsolute <= nowAbsolute) {
+ scheduleSyncOperation(
+ new SyncOperation(info.account, SyncStorageEngine.SOURCE_PERIODIC,
+ info.authority, extras, 0 /* delay */));
+ status.setPeriodicSyncTime(i, nowAbsolute);
+ } else {
+ // it isn't ready to run, remember this time if it is earlier than
+ // earliestFuturePollTime
+ if (earliestFuturePollTime == null
+ || nextPollTimeAbsolute < earliestFuturePollTime) {
+ earliestFuturePollTime = nextPollTimeAbsolute;
+ }
+ }
+ }
}
- // skip the sync if it isn't manual and auto sync is disabled
- final boolean syncAutomatically =
- mSyncStorageEngine.getSyncAutomatically(account, authority)
- && mSyncStorageEngine.getMasterSyncAutomatically();
- if (!(ignoreSettings || (backgroundDataUsageAllowed && syncAutomatically))) {
- return false;
+ if (earliestFuturePollTime == null) {
+ return null;
}
- if (mSyncStorageEngine.getIsSyncable(account, authority) <= 0) {
- // if not syncable or if the syncable is unknown (< 0), don't allow
- return false;
- }
-
- return true;
+ // convert absolute time to elapsed time
+ return SystemClock.elapsedRealtime()
+ + ((earliestFuturePollTime < nowAbsolute)
+ ? 0
+ : (earliestFuturePollTime - nowAbsolute));
}
private void runStateSyncing() {
// if the sync timeout has been reached then cancel it
-
ActiveSyncContext activeSyncContext = mActiveSyncContext;
final long now = SystemClock.elapsedRealtime();
if (now > activeSyncContext.mTimeoutStartTime + MAX_TIME_PER_SYNC) {
- SyncOperation nextSyncOperation;
+ Pair<SyncOperation, Long> nextOpAndRunTime;
synchronized (mSyncQueue) {
- nextSyncOperation = getNextReadyToRunSyncOperation(now);
+ nextOpAndRunTime = mSyncQueue.nextOperation();
}
- if (nextSyncOperation != null) {
+ SyncOperation curOp = activeSyncContext.mSyncOperation;
+ if (nextOpAndRunTime != null
+ && nextOpAndRunTime.second <= now
+ && !nextOpAndRunTime.first.account.equals(curOp.account)
+ && !nextOpAndRunTime.first.authority.equals(curOp.authority)) {
Log.d(TAG, "canceling and rescheduling sync because it ran too long: "
+ activeSyncContext.mSyncOperation);
scheduleSyncOperation(new SyncOperation(activeSyncContext.mSyncOperation));
@@ -1574,27 +1612,48 @@
// found that is runnable (not disabled, etc). If that one is ready to run then
// start it, otherwise just get out.
SyncOperation op;
+ int syncableState;
final boolean backgroundDataUsageAllowed =
getConnectivityManager().getBackgroundDataSetting();
+ final boolean masterSyncAutomatically = mSyncStorageEngine.getMasterSyncAutomatically();
+
synchronized (mSyncQueue) {
final long now = SystemClock.elapsedRealtime();
while (true) {
- op = getNextReadyToRunSyncOperation(now);
- if (op == null) {
+ Pair<SyncOperation, Long> nextOpAndRunTime = mSyncQueue.nextOperation();
+ if (nextOpAndRunTime == null || nextOpAndRunTime.second > now) {
if (isLoggable) {
- Log.v(TAG, "runStateIdle: no more sync operations, returning");
+ Log.v(TAG, "runStateIdle: no more ready sync operations, returning");
}
return;
}
+ op = nextOpAndRunTime.first;
- // we are either going to run this sync or drop it so go ahead and remove it
- // from the queue now
+ // we are either going to run this sync or drop it so go ahead and
+ // remove it from the queue now
mSyncQueue.remove(op);
- final boolean ignoreSettings = op.extras
- .getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
- if (!isSyncAllowed(op.account, op.authority, ignoreSettings,
- backgroundDataUsageAllowed)) {
+ // drop the sync if the account of this operation no longer exists
+ if (!ArrayUtils.contains(mAccounts, op.account)) {
+ continue;
+ }
+
+
+ // drop this sync request if it isn't syncable, intializing the sync adapter
+ // if the syncable state is set to "unknown"
+ syncableState = mSyncStorageEngine.getIsSyncable(op.account, op.authority);
+ if (syncableState == 0) {
+ continue;
+ }
+
+ // skip the sync if it isn't manual and auto sync or
+ // background data usage is disabled
+ if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
+ && (syncableState > 0)
+ && (!masterSyncAutomatically
+ || !backgroundDataUsageAllowed
+ || !mSyncStorageEngine.getSyncAutomatically(
+ op.account, op.authority))) {
continue;
}
@@ -1608,6 +1667,19 @@
}
}
+ // convert the op into an initialization sync if the syncable state is "unknown" and
+ // op isn't already an initialization sync. If it is marked syncable then convert
+ // this into a regular sync
+ final boolean initializeIsSet =
+ op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
+ if (syncableState < 0 && !initializeIsSet) {
+ op.extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+ op = new SyncOperation(op);
+ } else if (syncableState > 0 && initializeIsSet) {
+ op.extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
+ op = new SyncOperation(op);
+ }
+
// connect to the sync adapter
SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
@@ -1643,74 +1715,6 @@
// MESSAGE_SERVICE_CONNECTED or MESSAGE_SERVICE_DISCONNECTED message
}
- private SyncOperation getNextPeriodicSyncOperation() {
- final boolean backgroundDataUsageAllowed =
- getConnectivityManager().getBackgroundDataSetting();
- SyncStorageEngine.AuthorityInfo best = null;
- long bestPollTimeAbsolute = Long.MAX_VALUE;
- Bundle bestExtras = null;
- ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
- for (SyncStorageEngine.AuthorityInfo info : infos) {
- if (!isSyncAllowed(info.account, info.authority, false /* ignoreSettings */,
- backgroundDataUsageAllowed)) {
- continue;
- }
- SyncStatusInfo status = mSyncStorageEngine.getStatusByAccountAndAuthority(
- info.account, info.authority);
- int i = 0;
- for (Pair<Bundle, Long> periodicSync : info.periodicSyncs) {
- long lastPollTimeAbsolute = status != null ? status.getPeriodicSyncTime(i) : 0;
- final Bundle extras = periodicSync.first;
- final Long periodInSeconds = periodicSync.second;
- long nextPollTimeAbsolute = lastPollTimeAbsolute + periodInSeconds * 1000;
- if (nextPollTimeAbsolute < bestPollTimeAbsolute) {
- best = info;
- bestPollTimeAbsolute = nextPollTimeAbsolute;
- bestExtras = extras;
- }
- i++;
- }
- }
-
- if (best == null) {
- return null;
- }
-
- final long nowAbsolute = System.currentTimeMillis();
- final SyncOperation syncOperation = new SyncOperation(best.account,
- SyncStorageEngine.SOURCE_PERIODIC,
- best.authority, bestExtras, 0 /* delay */);
- syncOperation.earliestRunTime = SystemClock.elapsedRealtime()
- + (bestPollTimeAbsolute - nowAbsolute);
- if (syncOperation.earliestRunTime < 0) {
- syncOperation.earliestRunTime = 0;
- }
- return syncOperation;
- }
-
- public Pair<SyncOperation, Long> bestSyncOperationCandidate() {
- Pair<SyncOperation, Long> nextOpAndRunTime = mSyncQueue.nextOperation();
- SyncOperation nextOp = nextOpAndRunTime != null ? nextOpAndRunTime.first : null;
- Long nextRunTime = nextOpAndRunTime != null ? nextOpAndRunTime.second : null;
- SyncOperation pollOp = getNextPeriodicSyncOperation();
- if (nextOp != null
- && (pollOp == null || nextOp.expedited
- || nextRunTime <= pollOp.earliestRunTime)) {
- return nextOpAndRunTime;
- } else if (pollOp != null) {
- return Pair.create(pollOp, pollOp.earliestRunTime);
- } else {
- return null;
- }
- }
-
- private SyncOperation getNextReadyToRunSyncOperation(long now) {
- Pair<SyncOperation, Long> nextOpAndRunTime = bestSyncOperationCandidate();
- return nextOpAndRunTime != null && nextOpAndRunTime.second <= now
- ? nextOpAndRunTime.first
- : null;
- }
-
private void runBoundToSyncAdapter(ISyncAdapter syncAdapter) {
mActiveSyncContext.mSyncAdapter = syncAdapter;
final SyncOperation syncOperation = mActiveSyncContext.mSyncOperation;
@@ -1757,6 +1761,15 @@
downstreamActivity = 0;
upstreamActivity = 0;
clearBackoffSetting(syncOperation);
+ // if this was an initialization sync and the sync adapter is now
+ // marked syncable then reschedule the sync. The next time it runs it
+ // will be made into a regular sync.
+ if (syncOperation.extras.getBoolean(
+ ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
+ && mSyncStorageEngine.getIsSyncable(
+ syncOperation.account, syncOperation.authority) > 0) {
+ scheduleSyncOperation(new SyncOperation(syncOperation));
+ }
} else {
Log.d(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
// the operation failed so increase the backoff time
@@ -1919,7 +1932,7 @@
}
}
- private void manageSyncAlarm() {
+ private void manageSyncAlarm(Long earliestFuturePollElapsedTime) {
// in each of these cases the sync loop will be kicked, which will cause this
// method to be called again
if (!mDataConnectionIsConnected) return;
@@ -1935,8 +1948,16 @@
ActiveSyncContext activeSyncContext = mActiveSyncContext;
if (activeSyncContext == null) {
synchronized (mSyncQueue) {
- Pair<SyncOperation, Long> candidate = bestSyncOperationCandidate();
- alarmTime = candidate != null ? candidate.second : null;
+ final Pair<SyncOperation, Long> candidate = mSyncQueue.nextOperation();
+ if (earliestFuturePollElapsedTime == null && candidate == null) {
+ alarmTime = null;
+ } else if (earliestFuturePollElapsedTime == null) {
+ alarmTime = candidate.second;
+ } else if (candidate == null) {
+ alarmTime = earliestFuturePollElapsedTime;
+ } else {
+ alarmTime = Math.min(earliestFuturePollElapsedTime, candidate.second);
+ }
}
} else {
final long notificationTime =
@@ -2077,7 +2098,7 @@
SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
syncOperation.account.name.hashCode());
- mSyncStorageEngine.stopSyncEvent(rowId, syncOperation.extras, elapsedTime,
+ mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
resultMessage, downstreamActivity, upstreamActivity);
}
}
diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java
index ec601de..a7d036f 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/core/java/android/content/SyncOperation.java
@@ -80,7 +80,7 @@
sb.append("authority: ").append(authority);
sb.append(" account: ").append(account);
sb.append(" extras: ");
- extrasToStringBuilder(extras, sb);
+ extrasToStringBuilder(extras, sb, false /* asKey */);
sb.append(" syncSource: ").append(syncSource);
sb.append(" when: ").append(earliestRunTime);
sb.append(" expedited: ").append(expedited);
@@ -92,13 +92,19 @@
sb.append("authority: ").append(authority);
sb.append(" account: ").append(account);
sb.append(" extras: ");
- extrasToStringBuilder(extras, sb);
+ extrasToStringBuilder(extras, sb, true /* asKey */);
return sb.toString();
}
- public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
+ public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb, boolean asKey) {
sb.append("[");
for (String key : bundle.keySet()) {
+ // if we are writing this as a key don't consider whether this
+ // is an initialization sync or not when computing the key since
+ // we set this flag appropriately when dispatching the sync request.
+ if (asKey && ContentResolver.SYNC_EXTRAS_INITIALIZE.equals(key)) {
+ continue;
+ }
sb.append(key).append("=").append(bundle.get(key)).append(" ");
}
sb.append("]");
diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java
index 432277f..28baa0d 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/core/java/android/content/SyncQueue.java
@@ -16,6 +16,7 @@
package android.content;
+import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import android.util.Pair;
@@ -120,14 +121,16 @@
/**
* Find the operation that should run next. Operations are sorted by their earliestRunTime,
- * prioritizing expedited operations. The earliestRunTime is adjusted by the sync adapter's
- * backoff and delayUntil times, if any.
+ * prioritizing first those with a syncable state of "unknown" that aren't retries then
+ * expedited operations.
+ * The earliestRunTime is adjusted by the sync adapter's backoff and delayUntil times, if any.
* @return the operation that should run next and when it should run. The time may be in
* the future. It is expressed in milliseconds since boot.
*/
public Pair<SyncOperation, Long> nextOperation() {
SyncOperation best = null;
long bestRunTime = 0;
+ boolean bestSyncableIsUnknownAndNotARetry = false;
for (SyncOperation op : mOperationsMap.values()) {
long opRunTime = op.earliestRunTime;
if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
@@ -137,12 +140,23 @@
Math.max(opRunTime, delayUntil),
backoff != null ? backoff.first : 0);
}
- // if the expedited state of both ops are the same then compare their runtime.
- // Otherwise the candidate is only better than the current best if the candidate
- // is expedited.
+ // we know a sync is a retry if the intialization flag is set, since that will only
+ // be set by the sync dispatching code, thus if it is set it must have already been
+ // dispatched
+ final boolean syncableIsUnknownAndNotARetry =
+ !op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
+ && mSyncStorageEngine.getIsSyncable(op.account, op.authority) < 0;
+ // if the unsyncable state differs, make the current the best if it is unsyncable
+ // else, if the expedited state differs, make the current the best if it is expedited
+ // else, make the current the best if it is earlier than the best
if (best == null
- || (best.expedited == op.expedited ? opRunTime < bestRunTime : op.expedited)) {
+ || ((bestSyncableIsUnknownAndNotARetry == syncableIsUnknownAndNotARetry)
+ ? (best.expedited == op.expedited
+ ? opRunTime < bestRunTime
+ : op.expedited)
+ : syncableIsUnknownAndNotARetry)) {
best = op;
+ bestSyncableIsUnknownAndNotARetry = syncableIsUnknownAndNotARetry;
bestRunTime = opRunTime;
}
}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 6a959ae..984c070 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -59,7 +59,6 @@
*/
public class SyncStorageEngine extends Handler {
private static final String TAG = "SyncManager";
- private static final boolean DEBUG = false;
private static final boolean DEBUG_FILE = false;
private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
@@ -230,7 +229,7 @@
private final ArrayList<PendingOperation> mPendingOperations =
new ArrayList<PendingOperation>();
- private ActiveSyncInfo mActiveSync;
+ private SyncInfo mCurrentSync;
private final SparseArray<SyncStatusInfo> mSyncStatus =
new SparseArray<SyncStatusInfo>();
@@ -241,6 +240,8 @@
private final RemoteCallbackList<ISyncStatusObserver> mChangeListeners
= new RemoteCallbackList<ISyncStatusObserver>();
+ private int mNextAuthorityId = 0;
+
// We keep 4 weeks of stats.
private final DayStats[] mDayStats = new DayStats[7*4];
private final Calendar mCal;
@@ -301,7 +302,11 @@
readStatusLocked();
readPendingOperationsLocked();
readStatisticsLocked();
- readLegacyAccountInfoLocked();
+ readAndDeleteLegacyAccountInfoLocked();
+ writeAccountInfoLocked();
+ writeStatusLocked();
+ writePendingOperationsLocked();
+ writeStatisticsLocked();
}
public static SyncStorageEngine newTestInstance(Context context) {
@@ -365,7 +370,9 @@
mChangeListeners.finishBroadcast();
}
- if (DEBUG) Log.v(TAG, "reportChange " + which + " to: " + reports);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "reportChange " + which + " to: " + reports);
+ }
if (reports != null) {
int i = reports.size();
@@ -402,15 +409,19 @@
}
public void setSyncAutomatically(Account account, String providerName, boolean sync) {
- boolean wasEnabled;
+ Log.d(TAG, "setSyncAutomatically: " + account + ", provider " + providerName
+ + " -> " + sync);
synchronized (mAuthorities) {
AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
- wasEnabled = authority.enabled;
+ if (authority.enabled == sync) {
+ Log.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
+ return;
+ }
authority.enabled = sync;
writeAccountInfoLocked();
}
- if (!wasEnabled && sync) {
+ if (sync) {
ContentResolver.requestSync(account, providerName, new Bundle());
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
@@ -440,7 +451,6 @@
}
public void setIsSyncable(Account account, String providerName, int syncable) {
- int oldState;
if (syncable > 1) {
syncable = 1;
} else if (syncable < -1) {
@@ -449,12 +459,15 @@
Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName + " -> " + syncable);
synchronized (mAuthorities) {
AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
- oldState = authority.syncable;
+ if (authority.syncable == syncable) {
+ Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
+ return;
+ }
authority.syncable = syncable;
writeAccountInfoLocked();
}
- if (oldState <= 0 && syncable > 0) {
+ if (syncable > 0) {
ContentResolver.requestSync(account, providerName, new Bundle());
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
@@ -550,49 +563,60 @@
+ " -> period " + period + ", extras " + extras);
}
synchronized (mAuthorities) {
- AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
- if (add) {
- boolean alreadyPresent = false;
- for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
- Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
- final Bundle existingExtras = syncInfo.first;
- if (equals(existingExtras, extras)) {
- if (syncInfo.second == period) {
- return;
+ try {
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(account, providerName, -1, false);
+ if (add) {
+ // add this periodic sync if one with the same extras doesn't already
+ // exist in the periodicSyncs array
+ boolean alreadyPresent = false;
+ for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
+ Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
+ final Bundle existingExtras = syncInfo.first;
+ if (equals(existingExtras, extras)) {
+ if (syncInfo.second == period) {
+ return;
+ }
+ authority.periodicSyncs.set(i, Pair.create(extras, period));
+ alreadyPresent = true;
+ break;
}
- authority.periodicSyncs.set(i, Pair.create(extras, period));
- alreadyPresent = true;
- break;
+ }
+ // if we added an entry to the periodicSyncs array also add an entry to
+ // the periodic syncs status to correspond to it
+ if (!alreadyPresent) {
+ authority.periodicSyncs.add(Pair.create(extras, period));
+ SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
+ status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
+ }
+ } else {
+ // remove any periodic syncs that match the authority and extras
+ SyncStatusInfo status = mSyncStatus.get(authority.ident);
+ boolean changed = false;
+ Iterator<Pair<Bundle, Long>> iterator = authority.periodicSyncs.iterator();
+ int i = 0;
+ while (iterator.hasNext()) {
+ Pair<Bundle, Long> syncInfo = iterator.next();
+ if (equals(syncInfo.first, extras)) {
+ iterator.remove();
+ changed = true;
+ // if we removed an entry from the periodicSyncs array also
+ // remove the corresponding entry from the status
+ if (status != null) {
+ status.removePeriodicSyncTime(i);
+ }
+ } else {
+ i++;
+ }
+ }
+ if (!changed) {
+ return;
}
}
- if (!alreadyPresent) {
- authority.periodicSyncs.add(Pair.create(extras, period));
- SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
- status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
- }
- } else {
- SyncStatusInfo status = mSyncStatus.get(authority.ident);
- boolean changed = false;
- Iterator<Pair<Bundle, Long>> iterator = authority.periodicSyncs.iterator();
- int i = 0;
- while (iterator.hasNext()) {
- Pair<Bundle, Long> syncInfo = iterator.next();
- if (equals(syncInfo.first, extras)) {
- iterator.remove();
- changed = true;
- if (status != null) {
- status.removePeriodicSyncTime(i);
- }
- } else {
- i++;
- }
- }
- if (!changed) {
- return;
- }
+ } finally {
+ writeAccountInfoLocked();
+ writeStatusLocked();
}
- writeAccountInfoLocked();
- writeStatusLocked();
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
@@ -622,13 +646,14 @@
}
public void setMasterSyncAutomatically(boolean flag) {
- boolean old;
synchronized (mAuthorities) {
- old = mMasterSyncAutomatically;
+ if (mMasterSyncAutomatically == flag) {
+ return;
+ }
mMasterSyncAutomatically = flag;
writeAccountInfoLocked();
}
- if (!old && flag) {
+ if (flag) {
ContentResolver.requestSync(null, null, new Bundle());
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
@@ -651,7 +676,7 @@
public void removeAuthority(Account account, String authority) {
synchronized (mAuthorities) {
- removeAuthorityLocked(account, authority);
+ removeAuthorityLocked(account, authority, true /* doWrite */);
}
}
@@ -678,8 +703,8 @@
}
}
- if (mActiveSync != null) {
- AuthorityInfo ainfo = getAuthority(mActiveSync.getAuthorityId());
+ if (mCurrentSync != null) {
+ AuthorityInfo ainfo = getAuthority(mCurrentSync.authorityId);
if (ainfo != null && ainfo.account.equals(account)
&& ainfo.authority.equals(authority)) {
return true;
@@ -692,10 +717,12 @@
public PendingOperation insertIntoPending(PendingOperation op) {
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "insertIntoPending: account=" + op.account
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "insertIntoPending: account=" + op.account
+ " auth=" + op.authority
+ " src=" + op.syncSource
+ " extras=" + op.extras);
+ }
AuthorityInfo authority = getOrCreateAuthorityLocked(op.account,
op.authority,
@@ -721,10 +748,12 @@
public boolean deleteFromPending(PendingOperation op) {
boolean res = false;
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "deleteFromPending: account=" + op.account
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "deleteFromPending: account=" + op.account
+ " auth=" + op.authority
+ " src=" + op.syncSource
+ " extras=" + op.extras);
+ }
if (mPendingOperations.remove(op)) {
if (mPendingOperations.size() == 0
|| mNumPendingFinished >= PENDING_FINISH_TO_WRITE) {
@@ -737,7 +766,7 @@
AuthorityInfo authority = getAuthorityLocked(op.account, op.authority,
"deleteFromPending");
if (authority != null) {
- if (DEBUG) Log.v(TAG, "removing - " + authority);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "removing - " + authority);
final int N = mPendingOperations.size();
boolean morePending = false;
for (int i=0; i<N; i++) {
@@ -750,7 +779,7 @@
}
if (!morePending) {
- if (DEBUG) Log.v(TAG, "no more pending!");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "no more pending!");
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = false;
}
@@ -767,7 +796,9 @@
public int clearPending() {
int num;
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "clearPending");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "clearPending");
+ }
num = mPendingOperations.size();
mPendingOperations.clear();
final int N = mSyncStatus.size();
@@ -806,14 +837,16 @@
*/
public void doDatabaseCleanup(Account[] accounts) {
synchronized (mAuthorities) {
- if (DEBUG) Log.w(TAG, "Updating for new accounts...");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.w(TAG, "Updating for new accounts...");
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
Iterator<AccountInfo> accIt = mAccounts.values().iterator();
while (accIt.hasNext()) {
AccountInfo acc = accIt.next();
if (!ArrayUtils.contains(accounts, acc.account)) {
// This account no longer exists...
- if (DEBUG) Log.w(TAG, "Account removed: " + acc.account);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.w(TAG, "Account removed: " + acc.account);
+ }
for (AuthorityInfo auth : acc.authorities.values()) {
removing.put(auth.ident, auth);
}
@@ -859,12 +892,14 @@
public void setActiveSync(SyncManager.ActiveSyncContext activeSyncContext) {
synchronized (mAuthorities) {
if (activeSyncContext != null) {
- if (DEBUG) Log.v(TAG, "setActiveSync: account="
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setActiveSync: account="
+ activeSyncContext.mSyncOperation.account
+ " auth=" + activeSyncContext.mSyncOperation.authority
+ " src=" + activeSyncContext.mSyncOperation.syncSource
+ " extras=" + activeSyncContext.mSyncOperation.extras);
- if (mActiveSync != null) {
+ }
+ if (mCurrentSync != null) {
Log.w(TAG, "setActiveSync called with existing active sync!");
}
AuthorityInfo authority = getAuthorityLocked(
@@ -874,12 +909,12 @@
if (authority == null) {
return;
}
- mActiveSync = new ActiveSyncInfo(authority.ident,
+ mCurrentSync = new SyncInfo(authority.ident,
authority.account, authority.authority,
activeSyncContext.mStartTime);
} else {
- if (DEBUG) Log.v(TAG, "setActiveSync: null");
- mActiveSync = null;
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "setActiveSync: null");
+ mCurrentSync = null;
}
}
@@ -900,8 +935,10 @@
long now, int source) {
long id;
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "insertStartSyncEvent: account=" + accountName
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "insertStartSyncEvent: account=" + accountName
+ " auth=" + authorityName + " source=" + source);
+ }
AuthorityInfo authority = getAuthorityLocked(accountName, authorityName,
"insertStartSyncEvent");
if (authority == null) {
@@ -919,7 +956,7 @@
mSyncHistory.remove(mSyncHistory.size()-1);
}
id = item.historyId;
- if (DEBUG) Log.v(TAG, "returning historyId " + id);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "returning historyId " + id);
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
@@ -944,10 +981,12 @@
return true;
}
- public void stopSyncEvent(long historyId, Bundle extras, long elapsedTime, String resultMessage,
+ public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
long downstreamActivity, long upstreamActivity) {
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
+ }
SyncHistoryItem item = null;
int i = mSyncHistory.size();
while (i > 0) {
@@ -989,14 +1028,6 @@
break;
case SOURCE_PERIODIC:
status.numSourcePeriodic++;
- AuthorityInfo authority = mAuthorities.get(item.authorityId);
- for (int periodicSyncIndex = 0;
- periodicSyncIndex < authority.periodicSyncs.size();
- periodicSyncIndex++) {
- if (equals(extras, authority.periodicSyncs.get(periodicSyncIndex).first)) {
- status.setPeriodicSyncTime(periodicSyncIndex, item.eventTime);
- }
- }
break;
}
@@ -1063,9 +1094,9 @@
* active sync. Note that the returned object is the real, live active
* sync object, so be careful what you do with it.
*/
- public ActiveSyncInfo getActiveSync() {
+ public SyncInfo getCurrentSync() {
synchronized (mAuthorities) {
- return mActiveSync;
+ return mCurrentSync;
}
}
@@ -1261,18 +1292,14 @@
AuthorityInfo authority = account.authorities.get(authorityName);
if (authority == null) {
if (ident < 0) {
- // Look for a new identifier for this authority.
- final int N = mAuthorities.size();
- ident = 0;
- for (int i=0; i<N; i++) {
- if (mAuthorities.valueAt(i).ident > ident) {
- break;
- }
- ident++;
- }
+ ident = mNextAuthorityId;
+ mNextAuthorityId++;
+ doWrite = true;
}
- if (DEBUG) Log.v(TAG, "created a new AuthorityInfo for " + accountName
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "created a new AuthorityInfo for " + accountName
+ ", provider " + authorityName);
+ }
authority = new AuthorityInfo(accountName, authorityName, ident);
account.authorities.put(authorityName, authority);
mAuthorities.put(ident, authority);
@@ -1284,13 +1311,15 @@
return authority;
}
- private void removeAuthorityLocked(Account account, String authorityName) {
+ private void removeAuthorityLocked(Account account, String authorityName, boolean doWrite) {
AccountInfo accountInfo = mAccounts.get(account);
if (accountInfo != null) {
final AuthorityInfo authorityInfo = accountInfo.authorities.remove(authorityName);
if (authorityInfo != null) {
mAuthorities.remove(authorityInfo.ident);
- writeAccountInfoLocked();
+ if (doWrite) {
+ writeAccountInfoLocked();
+ }
}
}
}
@@ -1340,7 +1369,11 @@
readStatusLocked();
readPendingOperationsLocked();
readStatisticsLocked();
- readLegacyAccountInfoLocked();
+ readAndDeleteLegacyAccountInfoLocked();
+ writeAccountInfoLocked();
+ writeStatusLocked();
+ writePendingOperationsLocked();
+ writeStatisticsLocked();
}
}
@@ -1348,7 +1381,7 @@
* Read all account information back in to the initial engine state.
*/
private void readAccountInfoLocked() {
- boolean writeNeeded = false;
+ int highestAuthorityId = -1;
FileInputStream fis = null;
try {
fis = mAccountInfoFile.openRead();
@@ -1370,11 +1403,14 @@
} catch (NumberFormatException e) {
version = 0;
}
- if (version < ACCOUNTS_VERSION) {
- writeNeeded = true;
+ String nextIdString = parser.getAttributeValue(null, "nextAuthorityId");
+ try {
+ int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
+ mNextAuthorityId = Math.max(mNextAuthorityId, id);
+ } catch (NumberFormatException e) {
+ // don't care
}
- mMasterSyncAutomatically = listen == null
- || Boolean.parseBoolean(listen);
+ mMasterSyncAutomatically = listen == null || Boolean.parseBoolean(listen);
eventType = parser.next();
AuthorityInfo authority = null;
Pair<Bundle, Long> periodicSync = null;
@@ -1385,6 +1421,9 @@
if ("authority".equals(tagName)) {
authority = parseAuthority(parser, version);
periodicSync = null;
+ if (authority.ident > highestAuthorityId) {
+ highestAuthorityId = authority.ident;
+ }
}
} else if (parser.getDepth() == 3) {
if ("periodicSync".equals(tagName) && authority != null) {
@@ -1407,6 +1446,7 @@
else Log.w(TAG, "Error reading accounts", e);
return;
} finally {
+ mNextAuthorityId = Math.max(highestAuthorityId + 1, mNextAuthorityId);
if (fis != null) {
try {
fis.close();
@@ -1415,13 +1455,7 @@
}
}
- if (maybeMigrateSettingsForRenamedAuthorities()) {
- writeNeeded = true;
- }
-
- if (writeNeeded) {
- writeAccountInfoLocked();
- }
+ maybeMigrateSettingsForRenamedAuthorities();
}
/**
@@ -1463,7 +1497,8 @@
}
for (AuthorityInfo authorityInfo : authoritiesToRemove) {
- removeAuthorityLocked(authorityInfo.account, authorityInfo.authority);
+ removeAuthorityLocked(authorityInfo.account, authorityInfo.authority,
+ false /* doWrite */);
writeNeeded = true;
}
@@ -1593,6 +1628,7 @@
out.startTag(null, "accounts");
out.attribute(null, "version", Integer.toString(ACCOUNTS_VERSION));
+ out.attribute(null, "nextAuthorityId", Integer.toString(mNextAuthorityId));
if (!mMasterSyncAutomatically) {
out.attribute(null, "listen-for-tickles", "false");
}
@@ -1675,7 +1711,7 @@
* erase it. Note that we don't deal with pending operations, active
* sync, or history.
*/
- private void readLegacyAccountInfoLocked() {
+ private void readAndDeleteLegacyAccountInfoLocked() {
// Look for old database to initialize from.
File file = mContext.getDatabasePath("syncmanager.db");
if (!file.exists()) {
@@ -1792,8 +1828,6 @@
db.close();
- writeAccountInfoLocked();
- writeStatusLocked();
(new File(path)).delete();
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 480504d..0a04e5b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -16,6 +16,9 @@
package android.content.pm;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
@@ -496,7 +499,7 @@
*/
public CharSequence loadDescription(PackageManager pm) {
if (descriptionRes != 0) {
- CharSequence label = pm.getText(packageName, descriptionRes, null);
+ CharSequence label = pm.getText(packageName, descriptionRes, this);
if (label != null) {
return label;
}
@@ -514,4 +517,31 @@
FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS |
FLAG_SUPPORTS_SCREEN_DENSITIES);
}
+
+ /**
+ * @hide
+ */
+ @Override protected Drawable loadDefaultIcon(PackageManager pm) {
+ if ((flags & FLAG_EXTERNAL_STORAGE) != 0
+ && isPackageUnavailable(pm)) {
+ return Resources.getSystem().getDrawable(
+ com.android.internal.R.drawable.sym_app_on_sd_unavailable_icon);
+ }
+ return pm.getDefaultActivityIcon();
+ }
+
+ private boolean isPackageUnavailable(PackageManager pm) {
+ try {
+ return pm.getPackageInfo(packageName, 0) == null;
+ } catch (NameNotFoundException ex) {
+ return true;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override protected ApplicationInfo getApplicationInfo() {
+ return this;
+ }
}
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 338c62b6..cafe372 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -99,24 +99,6 @@
return name;
}
- @Override public Drawable loadIcon(PackageManager pm) {
- ApplicationInfo ai = applicationInfo;
- Drawable dr;
- if (icon != 0) {
- dr = pm.getDrawable(packageName, icon, ai);
- if (dr != null) {
- return dr;
- }
- }
- if (ai.icon != 0) {
- dr = pm.getDrawable(packageName, ai.icon, ai);
- if (dr != null) {
- return dr;
- }
- }
- return pm.getDefaultActivityIcon();
- }
-
/**
* Return the icon resource identifier to use for this component. If
* the component defines an icon, that is used; else, the application
@@ -155,7 +137,7 @@
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(exported ? 1 : 0);
}
-
+
protected ComponentInfo(Parcel source) {
super(source);
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
@@ -164,4 +146,18 @@
enabled = (source.readInt() != 0);
exported = (source.readInt() != 0);
}
+
+ /**
+ * @hide
+ */
+ @Override protected Drawable loadDefaultIcon(PackageManager pm) {
+ return applicationInfo.loadIcon(pm);
+ }
+
+ /**
+ * @hide
+ */
+ @Override protected ApplicationInfo getApplicationInfo() {
+ return applicationInfo;
+ }
}
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index d666263..14c0680 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -103,7 +103,7 @@
return nonLocalizedLabel;
}
if (labelRes != 0) {
- CharSequence label = pm.getText(packageName, labelRes, null);
+ CharSequence label = pm.getText(packageName, labelRes, getApplicationInfo());
if (label != null) {
return label.toString().trim();
}
@@ -123,15 +123,31 @@
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's icon. If the
- * item does not have an icon, the default activity icon is returned.
+ * item does not have an icon, the item's default icon is returned
+ * such as the default activity icon.
*/
public Drawable loadIcon(PackageManager pm) {
if (icon != 0) {
- Drawable dr = pm.getDrawable(packageName, icon, null);
+ Drawable dr = pm.getDrawable(packageName, icon, getApplicationInfo());
if (dr != null) {
return dr;
}
}
+ return loadDefaultIcon(pm);
+ }
+
+ /**
+ * Retrieve the default graphical icon associated with this item.
+ *
+ * @param pm A PackageManager from which the icon can be loaded; usually
+ * the PackageManager from which you originally retrieved this item.
+ *
+ * @return Returns a Drawable containing the item's default icon
+ * such as the default activity icon.
+ *
+ * @hide
+ */
+ protected Drawable loadDefaultIcon(PackageManager pm) {
return pm.getDefaultActivityIcon();
}
@@ -152,7 +168,7 @@
if (metaData != null) {
int resid = metaData.getInt(name);
if (resid != 0) {
- return pm.getXml(packageName, resid, null);
+ return pm.getXml(packageName, resid, getApplicationInfo());
}
}
return null;
@@ -182,7 +198,7 @@
dest.writeInt(icon);
dest.writeBundle(metaData);
}
-
+
protected PackageItemInfo(Parcel source) {
name = source.readString();
packageName = source.readString();
@@ -193,6 +209,18 @@
metaData = source.readBundle();
}
+ /**
+ * Get the ApplicationInfo for the application to which this item belongs,
+ * if available, otherwise returns null.
+ *
+ * @return Returns the ApplicationInfo of this item, or null if not known.
+ *
+ * @hide
+ */
+ protected ApplicationInfo getApplicationInfo() {
+ return null;
+ }
+
public static class DisplayNameComparator
implements Comparator<PackageItemInfo> {
public DisplayNameComparator(PackageManager pm) {
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index a35940f..74e756b 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -163,8 +163,6 @@
* item does not have an icon, the default activity icon is returned.
*/
public Drawable loadIcon(PackageManager pm) {
- ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
- ApplicationInfo ai = ci.applicationInfo;
Drawable dr;
if (resolvePackageName != null && icon != 0) {
dr = pm.getDrawable(resolvePackageName, icon, null);
@@ -172,6 +170,8 @@
return dr;
}
}
+ ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
+ ApplicationInfo ai = ci.applicationInfo;
if (icon != 0) {
dr = pm.getDrawable(ci.packageName, icon, ai);
if (dr != null) {
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index e5bc6e3..4101ab4 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -54,12 +54,12 @@
static final int MATCH_GROUP_PATH = 5;
static Pattern sAddressPattern = Pattern.compile(
- /* scheme */ "(?:(http|HTTP|https|HTTPS|file|FILE)\\:\\/\\/)?" +
+ /* scheme */ "(?:(http|https|file)\\:\\/\\/)?" +
/* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
/* host */ "([-" + GOOD_IRI_CHAR + "%_]+(?:\\.[-" + GOOD_IRI_CHAR + "%_]+)*|\\[[0-9a-fA-F:\\.]+\\])?" +
/* port */ "(?:\\:([0-9]*))?" +
/* path */ "(\\/?[^#]*)?" +
- /* anchor */ ".*");
+ /* anchor */ ".*", Pattern.CASE_INSENSITIVE);
/** parses given uriString. */
public WebAddress(String address) throws ParseException {
@@ -79,7 +79,7 @@
String t;
if (m.matches()) {
t = m.group(MATCH_GROUP_SCHEME);
- if (t != null) mScheme = t;
+ if (t != null) mScheme = t.toLowerCase();
t = m.group(MATCH_GROUP_AUTHORITY);
if (t != null) mAuthInfo = t;
t = m.group(MATCH_GROUP_HOST);
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index 84b6487..a31639f 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -238,6 +238,8 @@
mContext.registerReceiver(mProxyChangeReceiver,
new IntentFilter(Proxy.PROXY_CHANGE_ACTION));
}
+ // we need to resample the current proxy setup
+ setProxyConfig();
}
/**
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index eab1627..f7e7d39 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -68,6 +68,15 @@
* happened. You can determine its current state with
* {@link #getExternalStorageState()}.
*
+ * <p>Applications should not directly use this top-level directory, in
+ * order to avoid polluting the user's root namespace. Any files that are
+ * private to the application should be placed in a directory returned
+ * by {@link android.content.Context#getExternalFilesDir
+ * Context.getExternalFilesDir}, which the system will take care of deleting
+ * if the application is uninstalled. Other shared files should be placed
+ * in one of the directories returned by
+ * {@link #getExternalStoragePublicDirectory}.
+ *
* <p>Here is an example of typical code to monitor the state of
* external storage:</p>
*
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 194fe33..dc0d864 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -24,7 +24,6 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
-import android.os.RemoteException;
import android.pim.vcard.exception.VCardException;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
@@ -522,10 +521,6 @@
}
}
}
- } catch (RemoteException e) {
- Log.e(LOG_TAG, String.format("RemoteException at id %s (%s)",
- contactId, e.getMessage()));
- return "";
} finally {
if (entityIterator != null) {
entityIterator.close();
diff --git a/core/java/android/provider/Applications.java b/core/java/android/provider/Applications.java
index 0b0ce58..7aabc50 100644
--- a/core/java/android/provider/Applications.java
+++ b/core/java/android/provider/Applications.java
@@ -16,67 +16,112 @@
package android.provider;
-import android.app.SearchManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.database.Cursor;
import android.net.Uri;
-import android.widget.SimpleCursorAdapter;
+
+import java.util.List;
/**
- * <p>The Applications provider gives information about installed applications.</p>
- *
- * <p>This provider provides the following columns:
- *
- * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ * The Applications provider gives information about installed applications.
*
- * <thead>
- * <tr><th>Column Name</th> <th>Description</th> </tr>
- * </thead>
- *
- * <tbody>
- * <tr><th>{@link SearchManager#SUGGEST_COLUMN_TEXT_1}</th>
- * <td>The application name.</td>
- * </tr>
- *
- * <tr><th>{@link SearchManager#SUGGEST_COLUMN_INTENT_COMPONENT}</th>
- * <td>The component to be used when forming the intent.</td>
- * </tr>
- *
- * <tr><th>{@link SearchManager#SUGGEST_COLUMN_ICON_1}</th>
- * <td>The application's icon resource id, prepended by its package name and
- * separated by a colon, e.g., "com.android.alarmclock:2130837524". The
- * package name is required for an activity interpreting this value to
- * be able to correctly access the icon drawable, for example, in an override of
- * {@link SimpleCursorAdapter#setViewImage(android.widget.ImageView, String)}.</td>
- * </tr>
- *
- * <tr><th>{@link SearchManager#SUGGEST_COLUMN_ICON_2}</th>
- * <td><i>Unused - column provided to conform to the {@link SearchManager} stipulation
- * that all providers provide either both or neither of
- * {@link SearchManager#SUGGEST_COLUMN_ICON_1} and
- * {@link SearchManager#SUGGEST_COLUMN_ICON_2}.</td>
- * </tr>
- *
- * @hide pending API council approval - should be unhidden at the same time as
- * {@link SearchManager#SUGGEST_COLUMN_INTENT_COMPONENT}
+ * @hide Only used by ApplicationsProvider so far.
*/
public class Applications {
- private static final String TAG = "Applications";
/**
* The content authority for this provider.
- *
- * @hide
*/
public static final String AUTHORITY = "applications";
/**
* The content:// style URL for this provider
- *
- * @hide
*/
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
/**
+ * The content path for application component URIs.
+ */
+ public static final String APPLICATION_PATH = "applications";
+
+ /**
+ * The content path for application search.
+ */
+ public static final String SEARCH_PATH = "search";
+
+ private static final String APPLICATION_SUB_TYPE = "vnd.android.application";
+
+ /**
+ * The MIME type for a single application item.
+ */
+ public static final String APPLICATION_ITEM_TYPE =
+ ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + APPLICATION_SUB_TYPE;
+
+ /**
+ * The MIME type for a list of application items.
+ */
+ public static final String APPLICATION_DIR_TYPE =
+ ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + APPLICATION_SUB_TYPE;
+
+ /**
* no public constructor since this is a utility class
*/
private Applications() {}
+
+ /**
+ * Gets a cursor with application search results.
+ * See {@link ApplicationColumns} for the columns available in the returned cursor.
+ */
+ public static Cursor search(ContentResolver resolver, String query) {
+ Uri searchUri = CONTENT_URI.buildUpon().appendPath(SEARCH_PATH).appendPath(query).build();
+ return resolver.query(searchUri, null, null, null, null);
+ }
+
+ /**
+ * Gets the application component name from an application URI.
+ *
+ * @param appUri A URI of the form
+ * "content://applications/applications/<packageName>/<className>".
+ * @return The component name for the application, or
+ * <code>null</code> if the given URI was <code>null</code>
+ * or malformed.
+ */
+ public static ComponentName uriToComponentName(Uri appUri) {
+ if (appUri == null) return null;
+ if (!ContentResolver.SCHEME_CONTENT.equals(appUri.getScheme())) return null;
+ if (!AUTHORITY.equals(appUri.getAuthority())) return null;
+ List<String> pathSegments = appUri.getPathSegments();
+ if (pathSegments.size() != 3) return null;
+ if (!APPLICATION_PATH.equals(pathSegments.get(0))) return null;
+ String packageName = pathSegments.get(1);
+ String name = pathSegments.get(2);
+ return new ComponentName(packageName, name);
+ }
+
+ /**
+ * Gets the URI for an application component.
+ *
+ * @param packageName The name of the application's package.
+ * @param className The class name of the application.
+ * @return A URI of the form
+ * "content://applications/applications/<packageName>/<className>".
+ */
+ public static Uri componentNameToUri(String packageName, String className) {
+ return Applications.CONTENT_URI.buildUpon()
+ .appendEncodedPath(APPLICATION_PATH)
+ .appendPath(packageName)
+ .appendPath(className)
+ .build();
+ }
+
+ /**
+ * The columns in application cursors, like those returned by
+ * {@link Applications#search(ContentResolver, String)}.
+ */
+ public interface ApplicationColumns extends BaseColumns {
+ public static final String NAME = "name";
+ public static final String ICON = "icon";
+ public static final String URI = "uri";
+ }
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d615fd0..8ef2aeb 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1688,11 +1688,12 @@
// bail out before bad things happen
if (mDataChanged) return;
- if (mAdapter != null && mItemCount > 0 &&
- mClickMotionPosition != INVALID_POSITION &&
- mClickMotionPosition < mAdapter.getCount() && sameWindow()) {
- performItemClick(mChild, mClickMotionPosition, getAdapter().getItemId(
- mClickMotionPosition));
+ final ListAdapter adapter = mAdapter;
+ final int motionPosition = mClickMotionPosition;
+ if (adapter != null && mItemCount > 0 &&
+ motionPosition != INVALID_POSITION &&
+ motionPosition < adapter.getCount() && sameWindow()) {
+ performItemClick(mChild, motionPosition, adapter.getItemId(motionPosition));
}
}
}
@@ -2118,8 +2119,8 @@
mPendingCheckForTap : mPendingCheckForLongPress);
}
mLayoutMode = LAYOUT_NORMAL;
- mTouchMode = TOUCH_MODE_TAP;
- if (!mDataChanged) {
+ if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
+ mTouchMode = TOUCH_MODE_TAP;
setSelectedPositionInt(mMotionPosition);
layoutChildren();
child.setPressed(true);
@@ -2141,12 +2142,12 @@
mTouchMode = TOUCH_MODE_REST;
}
}, ViewConfiguration.getPressedStateDuration());
+ } else {
+ mTouchMode = TOUCH_MODE_REST;
}
return true;
- } else {
- if (!mDataChanged) {
- post(performClick);
- }
+ } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
+ post(performClick);
}
}
mTouchMode = TOUCH_MODE_REST;
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index ec79a50..333257e 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -269,9 +269,19 @@
bindContactInfo(cursor);
Uri lookupUri = Contacts.getLookupUri(cursor.getLong(ContactQuery._ID),
cursor.getString(ContactQuery.LOOKUP_KEY));
- startPhotoQuery(cursor.getLong(ContactQuery.PHOTO_ID),
- lookupUri, false /* don't reset query handler */);
- invalidate();
+
+ final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
+
+ if (photoId == 0) {
+ mPhotoView.setImageBitmap(loadPlaceholderPhoto(null));
+ if (cookie != null && cookie instanceof Uri) {
+ mPhotoView.assignContactUri((Uri) cookie);
+ }
+ invalidate();
+ } else {
+ startPhotoQuery(photoId, lookupUri,
+ false /* don't reset query handler */);
+ }
} else {
// shouldn't really happen
setDisplayName(null, null);
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index a3be309..f60fe6d 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -41,6 +41,7 @@
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsPrivacyInterface* sGpsPrivacyInterface = NULL;
static const GpsNiInterface* sGpsNiInterface = NULL;
static const GpsDebugInterface* sGpsDebugInterface = NULL;
@@ -223,9 +224,15 @@
sAGpsInterface->init(&sAGpsCallbacks);
if (!sGpsNiInterface)
- sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
if (sGpsNiInterface)
- sGpsNiInterface->init(&sGpsNiCallbacks);
+ sGpsNiInterface->init(&sGpsNiCallbacks);
+
+ // Clear privacy lock while enabled
+ if (!sGpsPrivacyInterface)
+ sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE);
+ if (sGpsPrivacyInterface)
+ sGpsPrivacyInterface->set_privacy_lock(0);
if (!sGpsDebugInterface)
sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
@@ -235,6 +242,12 @@
static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
{
+ // Enable privacy lock while disabled
+ if (!sGpsPrivacyInterface)
+ sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE);
+ if (sGpsPrivacyInterface)
+ sGpsPrivacyInterface->set_privacy_lock(1);
+
pthread_mutex_lock(&sEventMutex);
sPendingCallbacks |= kDisableRequest;
pthread_cond_signal(&sEventCond);
@@ -476,12 +489,10 @@
static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
jint notifId, jint response)
{
- if (!sGpsNiInterface) {
+ if (!sGpsNiInterface)
sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
- }
- if (sGpsNiInterface) {
+ if (sGpsNiInterface)
sGpsNiInterface->respond(notifId, response);
- }
}
static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
diff --git a/core/res/res/drawable-hdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/drawable-hdpi/sym_app_on_sd_unavailable_icon.png
new file mode 100644
index 0000000..d915d41
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_app_on_sd_unavailable_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/drawable-mdpi/sym_app_on_sd_unavailable_icon.png
new file mode 100644
index 0000000..4730668
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sym_app_on_sd_unavailable_icon.png
Binary files differ
diff --git a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
index 48fe765..f840512 100644
--- a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
+++ b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
@@ -51,7 +51,7 @@
long historyId = engine.insertStartSyncEvent(
account, authority, time0, SyncStorageEngine.SOURCE_LOCAL);
long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
- engine.stopSyncEvent(historyId, new Bundle(), time1 - time0, "yay", 0, 0);
+ engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
}
/**
diff --git a/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java b/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
index 1b3cdcc..5968e83 100644
--- a/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
+++ b/core/tests/coretests/src/android/pim/vcard/ExportTestResolver.java
@@ -21,7 +21,6 @@
import android.content.EntityIterator;
import android.database.Cursor;
import android.net.Uri;
-import android.pim.vcard.VCardComposer;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
@@ -69,6 +68,10 @@
return mIterator.next();
}
+ public void remove() {
+ throw new UnsupportedOperationException("remove not supported");
+ }
+
public void reset() {
mIterator = mEntityList.iterator();
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 842176e..27add0a 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -395,6 +395,7 @@
mVideoTimeUs = 0;
mSeeking = false;
+ mSeekNotificationSent = false;
mSeekTimeUs = 0;
mUri.setTo("");
@@ -686,11 +687,20 @@
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
mSeeking = true;
+ mSeekNotificationSent = false;
mSeekTimeUs = timeUs;
mFlags &= ~AT_EOS;
seekAudioIfNecessary_l();
+ if (!(mFlags & PLAYING)) {
+ LOGV("seeking while paused, sending SEEK_COMPLETE notification"
+ " immediately.");
+
+ notifyListener_l(MEDIA_SEEK_COMPLETE);
+ mSeekNotificationSent = true;
+ }
+
return OK;
}
@@ -701,6 +711,7 @@
mWatchForAudioSeekComplete = true;
mWatchForAudioEOS = true;
mSeeking = false;
+ mSeekNotificationSent = false;
}
}
@@ -869,7 +880,7 @@
mAudioPlayer->seekTo(timeUs);
mWatchForAudioSeekComplete = true;
mWatchForAudioEOS = true;
- } else {
+ } else if (!mSeekNotificationSent) {
// If we're playing video only, report seek complete now,
// otherwise audio player will notify us later.
notifyListener_l(MEDIA_SEEK_COMPLETE);
@@ -877,6 +888,7 @@
mFlags |= FIRST_FRAME;
mSeeking = false;
+ mSeekNotificationSent = false;
}
if (mFlags & FIRST_FRAME) {
@@ -984,7 +996,11 @@
if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
mWatchForAudioSeekComplete = false;
- notifyListener_l(MEDIA_SEEK_COMPLETE);
+
+ if (!mSeekNotificationSent) {
+ notifyListener_l(MEDIA_SEEK_COMPLETE);
+ mSeekNotificationSent = true;
+ }
}
status_t finalStatus;
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index fe84b38..2ed8ef1 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -144,6 +144,8 @@
meta->setInt64(kKeyDuration, durationUs);
}
+ meta->setCString(kKeyDecoderComponent, "AACDecoder");
+
return meta;
}
diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
index 553be87..7728597 100644
--- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
@@ -105,6 +105,8 @@
meta->setInt64(kKeyDuration, durationUs);
}
+ meta->setCString(kKeyDecoderComponent, "AMRNBDecoder");
+
return meta;
}
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index b6d7ea3..f349671 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -138,6 +138,8 @@
meta->setInt64(kKeyDuration, durationUs);
}
+ meta->setCString(kKeyDecoderComponent, "AMRNBEncoder");
+
return meta;
}
diff --git a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
index c9d38c0..c17c100 100644
--- a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
+++ b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
@@ -110,6 +110,8 @@
meta->setInt64(kKeyDuration, durationUs);
}
+ meta->setCString(kKeyDecoderComponent, "AMRWBDecoder");
+
return meta;
}
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
index 4dc96be..efcb476 100644
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -107,6 +107,8 @@
meta->setInt64(kKeyDuration, durationUs);
}
+ meta->setCString(kKeyDecoderComponent, "MP3Decoder");
+
return meta;
}
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index c985dff..9e8a674 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -132,6 +132,7 @@
int64_t mVideoTimeUs;
bool mSeeking;
+ bool mSeekNotificationSent;
int64_t mSeekTimeUs;
bool mWatchForAudioSeekComplete;
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 57944fb..5cf61bd 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -177,6 +177,7 @@
void systemReady() {
// check our power situation now that it is safe to display the shutdown dialog.
shutdownIfNoPower();
+ shutdownIfOverTemp();
}
private final void shutdownIfNoPower() {
@@ -190,6 +191,17 @@
}
}
+ private final void shutdownIfOverTemp() {
+ // shut down gracefully if temperature is too high (> 68.0C)
+ // wait until the system has booted before attempting to display the shutdown dialog.
+ if (mBatteryTemperature > 680 && ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+ }
+
private native void native_update();
private synchronized final void update() {
@@ -199,6 +211,7 @@
long dischargeDuration = 0;
shutdownIfNoPower();
+ shutdownIfOverTemp();
mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 7cd058a..8788cd5 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5464,6 +5464,17 @@
boolean dataDirExists = getDataPathForPackage(pkg).exists();
res.name = pkgName;
synchronized(mPackages) {
+ if (mSettings.mRenamedPackages.containsKey(pkgName)) {
+ // A package with the same name is already installed, though
+ // it has been renamed to an older name. The package we
+ // are trying to install should be installed as an update to
+ // the existing one, but that has not been requested, so bail.
+ Slog.w(TAG, "Attempt to re-install " + pkgName
+ + " without first uninstalling package running as "
+ + mSettings.mRenamedPackages.get(pkgName));
+ res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+ return;
+ }
if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
// Don't allow installation over an existing package with the same name.
Slog.w(TAG, "Attempt to re-install " + pkgName
@@ -5595,7 +5606,7 @@
PackageInstalledInfo restoreRes = new PackageInstalledInfo();
restoreRes.removedInfo = new PackageRemovedInfo();
// Parse old package
- parseFlags |= ~PackageManager.INSTALL_REPLACE_EXISTING;
+ parseFlags &= ~PackageManager.INSTALL_REPLACE_EXISTING;
scanPackageLI(restoreFile, parseFlags, scanMode);
synchronized (mPackages) {
updatePermissionsLP(deletedPackage.packageName, deletedPackage,
@@ -6278,7 +6289,7 @@
Log.i(TAG, "Removing non-system package:"+p.packageName);
// Kill application pre-emptively especially for apps on sd.
killApplication(packageName, p.applicationInfo.uid);
- ret = deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
+ ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
}
return ret;
}
@@ -7605,9 +7616,10 @@
}
void setFlags(int pkgFlags) {
- this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) |
- (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
- (pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE);
+ this.pkgFlags = pkgFlags & (
+ ApplicationInfo.FLAG_SYSTEM |
+ ApplicationInfo.FLAG_FORWARD_LOCK |
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE);
}
}
@@ -9606,7 +9618,7 @@
}
// Parse package
int parseFlags = PackageParser.PARSE_CHATTY |
- PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+ PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
PackageParser pp = new PackageParser(codePath);
pp.setSeparateProcesses(mSeparateProcesses);
final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
@@ -9682,7 +9694,7 @@
if (res) {
pkgList.add(pkgName);
} else {
- Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
+ Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
failedList.add(args);
}
}