Merge "In theory the package manager now scans /vendor/app" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 8651c4d..af91389 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -96356,6 +96356,17 @@
visibility="public"
>
</field>
+<field name="ERROR_FILE_ALREADY_EXISTS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1009"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ERROR_FILE_ERROR"
type="int"
transient="false"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6e6e86f..72bf825 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1427,7 +1427,9 @@
* <li> The function will be called between {@link #onStop} and
* {@link #onDestroy}.
* <li> A new instance of the activity will <em>always</em> be immediately
- * created after this one's {@link #onDestroy()} is called.
+ * created after this one's {@link #onDestroy()} is called. In particular,
+ * <em>no</em> messages will be dispatched during this time (when the returned
+ * object does not have an activity to be associated with).
* <li> The object you return here will <em>always</em> be available from
* the {@link #getLastNonConfigurationInstance()} method of the following
* activity instance as described there.
@@ -1440,6 +1442,15 @@
* may change based on the configuration, including any data loaded from
* resources such as strings, layouts, or drawables.
*
+ * <p>The guarantee of no message handling during the switch to the next
+ * activity simplifies use with active objects. For example if your retained
+ * state is an {@link android.os.AsyncTask} you are guaranteed that its
+ * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will
+ * not be called from the call here until you execute the next instance's
+ * {@link #onCreate(Bundle)}. (Note however that there is of course no such
+ * guarantee for {@link android.os.AsyncTask#doInBackground} since that is
+ * running in a separate thread.)
+ *
* @return Return any Object holding the desired state to propagate to the
* next activity instance.
*/
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index ae29994..e140349 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -3,6 +3,9 @@
<p>Contains the backup and restore functionality available to
applications. If a user wipes the data on their device or upgrades to a new Android-powered
device, all applications that have enabled backup will restore the user's previous data.</p>
+
+<p>For a detailed guide to using the backup APIs, see the <a
+href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p>
{@more}
<p>All backup and restore operations are controlled by the {@link
@@ -22,8 +25,5 @@
<li>Restore the data saved to remote storage</li>
</ul>
-<p>For a detailed guide to using the backup APIs, see the <a
-href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p>
-
</BODY>
</HTML>
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
index 5320da3..8bb747e 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/net/DownloadManager.java
@@ -25,7 +25,6 @@
import android.provider.BaseColumns;
import android.provider.Downloads;
-import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -195,6 +194,12 @@
public final static int ERROR_CANNOT_RESUME = 1008;
/**
+ * Value of {@link #COLUMN_ERROR_CODE} when the requested destination file already exists (the
+ * download manager will not overwrite an existing file).
+ */
+ public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
+
+ /**
* Broadcast intent action sent by the download manager when a download completes.
*/
public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
@@ -235,10 +240,11 @@
Downloads.COLUMN_URI,
Downloads.COLUMN_MIME_TYPE,
Downloads.COLUMN_TOTAL_BYTES,
- Downloads._DATA,
Downloads.COLUMN_STATUS,
Downloads.COLUMN_CURRENT_BYTES,
Downloads.COLUMN_LAST_MODIFICATION,
+ Downloads.COLUMN_DESTINATION,
+ Downloads.Impl.COLUMN_FILE_NAME_HINT,
};
private static final Set<String> LONG_COLUMNS = new HashSet<String>(
@@ -820,15 +826,10 @@
}
private String getLocalUri() {
- String localUri = getUnderlyingString(Downloads.Impl._DATA);
- if (localUri == null) {
- return null;
- }
-
long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
- // return file URI for external download
- return Uri.fromFile(new File(localUri)).toString();
+ // return client-provided file URI for external download
+ return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
}
// return content URI for cache download
@@ -894,6 +895,9 @@
case Downloads.Impl.STATUS_CANNOT_RESUME:
return ERROR_CANNOT_RESUME;
+ case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
+ return ERROR_FILE_ALREADY_EXISTS;
+
default:
return ERROR_UNKNOWN;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1e88c56..ba8014f2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -397,7 +397,7 @@
}
}
- public final class HistoryItem implements Parcelable {
+ public final static class HistoryItem implements Parcelable {
public HistoryItem next;
public long time;
@@ -482,6 +482,18 @@
dest.writeInt(states);
}
+ public void setTo(HistoryItem o) {
+ time = o.time;
+ cmd = o.cmd;
+ batteryLevel = o.batteryLevel;
+ batteryStatus = o.batteryStatus;
+ batteryHealth = o.batteryHealth;
+ batteryPlugType = o.batteryPlugType;
+ batteryTemperature = o.batteryTemperature;
+ batteryVoltage = o.batteryVoltage;
+ states = o.states;
+ }
+
public void setTo(long time, byte cmd, HistoryItem o) {
this.time = time;
this.cmd = cmd;
@@ -526,6 +538,10 @@
}
}
+ public abstract boolean startIteratingHistoryLocked();
+
+ public abstract boolean getNextHistoryLocked(HistoryItem out);
+
/**
* Return the current history of battery state changes.
*/
@@ -1688,8 +1704,8 @@
*/
@SuppressWarnings("unused")
public void dumpLocked(PrintWriter pw) {
- HistoryItem rec = getHistory();
- if (rec != null) {
+ final HistoryItem rec = new HistoryItem();
+ if (startIteratingHistoryLocked()) {
pw.println("Battery History:");
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
int oldState = 0;
@@ -1698,7 +1714,7 @@
int oldPlug = -1;
int oldTemp = -1;
int oldVolt = -1;
- while (rec != null) {
+ while (getNextHistoryLocked(rec)) {
pw.print(" ");
TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
pw.print(" ");
@@ -1803,7 +1819,6 @@
pw.println();
}
oldState = rec.states;
- rec = rec.next;
}
pw.println("");
}
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 74c7372..871a0441 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -1077,7 +1077,12 @@
/**
* The lowest-valued error status that is not an actual HTTP status code.
*/
- public static final int MIN_ARTIFICIAL_ERROR_STATUS = 489;
+ public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488;
+
+ /**
+ * The requested destination file already exists.
+ */
+ public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
/**
* Some possibly transient error occurred, but we can't resume the download.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index c2d003e..6e5c47f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -51,6 +51,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
/**
* All information we are collecting about things that can happen that impact
@@ -3834,6 +3835,22 @@
}
}
+ private HistoryItem mHistoryIterator;
+
+ public boolean startIteratingHistoryLocked() {
+ return (mHistoryIterator = mHistory) != null;
+ }
+
+ public boolean getNextHistoryLocked(HistoryItem out) {
+ HistoryItem cur = mHistoryIterator;
+ if (cur == null) {
+ return false;
+ }
+ out.setTo(cur);
+ mHistoryIterator = cur.next;
+ return true;
+ }
+
@Override
public HistoryItem getHistory() {
return mHistory;
@@ -3960,7 +3977,7 @@
}
if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
if (mFile != null) {
- writeLocked();
+ writeAsyncLocked();
}
}
}
@@ -4356,11 +4373,22 @@
}
public void shutdownLocked() {
- writeLocked();
+ writeSyncLocked();
mShuttingDown = true;
}
- public void writeLocked() {
+ Parcel mPendingWrite = null;
+ final ReentrantLock mWriteLock = new ReentrantLock();
+
+ public void writeAsyncLocked() {
+ writeLocked(false);
+ }
+
+ public void writeSyncLocked() {
+ writeLocked(true);
+ }
+
+ void writeLocked(boolean sync) {
if (mFile == null) {
Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
return;
@@ -4370,23 +4398,51 @@
return;
}
+ Parcel out = Parcel.obtain();
+ writeSummaryToParcel(out);
+ mLastWriteTime = SystemClock.elapsedRealtime();
+
+ if (mPendingWrite != null) {
+ mPendingWrite.recycle();
+ }
+ mPendingWrite = out;
+
+ if (sync) {
+ commitPendingDataToDisk();
+ } else {
+ Thread thr = new Thread("BatteryStats-Write") {
+ @Override
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ commitPendingDataToDisk();
+ }
+ };
+ thr.start();
+ }
+ }
+
+ public void commitPendingDataToDisk() {
+ Parcel next;
+ synchronized (this) {
+ next = mPendingWrite;
+ mPendingWrite = null;
+
+ mWriteLock.lock();
+ }
+
try {
FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
- Parcel out = Parcel.obtain();
- writeSummaryToParcel(out);
- stream.write(out.marshall());
- out.recycle();
-
+ stream.write(next.marshall());
stream.flush();
stream.close();
mFile.commit();
-
- mLastWriteTime = SystemClock.elapsedRealtime();
- return;
} catch (IOException e) {
Slog.w("BatteryStats", "Error writing battery statistics", e);
+ mFile.rollback();
+ } finally {
+ next.recycle();
+ mWriteLock.unlock();
}
- mFile.rollback();
}
static byte[] readFully(FileInputStream stream) throws java.io.IOException {
diff --git a/core/res/res/drawable-mdpi/overscroll_edge.png b/core/res/res/drawable-mdpi/overscroll_edge.png
new file mode 100644
index 0000000..22f4ef8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/overscroll_glow.png b/core/res/res/drawable-mdpi/overscroll_glow.png
new file mode 100644
index 0000000..761fb74
--- /dev/null
+++ b/core/res/res/drawable-mdpi/overscroll_glow.png
Binary files differ
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 5d6ac26..747c829 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -136,30 +136,24 @@
*/
void* dso;
- char path[PATH_MAX];
int index = int(display);
driver_t* hnd = 0;
- const char* const format = "/system/lib/egl/lib%s_%s.so";
char const* tag = getTag(index, impl);
if (tag) {
- snprintf(path, PATH_MAX, format, "GLES", tag);
- dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2);
+ dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
hnd = new driver_t(dso);
} else {
// Always load EGL first
- snprintf(path, PATH_MAX, format, "EGL", tag);
- dso = load_driver(path, cnx, EGL);
+ dso = load_driver("EGL", tag, cnx, EGL);
if (dso) {
hnd = new driver_t(dso);
// TODO: make this more automated
- snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
- hnd->set( load_driver(path, cnx, GLESv1_CM), GLESv1_CM );
+ hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
- snprintf(path, PATH_MAX, format, "GLESv2", tag);
- hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
+ hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
}
}
}
@@ -222,12 +216,20 @@
}
}
-void *Loader::load_driver(const char* driver_absolute_path,
+void *Loader::load_driver(const char* kind, const char *tag,
egl_connection_t* cnx, uint32_t mask)
{
+ char driver_absolute_path[PATH_MAX];
+ const char* const search1 = "/vendor/lib/egl/lib%s_%s.so";
+ const char* const search2 = "/system/lib/egl/lib%s_%s.so";
+
+ snprintf(driver_absolute_path, PATH_MAX, search1, kind, tag);
if (access(driver_absolute_path, R_OK)) {
- // this happens often, we don't want to log an error
- return 0;
+ snprintf(driver_absolute_path, PATH_MAX, search2, kind, tag);
+ if (access(driver_absolute_path, R_OK)) {
+ // this happens often, we don't want to log an error
+ return 0;
+ }
}
void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 8659b0b..580d6e4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -74,7 +74,7 @@
private:
Loader();
- void *load_driver(const char* driver, egl_connection_t* cnx, uint32_t mask);
+ void *load_driver(const char* kind, const char *tag, egl_connection_t* cnx, uint32_t mask);
static __attribute__((noinline))
void init_api(void* dso,
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9835098..d7a1ac25 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8316,6 +8316,11 @@
return;
}
+ if (mDisplay == null) {
+ // Not yet initialized, nothing to do.
+ return;
+ }
+
boolean recoveringMemory = false;
if (mForceRemoves != null) {
recoveringMemory = true;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cf767ca..3172077 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1383,7 +1383,7 @@
mBatteryStatsService = new BatteryStatsService(new File(
systemDir, "batterystats.bin").toString());
mBatteryStatsService.getActiveStatistics().readLocked();
- mBatteryStatsService.getActiveStatistics().writeLocked();
+ mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
@@ -1536,7 +1536,7 @@
if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
mLastWriteTime = now;
- mBatteryStatsService.getActiveStatistics().writeLocked();
+ mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 4d8cbf0..9f86378 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -82,7 +82,7 @@
// Singleton instance
private static final CallManager INSTANCE = new CallManager();
- // list of registered phones
+ // list of registered phones, which are PhoneBase objs
private final ArrayList<Phone> mPhones;
// list of supported ringing calls
@@ -97,7 +97,7 @@
// empty connection list
private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
- // default phone as the first phone registered
+ // default phone as the first phone registered, which is PhoneBase obj
private Phone mDefaultPhone;
// state registrants
@@ -181,6 +181,46 @@
}
/**
+ * Get the corresponding PhoneBase obj
+ *
+ * @param phone a Phone object
+ * @return the corresponding PhoneBase obj in Phone if Phone
+ * is a PhoneProxy obj
+ * or the Phone itself if Phone is not a PhoneProxy obj
+ */
+ private static Phone getPhoneBase(Phone phone) {
+ if (phone instanceof PhoneProxy) {
+ return phone.getForegroundCall().getPhone();
+ }
+ return phone;
+ }
+
+ /**
+ * Check if two phones refer to the same PhoneBase obj
+ *
+ * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
+ *
+ * Both PhoneBase and PhoneProxy implement Phone interface, so
+ * they have same phone APIs, such as dial(). The real implementation, for
+ * example in GSM, is in GSMPhone as extend from PhoneBase, so that
+ * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
+ * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
+ * member of GSMPhone.
+ *
+ * So for phone returned by PhoneFacotry, which is used by PhoneApp,
+ * phone.getForegroundCall().getPhone() != phone
+ * but
+ * isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
+ *
+ * @param p1 is the first Phone obj
+ * @param p2 is the second Phone obj
+ * @return true if p1 and p2 refer to the same phone
+ */
+ public static boolean isSamePhone(Phone p1, Phone p2) {
+ return (getPhoneBase(p1) == getPhoneBase(p2));
+ }
+
+ /**
* Returns all the registered phone objects.
* @return all the registered phone objects.
*/
@@ -246,25 +286,50 @@
/**
* Register phone to CallManager
- * @param phone
+ * @param phone to be registered
* @return true if register successfully
*/
public boolean registerPhone(Phone phone) {
- if (phone != null && !mPhones.contains(phone)) {
+ Phone basePhone = getPhoneBase(phone);
+
+ if (basePhone != null && !mPhones.contains(basePhone)) {
if (mPhones.isEmpty()) {
- mDefaultPhone = phone;
+ mDefaultPhone = basePhone;
}
- mPhones.add(phone);
- mRingingCalls.add(phone.getRingingCall());
- mBackgroundCalls.add(phone.getBackgroundCall());
- mForegroundCalls.add(phone.getForegroundCall());
- registerForPhoneStates(phone);
+ mPhones.add(basePhone);
+ mRingingCalls.add(basePhone.getRingingCall());
+ mBackgroundCalls.add(basePhone.getBackgroundCall());
+ mForegroundCalls.add(basePhone.getForegroundCall());
+ registerForPhoneStates(basePhone);
return true;
}
return false;
}
/**
+ * unregister phone from CallManager
+ * @param phone to be unregistered
+ */
+ public void unregisterPhone(Phone phone) {
+ Phone basePhone = getPhoneBase(phone);
+
+ if (basePhone != null && mPhones.contains(basePhone)) {
+ mPhones.remove(basePhone);
+ mRingingCalls.remove(basePhone.getRingingCall());
+ mBackgroundCalls.remove(basePhone.getBackgroundCall());
+ mForegroundCalls.remove(basePhone.getForegroundCall());
+ unregisterForPhoneStates(basePhone);
+ if (basePhone == mDefaultPhone) {
+ if (mPhones.isEmpty()) {
+ mDefaultPhone = null;
+ } else {
+ mDefaultPhone = mPhones.get(0);
+ }
+ }
+ }
+ }
+
+ /**
* return the default phone or null if no phone available
*/
public Phone getDefaultPhone() {
@@ -304,26 +369,7 @@
return null;
}
- /**
- * unregister phone from CallManager
- * @param phone
- */
- public void unregisterPhone(Phone phone) {
- if (phone != null && mPhones.contains(phone)) {
- mPhones.remove(phone);
- mRingingCalls.remove(phone.getRingingCall());
- mBackgroundCalls.remove(phone.getBackgroundCall());
- mForegroundCalls.remove(phone.getForegroundCall());
- unregisterForPhoneStates(phone);
- if (phone == mDefaultPhone) {
- if (mPhones.isEmpty()) {
- mDefaultPhone = null;
- } else {
- mDefaultPhone = mPhones.get(0);
- }
- }
- }
- }
+
public void setAudioMode() {
Context context = getContext();
@@ -592,8 +638,9 @@
* handled asynchronously.
*/
public Connection dial(Phone phone, String dialString) throws CallStateException {
+ Phone basePhone = getPhoneBase(phone);
if (VDBG) {
- Log.d(LOG_TAG, "CallManager.dial( phone=" + phone + ", dialString="+ dialString + ")");
+ Log.d(LOG_TAG, "CallManager.dial( phone=" + basePhone + ", dialString="+ dialString + ")");
Log.d(LOG_TAG, this.toString());
}
if ( hasActiveFgCall() ) {
@@ -601,10 +648,10 @@
boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
if (DBG) {
- Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == phone));
+ Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
}
- if (activePhone != phone) {
+ if (activePhone != basePhone) {
if (hasBgCall) {
Log.d(LOG_TAG, "Hangup");
getActiveFgCall().hangup();
@@ -614,7 +661,7 @@
}
}
}
- return phone.dial(dialString);
+ return basePhone.dial(dialString);
}
/**