summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml76
-rw-r--r--common/java/com/android/common/OperationScheduler.java41
-rw-r--r--common/tests/src/com/android/common/OperationSchedulerTest.java132
-rw-r--r--core/java/android/app/ContextImpl.java17
-rw-r--r--core/java/android/app/IUiModeManager.aidl2
-rw-r--r--core/java/android/app/UiModeManager.java23
-rw-r--r--core/java/android/net/IThrottleManager.aidl2
-rw-r--r--core/java/android/net/ThrottleManager.java25
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java19
-rw-r--r--core/java/android/os/RecoverySystem.java8
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/view/ViewRoot.java20
-rw-r--r--core/java/android/webkit/CacheManager.java6
-rw-r--r--core/java/android/webkit/CookieManager.java4
-rw-r--r--core/java/android/webkit/LoadListener.java3
-rw-r--r--core/java/android/webkit/WebView.java142
-rw-r--r--core/java/android/widget/ScrollView.java2
-rw-r--r--core/java/com/android/internal/http/HttpDateTime.java (renamed from core/java/android/net/http/HttpDateTime.java)4
-rw-r--r--core/jni/android_net_TrafficStats.cpp8
-rw-r--r--core/jni/android_util_EventLog.cpp26
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_chat.pngbin1663 -> 1166 bytes
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--data/fonts/DroidSansArabic.ttfbin37328 -> 35908 bytes
-rw-r--r--data/fonts/DroidSansHebrew.ttfbin14668 -> 23076 bytes
-rw-r--r--libs/audioflinger/AudioFlinger.cpp2
-rw-r--r--media/libstagefright/id3/ID3.cpp137
-rw-r--r--media/libstagefright/include/ID3.h5
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java6
-rw-r--r--preloaded-classes2
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java172
-rw-r--r--services/java/com/android/server/PackageManagerService.java25
-rw-r--r--services/java/com/android/server/ThrottleService.java149
-rw-r--r--services/java/com/android/server/UiModeManagerService.java110
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnection.java3
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java6
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java15
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java6
37 files changed, 792 insertions, 421 deletions
diff --git a/api/current.xml b/api/current.xml
index 58b9c17..b256d3f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -25428,6 +25428,17 @@
visibility="public"
>
</field>
+<field name="ENABLE_CAR_MODE_GO_CAR_HOME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MODE_NIGHT_AUTO"
type="int"
transient="false"
@@ -89029,7 +89040,7 @@
<method name="getMobileRxBytes"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89040,7 +89051,7 @@
<method name="getMobileRxPackets"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89051,7 +89062,7 @@
<method name="getMobileTxBytes"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89062,7 +89073,7 @@
<method name="getMobileTxPackets"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89073,7 +89084,7 @@
<method name="getTotalRxBytes"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89084,7 +89095,7 @@
<method name="getTotalRxPackets"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89095,7 +89106,7 @@
<method name="getTotalTxBytes"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89106,7 +89117,7 @@
<method name="getTotalTxPackets"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89117,7 +89128,7 @@
<method name="getUidRxBytes"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -89130,7 +89141,7 @@
<method name="getUidTxBytes"
return="long"
abstract="false"
- native="false"
+ native="true"
synchronized="false"
static="true"
final="false"
@@ -90859,35 +90870,8 @@
<parameter name="userAgent" type="java.lang.String">
</parameter>
</method>
-<field name="DEFAULT_SYNC_MIN_GZIP_BYTES"
- type="long"
- transient="false"
- volatile="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-<class name="HttpDateTime"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="HttpDateTime"
- type="android.net.http.HttpDateTime"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="parse"
- return="java.lang.Long"
+<method name="parseDate"
+ return="long"
abstract="false"
native="false"
synchronized="false"
@@ -90896,11 +90880,19 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="timeString" type="java.lang.String">
+<parameter name="dateString" type="java.lang.String">
</parameter>
-<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
-</exception>
</method>
+<field name="DEFAULT_SYNC_MIN_GZIP_BYTES"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="SslCertificate"
extends="java.lang.Object"
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
index 0a48fe7..1786957 100644
--- a/common/java/com/android/common/OperationScheduler.java
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -17,7 +17,7 @@
package com.android.common;
import android.content.SharedPreferences;
-import android.net.http.HttpDateTime;
+import android.net.http.AndroidHttpClient;
import android.text.format.Time;
import java.util.Map;
@@ -124,7 +124,8 @@ public class OperationScheduler {
}
/**
- * Compute the time of the next operation. Does not modify any state.
+ * Compute the time of the next operation. Does not modify any state
+ * (unless the clock rolls backwards, in which case timers are reset).
*
* @param options to use for this computation.
* @return the wall clock time ({@link System#currentTimeMillis()}) when the
@@ -143,11 +144,11 @@ public class OperationScheduler {
// clipped to the current time so we don't languish forever.
int errorCount = mStorage.getInt(PREFIX + "errorCount", 0);
- long now = System.currentTimeMillis();
+ long now = currentTimeMillis();
long lastSuccessTimeMillis = getTimeBefore(PREFIX + "lastSuccessTimeMillis", now);
long lastErrorTimeMillis = getTimeBefore(PREFIX + "lastErrorTimeMillis", now);
long triggerTimeMillis = mStorage.getLong(PREFIX + "triggerTimeMillis", Long.MAX_VALUE);
- long moratoriumSetMillis = mStorage.getLong(PREFIX + "moratoriumSetTimeMillis", 0);
+ long moratoriumSetMillis = getTimeBefore(PREFIX + "moratoriumSetTimeMillis", now);
long moratoriumTimeMillis = getTimeBefore(PREFIX + "moratoriumTimeMillis",
moratoriumSetMillis + options.maxMoratoriumMillis);
@@ -155,9 +156,8 @@ public class OperationScheduler {
if (options.periodicIntervalMillis > 0) {
time = Math.min(time, lastSuccessTimeMillis + options.periodicIntervalMillis);
}
- if (time >= moratoriumTimeMillis - options.maxMoratoriumMillis) {
- time = Math.max(time, moratoriumTimeMillis);
- }
+
+ time = Math.max(time, moratoriumTimeMillis);
time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis);
if (errorCount > 0) {
time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
@@ -205,7 +205,7 @@ public class OperationScheduler {
/**
* Request an operation to be performed at a certain time. The actual
* scheduled time may be affected by error backoff logic and defined
- * minimum intervals.
+ * minimum intervals. Use {@link Long#MAX_VALUE} to disable triggering.
*
* @param millis wall clock time ({@link System#currentTimeMillis()}) to
* trigger another operation; 0 to trigger immediately
@@ -218,13 +218,13 @@ public class OperationScheduler {
* Forbid any operations until after a certain (absolute) time.
* Limited by {@link #Options.maxMoratoriumMillis}.
*
- * @param millis wall clock time ({@link System#currentTimeMillis()}) to
- * wait before attempting any more operations; 0 to remove moratorium
+ * @param millis wall clock time ({@link System#currentTimeMillis()})
+ * when operations should be allowed again; 0 to remove moratorium
*/
public void setMoratoriumTimeMillis(long millis) {
mStorage.edit()
.putLong(PREFIX + "moratoriumTimeMillis", millis)
- .putLong(PREFIX + "moratoriumSetTimeMillis", System.currentTimeMillis())
+ .putLong(PREFIX + "moratoriumSetTimeMillis", currentTimeMillis())
.commit();
}
@@ -239,11 +239,11 @@ public class OperationScheduler {
public boolean setMoratoriumTimeHttp(String retryAfter) {
try {
long ms = Long.valueOf(retryAfter) * 1000;
- setMoratoriumTimeMillis(ms + System.currentTimeMillis());
+ setMoratoriumTimeMillis(ms + currentTimeMillis());
return true;
} catch (NumberFormatException nfe) {
try {
- setMoratoriumTimeMillis(HttpDateTime.parse(retryAfter));
+ setMoratoriumTimeMillis(AndroidHttpClient.parseDate(retryAfter));
return true;
} catch (IllegalArgumentException iae) {
return false;
@@ -269,13 +269,12 @@ public class OperationScheduler {
public void onSuccess() {
resetTransientError();
resetPermanentError();
- long now = System.currentTimeMillis();
mStorage.edit()
.remove(PREFIX + "errorCount")
.remove(PREFIX + "lastErrorTimeMillis")
.remove(PREFIX + "permanentError")
.remove(PREFIX + "triggerTimeMillis")
- .putLong(PREFIX + "lastSuccessTimeMillis", now).commit();
+ .putLong(PREFIX + "lastSuccessTimeMillis", currentTimeMillis()).commit();
}
/**
@@ -284,8 +283,7 @@ public class OperationScheduler {
* purposes.
*/
public void onTransientError() {
- long now = System.currentTimeMillis();
- mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", now).commit();
+ mStorage.edit().putLong(PREFIX + "lastErrorTimeMillis", currentTimeMillis()).commit();
mStorage.edit().putInt(PREFIX + "errorCount",
mStorage.getInt(PREFIX + "errorCount", 0) + 1).commit();
}
@@ -338,4 +336,13 @@ public class OperationScheduler {
}
return out.append("]").toString();
}
+
+ /**
+ * Gets the current time. Can be overridden for unit testing.
+ *
+ * @return {@link System#currentTimeMillis()}
+ */
+ protected long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
}
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
index 866d1a8..955508f 100644
--- a/common/tests/src/com/android/common/OperationSchedulerTest.java
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -22,19 +22,34 @@ import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
public class OperationSchedulerTest extends AndroidTestCase {
+ /**
+ * OperationScheduler subclass which uses an artificial time.
+ * Set {@link #timeMillis} to whatever value you like.
+ */
+ private class TimeTravelScheduler extends OperationScheduler {
+ static final long DEFAULT_TIME = 1250146800000L; // 13-Aug-2009, 12:00:00 am
+ public long timeMillis = DEFAULT_TIME;
+
+ @Override
+ protected long currentTimeMillis() { return timeMillis; }
+ public TimeTravelScheduler() { super(getFreshStorage()); }
+ }
+
+ private SharedPreferences getFreshStorage() {
+ SharedPreferences sp = getContext().getSharedPreferences("OperationSchedulerTest", 0);
+ sp.edit().clear().commit();
+ return sp;
+ }
+
@MediumTest
public void testScheduler() throws Exception {
- String name = "OperationSchedulerTest.testScheduler";
- SharedPreferences storage = getContext().getSharedPreferences(name, 0);
- storage.edit().clear().commit();
-
- OperationScheduler scheduler = new OperationScheduler(storage);
+ TimeTravelScheduler scheduler = new TimeTravelScheduler();
OperationScheduler.Options options = new OperationScheduler.Options();
assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
assertEquals(0, scheduler.getLastSuccessTimeMillis());
assertEquals(0, scheduler.getLastAttemptTimeMillis());
- long beforeTrigger = System.currentTimeMillis();
+ long beforeTrigger = scheduler.timeMillis;
scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
@@ -51,33 +66,26 @@ public class OperationSchedulerTest extends AndroidTestCase {
assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
// Backoff interval after an error
- long beforeError = System.currentTimeMillis();
+ long beforeError = (scheduler.timeMillis += 100);
scheduler.onTransientError();
- long afterError = System.currentTimeMillis();
assertEquals(0, scheduler.getLastSuccessTimeMillis());
- assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
- assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
options.backoffFixedMillis = 1000000;
options.backoffIncrementalMillis = 500000;
- assertTrue(beforeError + 1500000 <= scheduler.getNextTimeMillis(options));
- assertTrue(afterError + 1500000 >= scheduler.getNextTimeMillis(options));
+ assertEquals(beforeError + 1500000, scheduler.getNextTimeMillis(options));
// Two errors: backoff interval increases
- beforeError = System.currentTimeMillis();
+ beforeError = (scheduler.timeMillis += 100);
scheduler.onTransientError();
- afterError = System.currentTimeMillis();
- assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
- assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
- assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options));
- assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options));
+ assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeError + 2000000, scheduler.getNextTimeMillis(options));
// Reset transient error: no backoff interval
scheduler.resetTransientError();
assertEquals(0, scheduler.getLastSuccessTimeMillis());
assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
- assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
- assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
// Permanent error holds true even if transient errors are reset
// However, we remember that the transient error was reset...
@@ -89,30 +97,26 @@ public class OperationSchedulerTest extends AndroidTestCase {
assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
// Success resets the trigger
- long beforeSuccess = System.currentTimeMillis();
+ long beforeSuccess = (scheduler.timeMillis += 100);
scheduler.onSuccess();
- long afterSuccess = System.currentTimeMillis();
- assertTrue(beforeSuccess <= scheduler.getLastAttemptTimeMillis());
- assertTrue(afterSuccess >= scheduler.getLastAttemptTimeMillis());
- assertTrue(beforeSuccess <= scheduler.getLastSuccessTimeMillis());
- assertTrue(afterSuccess >= scheduler.getLastSuccessTimeMillis());
+ assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeSuccess, scheduler.getLastSuccessTimeMillis());
assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
// The moratorium is not reset by success!
- scheduler.setTriggerTimeMillis(beforeSuccess + 500000);
+ scheduler.setTriggerTimeMillis(0);
assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
scheduler.setMoratoriumTimeMillis(0);
- assertEquals(beforeSuccess + 500000, scheduler.getNextTimeMillis(options));
+ assertEquals(beforeSuccess, scheduler.getNextTimeMillis(options));
// Periodic interval after success
options.periodicIntervalMillis = 250000;
- assertTrue(beforeSuccess + 250000 <= scheduler.getNextTimeMillis(options));
- assertTrue(afterSuccess + 250000 >= scheduler.getNextTimeMillis(options));
+ scheduler.setTriggerTimeMillis(Long.MAX_VALUE);
+ assertEquals(beforeSuccess + 250000, scheduler.getNextTimeMillis(options));
// Trigger minimum is also since the last success
options.minTriggerMillis = 1000000;
- assertTrue(beforeSuccess + 1000000 <= scheduler.getNextTimeMillis(options));
- assertTrue(afterSuccess + 1000000 >= scheduler.getNextTimeMillis(options));
+ assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options));
}
@SmallTest
@@ -138,23 +142,19 @@ public class OperationSchedulerTest extends AndroidTestCase {
@SmallTest
public void testMoratoriumWithHttpDate() throws Exception {
- String name = "OperationSchedulerTest.testMoratoriumWithHttpDate";
- SharedPreferences storage = getContext().getSharedPreferences(name, 0);
- storage.edit().clear().commit();
-
- OperationScheduler scheduler = new OperationScheduler(storage);
+ TimeTravelScheduler scheduler = new TimeTravelScheduler();
OperationScheduler.Options options = new OperationScheduler.Options();
- long beforeTrigger = System.currentTimeMillis();
+ long beforeTrigger = scheduler.timeMillis;
scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000);
assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options));
- long beforeMoratorium = System.currentTimeMillis();
+ long beforeMoratorium = scheduler.timeMillis;
assertTrue(scheduler.setMoratoriumTimeHttp("3000"));
- long afterMoratorium = System.currentTimeMillis();
+ long afterMoratorium = scheduler.timeMillis;
assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options));
assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options));
@@ -164,4 +164,56 @@ public class OperationSchedulerTest extends AndroidTestCase {
assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date"));
}
+
+ @SmallTest
+ public void testClockRollbackScenario() throws Exception {
+ TimeTravelScheduler scheduler = new TimeTravelScheduler();
+ OperationScheduler.Options options = new OperationScheduler.Options();
+ options.minTriggerMillis = 2000;
+
+ // First, set up a scheduler with reasons to wait: a transient
+ // error with backoff and a moratorium for a few minutes.
+
+ long beforeTrigger = scheduler.timeMillis;
+ long triggerTime = beforeTrigger - 10000000;
+ scheduler.setTriggerTimeMillis(triggerTime);
+ assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
+ assertEquals(0, scheduler.getLastAttemptTimeMillis());
+
+ long beforeSuccess = (scheduler.timeMillis += 100);
+ scheduler.onSuccess();
+ scheduler.setTriggerTimeMillis(triggerTime);
+ assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options));
+
+ long beforeError = (scheduler.timeMillis += 100);
+ scheduler.onTransientError();
+ assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options));
+
+ long beforeMoratorium = (scheduler.timeMillis += 100);
+ scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000);
+ assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+
+ // Now set the time back a few seconds.
+ // The moratorium time should still be honored.
+ long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000);
+ assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
+
+ // The rollback also moved the last-attempt clock back to the rollback time.
+ assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis());
+
+ // But if we set the time back more than a day, the moratorium
+ // resets to the maximum moratorium (a day, by default), exposing
+ // the original trigger time.
+ beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000);
+ assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
+ assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
+
+ // If we roll forward until after the re-set moratorium, then it expires.
+ scheduler.timeMillis = triggerTime + 5000000;
+ assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
+ assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
+ assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis());
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 950f34f..9019af6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -67,6 +67,8 @@ import android.location.LocationManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
+import android.net.ThrottleManager;
+import android.net.IThrottleManager;
import android.net.Uri;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
@@ -164,6 +166,7 @@ class ContextImpl extends Context {
private static AlarmManager sAlarmManager;
private static PowerManager sPowerManager;
private static ConnectivityManager sConnectivityManager;
+ private static ThrottleManager sThrottleManager;
private static WifiManager sWifiManager;
private static LocationManager sLocationManager;
private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
@@ -929,6 +932,8 @@ class ContextImpl extends Context {
return getPowerManager();
} else if (CONNECTIVITY_SERVICE.equals(name)) {
return getConnectivityManager();
+ } else if (THROTTLE_SERVICE.equals(name)) {
+ return getThrottleManager();
} else if (WIFI_SERVICE.equals(name)) {
return getWifiManager();
} else if (NOTIFICATION_SERVICE.equals(name)) {
@@ -1028,6 +1033,18 @@ class ContextImpl extends Context {
return sConnectivityManager;
}
+ private ThrottleManager getThrottleManager()
+ {
+ synchronized (sSync) {
+ if (sThrottleManager == null) {
+ IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
+ IThrottleManager service = IThrottleManager.Stub.asInterface(b);
+ sThrottleManager = new ThrottleManager(service);
+ }
+ }
+ return sThrottleManager;
+ }
+
private WifiManager getWifiManager()
{
synchronized (sSync) {
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 7b668d2..7e9873e 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -25,7 +25,7 @@ interface IUiModeManager {
* Enables the car mode. Only the system can do this.
* @hide
*/
- void enableCarMode();
+ void enableCarMode(int flags);
/**
* Disables the car mode.
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index a76dfb1..95451d6 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -116,13 +116,13 @@ public class UiModeManager {
}
/**
- * Flag for use with {@link #disableCarMode(int)}: go to the normal
- * home activity as part of the disable. Disabling this way ensures
- * a clean transition between the current activity (in car mode) and
- * the original home activity (which was typically last running without
- * being in car mode).
+ * Flag for use with {@link #enableCarMode(int)}: go to the car
+ * home activity as part of the enable. Enabling this way ensures
+ * a clean transition between the current activity (in non-car-mode) and
+ * the car home activity that will serve as home while in car mode. This
+ * will switch to the car home activity even if we are already in car mode.
*/
- public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001;
+ public static final int ENABLE_CAR_MODE_GO_CAR_HOME = 0x0001;
/**
* Force device into car mode, like it had been placed in the car dock.
@@ -133,7 +133,7 @@ public class UiModeManager {
public void enableCarMode(int flags) {
if (mService != null) {
try {
- mService.enableCarMode();
+ mService.enableCarMode(flags);
} catch (RemoteException e) {
Log.e(TAG, "disableCarMode: RemoteException", e);
}
@@ -141,6 +141,15 @@ public class UiModeManager {
}
/**
+ * Flag for use with {@link #disableCarMode(int)}: go to the normal
+ * home activity as part of the disable. Disabling this way ensures
+ * a clean transition between the current activity (in car mode) and
+ * the original home activity (which was typically last running without
+ * being in car mode).
+ */
+ public static final int DISABLE_CAR_MODE_GO_HOME = 0x0001;
+
+ /**
* Turn off special mode if currently in car mode.
* @param flags May be 0 or {@link #DISABLE_CAR_MODE_GO_HOME}.
*/
diff --git a/core/java/android/net/IThrottleManager.aidl b/core/java/android/net/IThrottleManager.aidl
index 298de6e..a12469d 100644
--- a/core/java/android/net/IThrottleManager.aidl
+++ b/core/java/android/net/IThrottleManager.aidl
@@ -35,4 +35,6 @@ interface IThrottleManager
long getCliffThreshold(String iface, int cliff);
int getCliffLevel(String iface, int cliff);
+
+ String getHelpUri();
}
diff --git a/core/java/android/net/ThrottleManager.java b/core/java/android/net/ThrottleManager.java
index 0500f6f..5fdac58 100644
--- a/core/java/android/net/ThrottleManager.java
+++ b/core/java/android/net/ThrottleManager.java
@@ -73,6 +73,12 @@ public class ThrottleManager
*/
public static final String EXTRA_THROTTLE_LEVEL = "level";
+ /**
+ * Broadcast on boot and whenever the settings change.
+ * {@hide}
+ */
+ public static final String POLICY_CHANGED_ACTION = "android.net.thrott.POLICY_CHANGED_ACTION";
+
// {@hide}
public static final int DIRECTION_TX = 0;
// {@hide}
@@ -103,6 +109,8 @@ public class ThrottleManager
// @hide
public static final int PERIOD_SECOND = 11;
+
+
/**
* returns a long of the ms from the epoch to the time the current cycle ends for the
* named interface
@@ -147,7 +155,7 @@ public class ThrottleManager
/**
* returns the number of bytes read+written after which a particular cliff
- * takes effect on the named iface. Currently only cliff #0 is supported (1 step)
+ * takes effect on the named iface. Currently only cliff #1 is supported (1 step)
* {@hide}
*/
public long getCliffThreshold(String iface, int cliff) {
@@ -160,7 +168,7 @@ public class ThrottleManager
/**
* returns the thottling bandwidth (bps) for a given cliff # on the named iface.
- * only cliff #0 is currently supported.
+ * only cliff #1 is currently supported.
* {@hide}
*/
public int getCliffLevel(String iface, int cliff) {
@@ -171,6 +179,19 @@ public class ThrottleManager
}
}
+ /**
+ * returns the help URI for throttling
+ * {@hide}
+ */
+ public String getHelpUri() {
+ try {
+ return mService.getHelpUri();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+
private IThrottleManager mService;
/**
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 3517737..e07ee59 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -16,6 +16,7 @@
package android.net.http;
+import com.android.internal.http.HttpDateTime;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
@@ -444,4 +445,22 @@ public final class AndroidHttpClient implements HttpClient {
return builder.toString();
}
+
+ /**
+ * Returns the date of the given HTTP date string. This method can identify
+ * and parse the date formats emitted by common HTTP servers, such as
+ * <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>,
+ * <a href="http://www.ietf.org/rfc/rfc0850.txt">RFC 850</a>,
+ * <a href="http://www.ietf.org/rfc/rfc1036.txt">RFC 1036</a>,
+ * <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a> and
+ * <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/asctime.html">ANSI
+ * C's asctime()</a>.
+ *
+ * @return the number of milliseconds since Jan. 1, 1970, midnight GMT.
+ * @throws IllegalArgumentException if {@code dateString} is not a date or
+ * of an unsupported format.
+ */
+ public static long parseDate(String dateString) {
+ return HttpDateTime.parse(dateString);
+ }
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b3ec114..b6dc1b5 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -304,9 +304,7 @@ public class RecoverySystem {
/**
* Reboots the device in order to install the given update
* package.
- * Requires the {@link android.Manifest.permission#REBOOT}
- * and {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}
- * permissions.
+ * Requires the {@link android.Manifest.permission#REBOOT} permission.
*
* @param context the Context to use
* @param packageFile the update package to install. Currently
@@ -337,9 +335,7 @@ public class RecoverySystem {
* sometimes called a "factory reset", which is something of a
* misnomer because the system partition is not restored to its
* factory state.
- * Requires the {@link android.Manifest.permission#REBOOT}
- * and {@link android.Manifest.permission#ACCESS_CACHE_FILESYSTEM}
- * permissions.
+ * Requires the {@link android.Manifest.permission#REBOOT} permission.
*
* @param context the Context to use
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index eb14815..e640005 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3333,6 +3333,13 @@ public final class Settings {
public static final String THROTTLE_IFACE = "throttle_iface";
/**
+ * Help URI for data throttling policy
+ * @hide
+ */
+ public static final String THROTTLE_HELP_URI = "throttle_help_uri";
+
+
+ /**
* @hide
*/
public static final String[] SETTINGS_TO_BACKUP = {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index e56a6fe..bf94707 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -766,7 +766,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// make sure touch mode code executes by setting cached value
// to opposite of the added touch mode.
mAttachInfo.mInTouchMode = !mAddedTouchMode;
- ensureTouchModeLocally(mAddedTouchMode, false);
+ ensureTouchModeLocally(mAddedTouchMode);
} else {
if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
mAttachInfo.mContentInsets.set(mPendingContentInsets);
@@ -983,7 +983,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
- (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0, true);
+ (relayoutResult&WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.mMeasuredWidth
|| mHeight != host.mMeasuredHeight || contentInsetsChanged) {
childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
@@ -1043,13 +1043,6 @@ public final class ViewRoot extends Handler implements ViewParent,
startTime = SystemClock.elapsedRealtime();
}
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
- if (mFirst) {
- if (mAddedTouchMode) {
- enterTouchMode();
- } else {
- leaveTouchMode();
- }
- }
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
if (!host.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_LAYOUT)) {
@@ -1899,7 +1892,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mHasWindowFocus = hasWindowFocus;
if (hasWindowFocus) {
boolean inTouchMode = msg.arg2 != 0;
- ensureTouchModeLocally(inTouchMode, true);
+ ensureTouchModeLocally(inTouchMode);
if (mGlWanted) {
checkEglErrors();
@@ -2009,17 +2002,16 @@ public final class ViewRoot extends Handler implements ViewParent,
}
// handle the change
- return ensureTouchModeLocally(inTouchMode, true);
+ return ensureTouchModeLocally(inTouchMode);
}
/**
* Ensure that the touch mode for this window is set, and if it is changing,
* take the appropriate action.
* @param inTouchMode Whether we want to be in touch mode.
- * @param dispatchFocus
* @return True if the touch mode changed and focus changed was changed as a result
*/
- private boolean ensureTouchModeLocally(boolean inTouchMode, boolean dispatchFocus) {
+ private boolean ensureTouchModeLocally(boolean inTouchMode) {
if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
+ "touch mode is " + mAttachInfo.mInTouchMode);
@@ -2028,7 +2020,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mInTouchMode = inTouchMode;
mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);
- return dispatchFocus && (inTouchMode) ? enterTouchMode() : leaveTouchMode();
+ return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
}
private boolean enterTouchMode() {
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index d19805e..d5058b0 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -17,8 +17,8 @@
package android.webkit;
import android.content.Context;
+import android.net.http.AndroidHttpClient;
import android.net.http.Headers;
-import android.net.http.HttpDateTime;
import android.os.FileUtils;
import android.util.Log;
import java.io.File;
@@ -716,7 +716,7 @@ public final class CacheManager {
ret.expiresString = headers.getExpires();
if (ret.expiresString != null) {
try {
- ret.expires = HttpDateTime.parse(ret.expiresString);
+ ret.expires = AndroidHttpClient.parseDate(ret.expiresString);
} catch (IllegalArgumentException ex) {
// Take care of the special "-1" and "0" cases
if ("-1".equals(ret.expiresString)
@@ -831,7 +831,7 @@ public final class CacheManager {
// 24 * 60 * 60 * 1000
long lastmod = System.currentTimeMillis() + 86400000;
try {
- lastmod = HttpDateTime.parse(ret.lastModified);
+ lastmod = AndroidHttpClient.parseDate(ret.lastModified);
} catch (IllegalArgumentException ex) {
Log.e(LOGTAG, "illegal lastModified: " + ret.lastModified);
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 758a152..ac20791 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -18,7 +18,7 @@ package android.webkit;
import android.net.ParseException;
import android.net.WebAddress;
-import android.net.http.HttpDateTime;
+import android.net.http.AndroidHttpClient;
import android.util.Log;
@@ -939,7 +939,7 @@ public final class CookieManager {
}
if (name.equals(EXPIRES)) {
try {
- cookie.expires = HttpDateTime.parse(value);
+ cookie.expires = AndroidHttpClient.parseDate(value);
} catch (IllegalArgumentException ex) {
Log.e(LOGTAG,
"illegal format for expires: " + value);
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 1130e95..12b8c74 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -380,7 +380,8 @@ class LoadListener extends Handler implements EventHandler {
}
// At this point, mMimeType has been set to non-null.
if (mIsMainPageLoader && mIsMainResourceLoader && mUserGesture &&
- Pattern.matches(XML_MIME_TYPE, mMimeType)) {
+ Pattern.matches(XML_MIME_TYPE, mMimeType) &&
+ !mMimeType.equalsIgnoreCase("application/xhtml+xml")) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse(url()), mMimeType);
ResolveInfo info = mContext.getPackageManager().resolveActivity(i,
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4233af1..bbe52a3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -475,6 +475,7 @@ public class WebView extends AbsoluteLayout
private static final int MOTIONLESS_FALSE = 0;
private static final int MOTIONLESS_PENDING = 1;
private static final int MOTIONLESS_TRUE = 2;
+ private static final int MOTIONLESS_IGNORE = 3;
private int mHeldMotionless;
// whether support multi-touch
@@ -1274,30 +1275,57 @@ public class WebView extends AbsoluteLayout
* overwritten with this WebView's picture data.
* @return True if the picture was successfully saved.
*/
- public boolean savePicture(Bundle b, File dest) {
+ public boolean savePicture(Bundle b, final File dest) {
if (dest == null || b == null) {
return false;
}
final Picture p = capturePicture();
- try {
- final FileOutputStream out = new FileOutputStream(dest);
- p.writeToStream(out);
- out.close();
- // now update the bundle
- b.putInt("scrollX", mScrollX);
- b.putInt("scrollY", mScrollY);
- b.putFloat("scale", mActualScale);
- b.putFloat("textwrapScale", mTextWrapScale);
- b.putBoolean("overview", mInZoomOverview);
- return true;
- } catch (FileNotFoundException e){
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
- return false;
+ // Use a temporary file while writing to ensure the destination file
+ // contains valid data.
+ final File temp = new File(dest.getPath() + ".writing");
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ FileOutputStream out = new FileOutputStream(temp);
+ p.writeToStream(out);
+ out.close();
+ // Writing the picture succeeded, rename the temporary file
+ // to the destination.
+ temp.renameTo(dest);
+ } catch (Exception e) {
+ // too late to do anything about it.
+ } finally {
+ temp.delete();
+ }
+ }
+ }).start();
+ // now update the bundle
+ b.putInt("scrollX", mScrollX);
+ b.putInt("scrollY", mScrollY);
+ b.putFloat("scale", mActualScale);
+ b.putFloat("textwrapScale", mTextWrapScale);
+ b.putBoolean("overview", mInZoomOverview);
+ return true;
+ }
+
+ private void restoreHistoryPictureFields(Picture p, Bundle b) {
+ int sx = b.getInt("scrollX", 0);
+ int sy = b.getInt("scrollY", 0);
+ float scale = b.getFloat("scale", 1.0f);
+ mDrawHistory = true;
+ mHistoryPicture = p;
+ mScrollX = sx;
+ mScrollY = sy;
+ mHistoryWidth = Math.round(p.getWidth() * scale);
+ mHistoryHeight = Math.round(p.getHeight() * scale);
+ // as getWidth() / getHeight() of the view are not available yet, set up
+ // mActualScale, so that when onSizeChanged() is called, the rest will
+ // be set correctly
+ mActualScale = scale;
+ mInvActualScale = 1 / scale;
+ mTextWrapScale = b.getFloat("textwrapScale", scale);
+ mInZoomOverview = b.getBoolean("overview");
+ invalidate();
}
/**
@@ -1311,42 +1339,35 @@ public class WebView extends AbsoluteLayout
if (src == null || b == null) {
return false;
}
- if (src.exists()) {
- Picture p = null;
- try {
- final FileInputStream in = new FileInputStream(src);
- p = Picture.createFromStream(in);
- in.close();
- } catch (FileNotFoundException e){
- e.printStackTrace();
- } catch (RuntimeException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (p != null) {
- int sx = b.getInt("scrollX", 0);
- int sy = b.getInt("scrollY", 0);
- float scale = b.getFloat("scale", 1.0f);
- mDrawHistory = true;
- mHistoryPicture = p;
- mScrollX = sx;
- mScrollY = sy;
- mHistoryWidth = Math.round(p.getWidth() * scale);
- mHistoryHeight = Math.round(p.getHeight() * scale);
- // as getWidth() / getHeight() of the view are not
- // available yet, set up mActualScale, so that when
- // onSizeChanged() is called, the rest will be set
- // correctly
- mActualScale = scale;
- mInvActualScale = 1 / scale;
- mTextWrapScale = b.getFloat("textwrapScale", scale);
- mInZoomOverview = b.getBoolean("overview");
- invalidate();
- return true;
- }
+ if (!src.exists()) {
+ return false;
}
- return false;
+ try {
+ final FileInputStream in = new FileInputStream(src);
+ final Bundle copy = new Bundle(b);
+ new Thread(new Runnable() {
+ public void run() {
+ final Picture p = Picture.createFromStream(in);
+ if (p != null) {
+ // Post a runnable on the main thread to update the
+ // history picture fields.
+ mPrivateHandler.post(new Runnable() {
+ public void run() {
+ restoreHistoryPictureFields(p, copy);
+ }
+ });
+ }
+ try {
+ in.close();
+ } catch (Exception e) {
+ // Nothing we can do now.
+ }
+ }
+ }).start();
+ } catch (FileNotFoundException e){
+ e.printStackTrace();
+ }
+ return true;
}
/**
@@ -3339,6 +3360,7 @@ public class WebView extends AbsoluteLayout
if (null == mWebViewCore) return; // CallbackProxy may trigger this
if (mDrawHistory && mWebViewCore.pictureReady()) {
mDrawHistory = false;
+ mHistoryPicture = null;
invalidate();
int oldScrollX = mScrollX;
int oldScrollY = mScrollY;
@@ -4902,9 +4924,6 @@ public class WebView extends AbsoluteLayout
case TOUCH_DRAG_MODE:
mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
- mHeldMotionless = MOTIONLESS_TRUE;
- // redraw in high-quality, as we're done dragging
- invalidate();
// if the user waits a while w/o moving before the
// up, we don't want to do a fling
if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
@@ -4916,9 +4935,16 @@ public class WebView extends AbsoluteLayout
+ mDeferTouchProcess);
}
mVelocityTracker.addMovement(ev);
+ // set to MOTIONLESS_IGNORE so that it won't keep
+ // removing and sending message in
+ // drawCoreAndCursorRing()
+ mHeldMotionless = MOTIONLESS_IGNORE;
doFling();
break;
}
+ // redraw in high-quality, as we're done dragging
+ mHeldMotionless = MOTIONLESS_TRUE;
+ invalidate();
// fall through
case TOUCH_DRAG_START_MODE:
// TOUCH_DRAG_START_MODE should not happen for the real
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 873dc67..959e982 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -330,7 +330,7 @@ public class ScrollView extends FrameLayout {
mTempRect.setEmpty();
if (!canScroll()) {
- if (isFocused()) {
+ if (isFocused() && event.getKeyCode() != KeyEvent.KEYCODE_BACK) {
View currentFocused = findFocus();
if (currentFocused == this) currentFocused = null;
View nextFocused = FocusFinder.getInstance().findNextFocus(this,
diff --git a/core/java/android/net/http/HttpDateTime.java b/core/java/com/android/internal/http/HttpDateTime.java
index c7a31ee..8ebd4aa 100644
--- a/core/java/android/net/http/HttpDateTime.java
+++ b/core/java/com/android/internal/http/HttpDateTime.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net.http;
+package com.android.internal.http;
import android.text.format.Time;
@@ -82,7 +82,7 @@ public final class HttpDateTime {
int second;
}
- public static Long parse(String timeString)
+ public static long parse(String timeString)
throws IllegalArgumentException {
int date = 1;
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index db8fdf2..ff46bdd 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -32,6 +32,7 @@ namespace android {
// Returns an ASCII decimal number read from the specified file, -1 on error.
static jlong readNumber(char const* filename) {
+#ifdef HAVE_ANDROID_OS
char buf[80];
int fd = open(filename, O_RDONLY);
if (fd < 0) {
@@ -49,6 +50,9 @@ static jlong readNumber(char const* filename) {
close(fd);
buf[len] = '\0';
return atoll(buf);
+#else // Simulator
+ return -1;
+#endif
}
// Return the number from the first file which exists and contains data
@@ -60,6 +64,7 @@ static jlong tryBoth(char const* a, char const* b) {
// Returns the sum of numbers from the specified path under /sys/class/net/*,
// -1 if no such file exists.
static jlong readTotal(char const* suffix) {
+#ifdef HAVE_ANDROID_OS
char filename[PATH_MAX] = "/sys/class/net/";
DIR *dir = opendir(filename);
if (dir == NULL) {
@@ -81,6 +86,9 @@ static jlong readTotal(char const* suffix) {
closedir(dir);
return total;
+#else // Simulator
+ return -1;
+#endif
}
// Mobile stats get accessed a lot more often than total stats.
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 75f6cb2..e43478c 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -165,14 +165,32 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
jint *tagValues = env->GetIntArrayElements(tags, NULL);
uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+ struct timeval timeout = {0, 0};
+ fd_set readset;
+ FD_ZERO(&readset);
+
for (;;) {
+ // Use a short select() to try to avoid problems hanging on read().
+ // This means we block for 5ms at the end of the log -- oh well.
+ timeout.tv_usec = 5000;
+ FD_SET(fd, &readset);
+ int r = select(fd + 1, &readset, NULL, NULL, &timeout);
+ if (r == 0) {
+ break; // no more events
+ } else if (r < 0 && errno == EINTR) {
+ continue; // interrupted by signal, try again
+ } else if (r < 0) {
+ jniThrowIOException(env, errno); // Will throw on return
+ break;
+ }
+
int len = read(fd, buf, sizeof(buf));
if (len == 0 || (len < 0 && errno == EAGAIN)) {
- break;
+ break; // no more events
+ } else if (len < 0 && errno == EINTR) {
+ continue; // interrupted by signal, try again
} else if (len < 0) {
- // This calls env->ThrowNew(), which doesn't throw an exception
- // now, but sets a flag to trigger an exception after we return.
- jniThrowIOException(env, errno);
+ jniThrowIOException(env, errno); // Will throw on return
break;
} else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) {
jniThrowException(env, "java/io/IOException", "Event too short");
diff --git a/core/res/res/drawable-mdpi/stat_notify_chat.png b/core/res/res/drawable-mdpi/stat_notify_chat.png
index 097a979..068b7ec 100644
--- a/core/res/res/drawable-mdpi/stat_notify_chat.png
+++ b/core/res/res/drawable-mdpi/stat_notify_chat.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 36dc07c..45d7aea 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2260,11 +2260,11 @@
<!-- Strings for throttling notification -->
<!-- Shown when the user is in danger of being throttled -->
- <string name="throttle_warning_notification_title">Excessive data use warning</string>
- <string name="throttle_warning_notification_message">If your data use pattern continues you may be subject to bandwidth restrictions - touch for more information</string>
+ <string name="throttle_warning_notification_title">High mobile data use</string>
+ <string name="throttle_warning_notification_message">Touch to learn more about mobile data use</string>
<!-- Strings for throttling notification -->
<!-- Shown when the users bandwidth is reduced because of excessive data use -->
- <string name="throttled_notification_title">Bandwidth Restricted</string>
- <string name="throttled_notification_message">Your mobile data bandwidth is being reduced because of excessive data use - touch for more information</string>
+ <string name="throttled_notification_title">Mobile data limit exceeded</string>
+ <string name="throttled_notification_message">Touch to learn more about mobile data use</string>
</resources>
diff --git a/data/fonts/DroidSansArabic.ttf b/data/fonts/DroidSansArabic.ttf
index c179bc6..660e2a9 100644
--- a/data/fonts/DroidSansArabic.ttf
+++ b/data/fonts/DroidSansArabic.ttf
Binary files differ
diff --git a/data/fonts/DroidSansHebrew.ttf b/data/fonts/DroidSansHebrew.ttf
index 0b48628..8d77e3e 100644
--- a/data/fonts/DroidSansHebrew.ttf
+++ b/data/fonts/DroidSansHebrew.ttf
Binary files differ
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 7166c89..2414e8d 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1867,7 +1867,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// The first time a track is added we wait
// for all its buffers to be filled before processing it
if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
- !track->isPaused())
+ !track->isPaused() && !track->isTerminated())
{
//LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index d688e2c..ca0c68c 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -58,13 +58,27 @@ ID3::Version ID3::version() const {
return mVersion;
}
+// static
+bool ID3::ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x) {
+ *x = 0;
+ for (int32_t i = 0; i < 4; ++i) {
+ if (encoded[i] & 0x80) {
+ return false;
+ }
+
+ *x = ((*x) << 7) | encoded[i];
+ }
+
+ return true;
+}
+
bool ID3::parseV2(const sp<DataSource> &source) {
- struct id3_header {
- char id[3];
- uint8_t version_major;
- uint8_t version_minor;
- uint8_t flags;
- uint8_t enc_size[4];
+struct id3_header {
+ char id[3];
+ uint8_t version_major;
+ uint8_t version_minor;
+ uint8_t flags;
+ uint8_t enc_size[4];
};
id3_header header;
@@ -100,17 +114,18 @@ bool ID3::parseV2(const sp<DataSource> &source) {
// set, we cannot guarantee to understand the tag format.
return false;
}
+ } else if (header.version_major == 4) {
+ if (header.flags & 0x0f) {
+ // The lower 4 bits are undefined in this spec.
+ return false;
+ }
} else {
return false;
}
- size_t size = 0;
- for (int32_t i = 0; i < 4; ++i) {
- if (header.enc_size[i] & 0x80) {
- return false;
- }
-
- size = (size << 7) | header.enc_size[i];
+ size_t size;
+ if (!ParseSyncsafeInteger(header.enc_size, &size)) {
+ return false;
}
if (size > kMaxMetadataSize) {
@@ -178,13 +193,42 @@ bool ID3::parseV2(const sp<DataSource> &source) {
LOGV("have crc");
}
}
+ } else if (header.version_major == 4 && (header.flags & 0x40)) {
+ // Version 2.4 has an optional extended header, that's different
+ // from Version 2.3's...
+
+ if (mSize < 4) {
+ free(mData);
+ mData = NULL;
+
+ return false;
+ }
+
+ size_t ext_size;
+ if (!ParseSyncsafeInteger(mData, &ext_size)) {
+ free(mData);
+ mData = NULL;
+
+ return false;
+ }
+
+ if (ext_size < 6 || ext_size > mSize) {
+ free(mData);
+ mData = NULL;
+
+ return false;
+ }
+
+ mFirstFrameOffset = ext_size;
}
if (header.version_major == 2) {
mVersion = ID3_V2_2;
- } else {
- CHECK_EQ(header.version_major, 3);
+ } else if (header.version_major == 3) {
mVersion = ID3_V2_3;
+ } else {
+ CHECK_EQ(header.version_major, 4);
+ mVersion = ID3_V2_4;
}
return true;
@@ -242,7 +286,7 @@ void ID3::Iterator::getID(String8 *id) const {
if (mParent.mVersion == ID3_V2_2) {
id->setTo((const char *)&mParent.mData[mOffset], 3);
- } else if (mParent.mVersion == ID3_V2_3) {
+ } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
id->setTo((const char *)&mParent.mData[mOffset], 4);
} else {
CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
@@ -346,6 +390,26 @@ void ID3::Iterator::getString(String8 *id) const {
if (*mFrameData == 0x00) {
// ISO 8859-1
convertISO8859ToString8(mFrameData + 1, n, id);
+ } else if (*mFrameData == 0x03) {
+ // UTF-8
+ id->setTo((const char *)(mFrameData + 1), n);
+ } else if (*mFrameData == 0x02) {
+ // UTF-16 BE, no byte order mark.
+ // API wants number of characters, not number of bytes...
+ int len = n / 2;
+ const char16_t *framedata = (const char16_t *) (mFrameData + 1);
+ char16_t *framedatacopy = NULL;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ framedatacopy = new char16_t[len];
+ for (int i = 0; i < len; i++) {
+ framedatacopy[i] = bswap_16(framedata[i]);
+ }
+ framedata = framedatacopy;
+#endif
+ id->setTo(framedata, len);
+ if (framedatacopy != NULL) {
+ delete[] framedatacopy;
+ }
} else {
// UCS-2
// API wants number of characters, not number of bytes...
@@ -387,7 +451,7 @@ const uint8_t *ID3::Iterator::getData(size_t *length) const {
size_t ID3::Iterator::getHeaderLength() const {
if (mParent.mVersion == ID3_V2_2) {
return 6;
- } else if (mParent.mVersion == ID3_V2_3) {
+ } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) {
return 10;
} else {
CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
@@ -435,7 +499,8 @@ void ID3::Iterator::findFrame() {
if (!strcmp(id, mID)) {
break;
}
- } else if (mParent.mVersion == ID3_V2_3) {
+ } else if (mParent.mVersion == ID3_V2_3
+ || mParent.mVersion == ID3_V2_4) {
if (mOffset + 10 > mParent.mSize) {
return;
}
@@ -444,7 +509,17 @@ void ID3::Iterator::findFrame() {
return;
}
- mFrameSize = 10 + U32_AT(&mParent.mData[mOffset + 4]);
+ size_t baseSize;
+ if (mParent.mVersion == ID3_V2_4) {
+ if (!ParseSyncsafeInteger(
+ &mParent.mData[mOffset + 4], &baseSize)) {
+ return;
+ }
+ } else {
+ baseSize = U32_AT(&mParent.mData[mOffset + 4]);
+ }
+
+ mFrameSize = 10 + baseSize;
if (mOffset + mFrameSize > mParent.mSize) {
LOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)",
@@ -452,6 +527,20 @@ void ID3::Iterator::findFrame() {
return;
}
+ uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]);
+
+ if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000e))
+ || (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) {
+ // Compression, Encryption or per-Frame unsynchronization
+ // are not supported at this time.
+
+ LOGV("Skipping unsupported frame (compression, encryption "
+ "or per-frame unsynchronization flagged");
+
+ mOffset += mFrameSize;
+ continue;
+ }
+
mFrameData = &mParent.mData[mOffset + 10];
if (!mID) {
@@ -518,8 +607,8 @@ void ID3::Iterator::findFrame() {
}
static size_t StringSize(const uint8_t *start, uint8_t encoding) {
- if (encoding== 0x00) {
- // ISO 8859-1
+ if (encoding == 0x00 || encoding == 0x03) {
+ // ISO 8859-1 or UTF-8
return strlen((const char *)start) + 1;
}
@@ -537,13 +626,15 @@ ID3::getAlbumArt(size_t *length, String8 *mime) const {
*length = 0;
mime->setTo("");
- Iterator it(*this, mVersion == ID3_V2_3 ? "APIC" : "PIC");
+ Iterator it(
+ *this,
+ (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) ? "APIC" : "PIC");
while (!it.done()) {
size_t size;
const uint8_t *data = it.getData(&size);
- if (mVersion == ID3_V2_3) {
+ if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
uint8_t encoding = data[0];
mime->setTo((const char *)&data[1]);
size_t mimeLen = strlen((const char *)&data[1]) + 1;
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index da042a3..c6b1a8b 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -31,7 +31,8 @@ struct ID3 {
ID3_V1,
ID3_V1_1,
ID3_V2_2,
- ID3_V2_3
+ ID3_V2_3,
+ ID3_V2_4,
};
ID3(const sp<DataSource> &source);
@@ -80,6 +81,8 @@ private:
bool parseV2(const sp<DataSource> &source);
void removeUnsynchronization();
+ static bool ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x);
+
ID3(const ID3 &);
ID3 &operator=(const ID3 &);
};
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index ee6067a..23bbb87 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -439,7 +439,7 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
@MediumTest
public void testPrepareAsyncReset() throws Exception {
- assertTrue(MediaFrameworkTest.checkStreamingServer());
+ //assertTrue(MediaFrameworkTest.checkStreamingServer());
boolean isReset = CodecTest.prepareAsyncReset(MediaNames.STREAM_MP3);
assertTrue("PrepareAsync Reset", isReset);
}
@@ -472,7 +472,7 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
@LargeTest
public void testStreamPrepareAsyncCallback() throws Exception {
- assertTrue(MediaFrameworkTest.checkStreamingServer());
+ //assertTrue(MediaFrameworkTest.checkStreamingServer());
boolean onPrepareSuccess =
CodecTest.prepareAsyncCallback(MediaNames.STREAM_H264_480_360_1411k, false);
assertTrue("StreamH264PrepareAsyncCallback", onPrepareSuccess);
@@ -480,7 +480,7 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
@LargeTest
public void testStreamPrepareAsyncCallbackReset() throws Exception {
- assertTrue(MediaFrameworkTest.checkStreamingServer());
+ //assertTrue(MediaFrameworkTest.checkStreamingServer());
boolean onPrepareSuccess =
CodecTest.prepareAsyncCallback(MediaNames.STREAM_H264_480_360_1411k, true);
assertTrue("StreamH264PrepareAsyncCallback", onPrepareSuccess);
diff --git a/preloaded-classes b/preloaded-classes
index 54c7303..8114562 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -313,7 +313,7 @@ android.net.http.AndroidHttpClientConnection
android.net.http.EventHandler
android.net.http.Headers
android.net.http.HttpsConnection
-android.net.http.HttpDateTime
+com.android.internal.http.HttpDateTime
android.net.http.Request
android.net.http.RequestQueue
android.net.http.SslCertificate
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index 26b57bf..77bddb0 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -122,8 +122,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
ParcelFileDescriptor newState) {
if (DEBUG) Slog.v(TAG, "onBackup()");
- ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
- DataOutputStream outWriter = new DataOutputStream(bufStream);
+ ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); // we'll reuse these
+ DataOutputStream outputBufferStream = new DataOutputStream(outputBuffer);
parseStateFile(oldState);
// If the stored version string differs, we need to re-backup all
@@ -148,11 +148,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
*/
if (!mExisting.contains(GLOBAL_METADATA_KEY)) {
if (DEBUG) Slog.v(TAG, "Storing global metadata key");
- outWriter.writeInt(Build.VERSION.SDK_INT);
- outWriter.writeUTF(Build.VERSION.INCREMENTAL);
- byte[] metadata = bufStream.toByteArray();
- data.writeEntityHeader(GLOBAL_METADATA_KEY, metadata.length);
- data.writeEntityData(metadata, metadata.length);
+ outputBufferStream.writeInt(Build.VERSION.SDK_INT);
+ outputBufferStream.writeUTF(Build.VERSION.INCREMENTAL);
+ writeEntity(data, GLOBAL_METADATA_KEY, outputBuffer.toByteArray());
} else {
if (DEBUG) Slog.v(TAG, "Global metadata key already stored");
// don't consider it to have been skipped/deleted
@@ -178,49 +176,46 @@ public class PackageManagerBackupAgent extends BackupAgent {
continue;
}
- boolean doBackup = false;
- if (!mExisting.contains(packName)) {
- // We haven't backed up this app before
- doBackup = true;
- } else {
- // We *have* backed this one up before. Check whether the version
+ if (mExisting.contains(packName)) {
+ // We have backed up this app before. Check whether the version
// of the backup matches the version of the current app; if they
// don't match, the app has been updated and we need to store its
// metadata again. In either case, take it out of mExisting so that
// we don't consider it deleted later.
- if (info.versionCode != mStateVersions.get(packName).versionCode) {
- doBackup = true;
- }
mExisting.remove(packName);
+ if (info.versionCode == mStateVersions.get(packName).versionCode) {
+ continue;
+ }
+ }
+
+ if (info.signatures == null || info.signatures.length == 0)
+ {
+ Slog.w(TAG, "Not backing up package " + packName
+ + " since it appears to have no signatures.");
+ continue;
}
- if (doBackup) {
- // We need to store this app's metadata
- /*
- * Metadata for each package:
- *
- * int version -- [4] the package's versionCode
- * byte[] signatures -- [len] flattened Signature[] of the package
- */
-
- // marshal the version code in a canonical form
- bufStream.reset();
- outWriter.writeInt(info.versionCode);
- byte[] versionBuf = bufStream.toByteArray();
-
- byte[] sigs = flattenSignatureArray(info.signatures);
-
- if (DEBUG) {
- Slog.v(TAG, "+ metadata for " + packName
- + " version=" + info.versionCode
- + " versionLen=" + versionBuf.length
- + " sigsLen=" + sigs.length);
- }
- // Now we can write the backup entity for this package
- data.writeEntityHeader(packName, versionBuf.length + sigs.length);
- data.writeEntityData(versionBuf, versionBuf.length);
- data.writeEntityData(sigs, sigs.length);
+ // We need to store this app's metadata
+ /*
+ * Metadata for each package:
+ *
+ * int version -- [4] the package's versionCode
+ * byte[] signatures -- [len] flattened Signature[] of the package
+ */
+
+ // marshal the version code in a canonical form
+ outputBuffer.reset();
+ outputBufferStream.writeInt(info.versionCode);
+ writeSignatureArray(outputBufferStream, info.signatures);
+
+ if (DEBUG) {
+ Slog.v(TAG, "+ writing metadata for " + packName
+ + " version=" + info.versionCode
+ + " entityLen=" + outputBuffer.size());
}
+
+ // Now we can write the backup entity for this package
+ writeEntity(data, packName, outputBuffer.toByteArray());
}
}
@@ -245,6 +240,12 @@ public class PackageManagerBackupAgent extends BackupAgent {
// Finally, write the new state blob -- just the list of all apps we handled
writeStateFile(mAllPackages, newState);
}
+
+ private static void writeEntity(BackupDataOutput data, String key, byte[] bytes)
+ throws IOException {
+ data.writeEntityHeader(key, bytes.length);
+ data.writeEntityData(bytes, bytes.length);
+ }
// "Restore" here is a misnomer. What we're really doing is reading back the
// set of app signatures associated with each backed-up app in this restore
@@ -263,13 +264,13 @@ public class PackageManagerBackupAgent extends BackupAgent {
if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize);
// generic setup to parse any entity data
- byte[] dataBuf = new byte[dataSize];
- data.readEntityData(dataBuf, 0, dataSize);
- ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
- DataInputStream in = new DataInputStream(baStream);
+ byte[] inputBytes = new byte[dataSize];
+ data.readEntityData(inputBytes, 0, dataSize);
+ ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes);
+ DataInputStream inputBufferStream = new DataInputStream(inputBuffer);
if (key.equals(GLOBAL_METADATA_KEY)) {
- int storedSdkVersion = in.readInt();
+ int storedSdkVersion = inputBufferStream.readInt();
if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion);
if (storedSystemVersion > Build.VERSION.SDK_INT) {
// returning before setting the sig map means we rejected the restore set
@@ -277,7 +278,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
return;
}
mStoredSdkVersion = storedSdkVersion;
- mStoredIncrementalVersion = in.readUTF();
+ mStoredIncrementalVersion = inputBufferStream.readUTF();
mHasMetadata = true;
if (DEBUG) {
Slog.i(TAG, "Restore set version " + storedSystemVersion
@@ -287,13 +288,19 @@ public class PackageManagerBackupAgent extends BackupAgent {
}
} else {
// it's a file metadata record
- int versionCode = in.readInt();
- Signature[] sigs = unflattenSignatureArray(in);
+ int versionCode = inputBufferStream.readInt();
+ Signature[] sigs = readSignatureArray(inputBufferStream);
if (DEBUG) {
- Slog.i(TAG, " restored metadata for " + key
+ Slog.i(TAG, " read metadata for " + key
+ " dataSize=" + dataSize
+ " versionCode=" + versionCode + " sigs=" + sigs);
}
+
+ if (sigs == null || sigs.length == 0) {
+ Slog.w(TAG, "Not restoring package " + key
+ + " since it appears to have no signatures.");
+ continue;
+ }
ApplicationInfo app = new ApplicationInfo();
app.packageName = key;
@@ -306,63 +313,50 @@ public class PackageManagerBackupAgent extends BackupAgent {
mRestoredSignatures = sigMap;
}
-
- // Util: convert an array of Signatures into a flattened byte buffer. The
- // flattened format contains enough info to reconstruct the signature array.
- private byte[] flattenSignatureArray(Signature[] allSigs) {
- ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
- DataOutputStream out = new DataOutputStream(outBuf);
-
- // build the set of subsidiary buffers
- try {
- // first the # of signatures in the array
- out.writeInt(allSigs.length);
-
- // then the signatures themselves, length + flattened buffer
- for (Signature sig : allSigs) {
- byte[] flat = sig.toByteArray();
- out.writeInt(flat.length);
- out.write(flat);
- }
- } catch (IOException e) {
- // very strange; we're writing to memory here. abort.
- return null;
+ private static void writeSignatureArray(DataOutputStream out, Signature[] sigs)
+ throws IOException {
+ // write the number of signatures in the array
+ out.writeInt(sigs.length);
+
+ // write the signatures themselves, length + flattened buffer
+ for (Signature sig : sigs) {
+ byte[] flat = sig.toByteArray();
+ out.writeInt(flat.length);
+ out.write(flat);
}
-
- return outBuf.toByteArray();
}
- private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
- Signature[] sigs = null;
-
+ private static Signature[] readSignatureArray(DataInputStream in) {
try {
- int num = in.readInt();
+ int num;
+ try {
+ num = in.readInt();
+ } catch (EOFException e) {
+ // clean termination
+ Slog.w(TAG, "Read empty signature block");
+ return null;
+ }
+
if (DEBUG) Slog.v(TAG, " ... unflatten read " + num);
-
+
// Sensical?
if (num > 20) {
Slog.e(TAG, "Suspiciously large sig count in restore data; aborting");
throw new IllegalStateException("Bad restore state");
}
-
- sigs = new Signature[num];
+
+ Signature[] sigs = new Signature[num];
for (int i = 0; i < num; i++) {
int len = in.readInt();
byte[] flatSig = new byte[len];
in.read(flatSig);
sigs[i] = new Signature(flatSig);
}
- } catch (EOFException e) {
- // clean termination
- if (sigs == null) {
- Slog.w(TAG, "Empty signature block found");
- }
+ return sigs;
} catch (IOException e) {
- Slog.e(TAG, "Unable to unflatten sigs");
+ Slog.e(TAG, "Unable to read signatures");
return null;
}
-
- return sigs;
}
// Util: parse out an existing state file into a usable structure
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index e6663d4..3908389 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2496,16 +2496,25 @@ class PackageManagerService extends IPackageManager.Stub {
private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps,
PackageParser.Package pkg, File srcFile, int parseFlags) {
if (GET_CERTIFICATES) {
- if (ps == null || !ps.codePath.equals(srcFile)
- || ps.getTimeStamp() != srcFile.lastModified()) {
- Log.i(TAG, srcFile.toString() + " changed; collecting certs");
- if (!pp.collectCertificates(pkg, parseFlags)) {
- mLastScanError = pp.getParseError();
- return false;
+ if (ps != null
+ && ps.codePath.equals(srcFile)
+ && ps.getTimeStamp() == srcFile.lastModified()) {
+ if (ps.signatures.mSignatures != null
+ && ps.signatures.mSignatures.length != 0) {
+ // Optimization: reuse the existing cached certificates
+ // if the package appears to be unchanged.
+ pkg.mSignatures = ps.signatures.mSignatures;
+ return true;
}
+
+ Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them.");
} else {
- // Lets implicitly assign existing certificates.
- pkg.mSignatures = ps.signatures.mSignatures;
+ Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+ }
+
+ if (!pp.collectCertificates(pkg, parseFlags)) {
+ mLastScanError = pp.getParseError();
+ return false;
}
}
return true;
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 36931b2..9d4e226 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -22,12 +22,14 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.SharedPreferences;
+import android.database.ContentObserver;
import android.net.IThrottleManager;
import android.net.ThrottleManager;
import android.os.Binder;
@@ -44,6 +46,8 @@ import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;
+import com.android.internal.telephony.TelephonyProperties;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Calendar;
@@ -96,8 +100,6 @@ public class ThrottleService extends IThrottleManager.Stub {
private DataRecorder mRecorder;
- private int mThrottleLevel; // 0 for none, 1 for first throttle val, 2 for next, etc
-
private String mPolicyIface;
private static final int NOTIFICATION_WARNING = 2;
@@ -107,6 +109,12 @@ public class ThrottleService extends IThrottleManager.Stub {
private Notification mThrottlingNotification;
private boolean mWarningNotificationSent = false;
+ private SettingsObserver mSettingsObserver;
+
+ private int mThrottleIndex; // 0 for none, 1 for first throttle val, 2 for next, etc
+ private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
+ private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
+
public ThrottleService(Context context) {
if (DBG) Slog.d(TAG, "Starting ThrottleService");
mContext = context;
@@ -124,6 +132,38 @@ public class ThrottleService extends IThrottleManager.Stub {
Context.NOTIFICATION_SERVICE);
}
+ private static class SettingsObserver extends ContentObserver {
+ private int mMsg;
+ private Handler mHandler;
+ SettingsObserver(Handler handler, int msg) {
+ super(handler);
+ mHandler = handler;
+ mMsg = msg;
+ }
+
+ void observe(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_POLLING_SEC), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_THRESHOLD), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_VALUE), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_RESET_DAY), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.THROTTLE_IFACE), false, this);
+ // TODO - add help url
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mHandler.obtainMessage(mMsg).sendToTarget();
+ }
+ }
+
private void enforceAccessPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -143,7 +183,7 @@ public class ThrottleService extends IThrottleManager.Stub {
//TODO - a better name? getCliffByteCountThreshold?
public synchronized long getCliffThreshold(String iface, int cliff) {
enforceAccessPermission();
- if ((cliff == 0) && iface.equals(mPolicyIface)) {
+ if ((cliff == 1) && iface.equals(mPolicyIface)) {
return mPolicyThreshold;
}
return 0;
@@ -151,12 +191,18 @@ public class ThrottleService extends IThrottleManager.Stub {
// TODO - a better name? getThrottleRate?
public synchronized int getCliffLevel(String iface, int cliff) {
enforceAccessPermission();
- if ((cliff == 0) && iface.equals(mPolicyIface)) {
+ if ((cliff == 1) && iface.equals(mPolicyIface)) {
return mPolicyThrottleValue;
}
return 0;
}
+ public String getHelpUri() {
+ enforceAccessPermission();
+ return Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.THROTTLE_HELP_URI);
+ }
+
public synchronized long getByteCount(String iface, int dir, int period, int ago) {
enforceAccessPermission();
if (iface.equals(mPolicyIface) &&
@@ -171,7 +217,7 @@ public class ThrottleService extends IThrottleManager.Stub {
// TODO - a better name - getCurrentThrottleRate?
public synchronized int getThrottle(String iface) {
enforceAccessPermission();
- if (iface.equals(mPolicyIface) && (mThrottleLevel == 1)) {
+ if (iface.equals(mPolicyIface) && (mThrottleIndex == 1)) {
return mPolicyThrottleValue;
}
return 0;
@@ -200,6 +246,9 @@ public class ThrottleService extends IThrottleManager.Stub {
mThread.start();
mHandler = new MyHandler(mThread.getLooper());
mHandler.obtainMessage(EVENT_REBOOT_RECOVERY).sendToTarget();
+
+ mSettingsObserver = new SettingsObserver(mHandler, EVENT_POLICY_CHANGED);
+ mSettingsObserver.observe(mContext);
}
@@ -234,8 +283,7 @@ public class ThrottleService extends IThrottleManager.Stub {
// check for sim change TODO
// reregister for notification of policy change
- // register for roaming indication change
- // check for roaming TODO
+ mThrottleIndex = THROTTLE_INDEX_UNINITIALIZED;
mRecorder = new DataRecorder(mContext, ThrottleService.this);
@@ -292,14 +340,10 @@ public class ThrottleService extends IThrottleManager.Stub {
", resetDay=" + mPolicyResetDay + ", noteType=" +
mPolicyNotificationsAllowedMask);
- Calendar end = calculatePeriodEnd();
- Calendar start = calculatePeriodStart(end);
+ onResetAlarm();
- mRecorder.setNextPeriod(start,end);
-
- mAlarmManager.cancel(mPendingResetIntent);
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, end.getTimeInMillis(),
- mPendingResetIntent);
+ Intent broadcast = new Intent(ThrottleManager.POLICY_CHANGED_ACTION);
+ mContext.sendBroadcast(broadcast);
}
private void onPollAlarm() {
@@ -313,15 +357,19 @@ public class ThrottleService extends IThrottleManager.Stub {
} catch (RemoteException e) {
Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
}
-
- mRecorder.addData(incRead, incWrite);
+ // don't count this data if we're roaming.
+ boolean roaming = "true".equals(
+ SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
+ if (!roaming) {
+ mRecorder.addData(incRead, incWrite);
+ }
long periodRx = mRecorder.getPeriodRx(0);
long periodTx = mRecorder.getPeriodTx(0);
long total = periodRx + periodTx;
if (DBG) {
- Slog.d(TAG, "onPollAlarm - now =" + now + ", read =" + incRead +
- ", written =" + incWrite + ", new total =" + total);
+ Slog.d(TAG, "onPollAlarm - now =" + now + ", roaming =" + roaming +
+ ", read =" + incRead + ", written =" + incWrite + ", new total =" + total);
}
mLastRead += incRead;
mLastWrite += incWrite;
@@ -345,9 +393,9 @@ public class ThrottleService extends IThrottleManager.Stub {
// check if we need to throttle
if (currentTotal > mPolicyThreshold) {
- if (mThrottleLevel != 1) {
+ if (mThrottleIndex != 1) {
synchronized (ThrottleService.this) {
- mThrottleLevel = 1;
+ mThrottleIndex = 1;
}
if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
try {
@@ -362,7 +410,8 @@ public class ThrottleService extends IThrottleManager.Stub {
postNotification(com.android.internal.R.string.throttled_notification_title,
com.android.internal.R.string.throttled_notification_message,
- com.android.internal.R.drawable.stat_sys_throttled);
+ com.android.internal.R.drawable.stat_sys_throttled,
+ Notification.FLAG_ONGOING_EVENT);
Intent broadcast = new Intent(ThrottleManager.THROTTLE_ACTION);
broadcast.putExtra(ThrottleManager.EXTRA_THROTTLE_LEVEL, mPolicyThrottleValue);
@@ -372,23 +421,46 @@ public class ThrottleService extends IThrottleManager.Stub {
} else {
if ((mPolicyNotificationsAllowedMask & NOTIFICATION_WARNING) != 0) {
// check if we should warn about throttle
- if (currentTotal > (mPolicyThreshold/2) && !mWarningNotificationSent) {
- mWarningNotificationSent = true;
- mNotificationManager.cancel(com.android.internal.R.drawable.
- stat_sys_throttle_warning);
- postNotification(com.android.internal.R.string.
- throttle_warning_notification_title,
- com.android.internal.R.string.
- throttle_warning_notification_message,
- com.android.internal.R.drawable.stat_sys_throttle_warning);
+ // pretend we only have 1/2 the time remaining that we actually do
+ // if our burn rate in the period so far would have us exceed the limit
+ // in that 1/2 window, warn the user.
+ // this gets more generous in the early to middle period and converges back
+ // to the limit as we move toward the period end.
+
+ // adding another factor - it must be greater than the total cap/4
+ // else we may get false alarms very early in the period.. in the first
+ // tenth of a percent of the period if we used more than a tenth of a percent
+ // of the cap we'd get a warning and that's not desired.
+ long start = mRecorder.getPeriodStart();
+ long end = mRecorder.getPeriodEnd();
+ long periodLength = end - start;
+ long now = System.currentTimeMillis();
+ long timeUsed = now - start;
+ long warningThreshold = 2*mPolicyThreshold*timeUsed/(timeUsed+periodLength);
+ if ((currentTotal > warningThreshold) && (currentTotal > mPolicyThreshold/4)) {
+ if (mWarningNotificationSent == false) {
+ mWarningNotificationSent = true;
+ mNotificationManager.cancel(com.android.internal.R.drawable.
+ stat_sys_throttle_warning);
+ postNotification(com.android.internal.R.string.
+ throttle_warning_notification_title,
+ com.android.internal.R.string.
+ throttle_warning_notification_message,
+ com.android.internal.R.drawable.stat_sys_throttle_warning,
+ 0);
+ }
} else {
- mWarningNotificationSent =false;
+ if (mWarningNotificationSent == true) {
+ mNotificationManager.cancel(com.android.internal.R.drawable.
+ stat_sys_throttle_warning);
+ mWarningNotificationSent =false;
+ }
}
}
}
}
- private void postNotification(int titleInt, int messageInt, int icon) {
+ private void postNotification(int titleInt, int messageInt, int icon, int flags) {
Intent intent = new Intent();
// TODO - fix up intent
intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
@@ -405,8 +477,8 @@ public class ThrottleService extends IThrottleManager.Stub {
// TODO - fixup icon
mThrottlingNotification.icon = icon;
mThrottlingNotification.defaults &= ~Notification.DEFAULT_SOUND;
-// mThrottlingNotification.flags = Notification.FLAG_ONGOING_EVENT;
}
+ mThrottlingNotification.flags = flags;
mThrottlingNotification.tickerText = title;
mThrottlingNotification.setLatestEventInfo(mContext, title, message, pi);
@@ -415,9 +487,9 @@ public class ThrottleService extends IThrottleManager.Stub {
private synchronized void clearThrottleAndNotification() {
- if (mThrottleLevel == 1) {
+ if (mThrottleIndex != THROTTLE_INDEX_UNTHROTTLED) {
synchronized (ThrottleService.this) {
- mThrottleLevel = 0;
+ mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
}
try {
mNMService.setInterfaceThrottle(mPolicyIface, -1, -1);
@@ -485,6 +557,7 @@ public class ThrottleService extends IThrottleManager.Stub {
mRecorder.setNextPeriod(start,end);
+ mAlarmManager.cancel(mPendingResetIntent);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, end.getTimeInMillis(),
mPendingResetIntent);
}
@@ -678,12 +751,6 @@ public class ThrottleService extends IThrottleManager.Stub {
}
long getPeriodRx(int which) {
- if (DBG) { // TODO - remove
- Slog.d(TAG, "reading slot "+ which +" with current =" + mCurrentPeriod);
- for(int x = 0; x<mPeriodCount; x++) {
- Slog.d(TAG, " " + x + " = " + mPeriodRxData[x]);
- }
- }
synchronized (mParent) {
if (which > mPeriodCount) return 0;
which = mCurrentPeriod - which;
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index d6a42f6..3606629 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -25,6 +25,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.UiModeManager;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -103,6 +104,14 @@ class UiModeManagerService extends IUiModeManager.Stub {
private StatusBarManager mStatusBarManager;
private final PowerManager.WakeLock mWakeLock;
+ static Intent buildHomeIntent(String category) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(category);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ return intent;
+ }
+
// The broadcast receiver which receives the result of the ordered broadcast sent when
// the dock state changes. The original ordered broadcast is sent with an initial result
// code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
@@ -114,24 +123,36 @@ class UiModeManagerService extends IUiModeManager.Stub {
return;
}
+ final int enableFlags = intent.getIntExtra("enableFlags", 0);
+ final int disableFlags = intent.getIntExtra("disableFlags", 0);
+
synchronized (mLock) {
// Launch a dock activity
- String category;
+ String category = null;
if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
- // Only launch car home when car mode is enabled.
- category = Intent.CATEGORY_CAR_DOCK;
+ // Only launch car home when car mode is enabled and the caller
+ // has asked us to switch to it.
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_CAR_DOCK;
+ }
} else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
- category = Intent.CATEGORY_DESK_DOCK;
+ // Only launch car home when desk mode is enabled and the caller
+ // has asked us to switch to it. Currently re-using the car
+ // mode flag since we don't have a formal API for "desk mode".
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_DESK_DOCK;
+ }
} else {
- category = null;
+ // Launch the standard home app if requested.
+ if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+ category = Intent.CATEGORY_HOME;
+ }
}
+
if (category != null) {
// This is the new activity that will serve as home while
// we are in care mode.
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(category);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ Intent homeIntent = buildHomeIntent(category);
// Now we are going to be careful about switching the
// configuration and starting the activity -- we need to
@@ -148,7 +169,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
}
try {
ActivityManagerNative.getDefault().startActivityWithConfig(
- null, intent, null, null, 0, null, null, 0, false, false,
+ null, homeIntent, null, null, 0, null, null, 0, false, false,
newConfig);
mHoldingConfiguration = false;
} catch (RemoteException e) {
@@ -188,7 +209,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
synchronized (mLock) {
if (mSystemReady) {
- updateLocked(0);
+ updateLocked(0, 0);
}
}
}
@@ -302,16 +323,16 @@ class UiModeManagerService extends IUiModeManager.Stub {
synchronized (mLock) {
setCarModeLocked(false);
if (mSystemReady) {
- updateLocked(flags);
+ updateLocked(0, flags);
}
}
}
- public void enableCarMode() {
+ public void enableCarMode(int flags) {
synchronized (mLock) {
setCarModeLocked(true);
if (mSystemReady) {
- updateLocked(0);
+ updateLocked(flags, 0);
}
}
}
@@ -342,7 +363,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
Settings.Secure.UI_NIGHT_MODE, mode);
Binder.restoreCallingIdentity(ident);
mNightMode = mode;
- updateLocked(0);
+ updateLocked(0, 0);
}
}
}
@@ -355,7 +376,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
synchronized (mLock) {
mSystemReady = true;
mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
- updateLocked(0);
+ updateLocked(0, 0);
mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
}
}
@@ -376,7 +397,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
mDockState = newState;
setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR);
if (mSystemReady) {
- updateLocked(0);
+ updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0);
}
}
}
@@ -426,7 +447,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
}
}
- final void updateLocked(int flags) {
+ final void updateLocked(int enableFlags, int disableFlags) {
long ident = Binder.clearCallingIdentity();
try {
@@ -469,35 +490,40 @@ class UiModeManagerService extends IUiModeManager.Stub {
// not launch the corresponding dock application. This gives apps a chance
// to override the behavior and stay in their app even when the device is
// placed into a dock.
- mContext.sendOrderedBroadcast(new Intent(action), null,
+ Intent intent = new Intent(action);
+ intent.putExtra("enableFlags", enableFlags);
+ intent.putExtra("disableFlags", disableFlags);
+ mContext.sendOrderedBroadcast(intent, null,
mResultReceiver, null, Activity.RESULT_OK, null, null);
// Attempting to make this transition a little more clean, we are going
// to hold off on doing a configuration change until we have finished
- // the broacast and started the home activity.
+ // the broadcast and started the home activity.
mHoldingConfiguration = true;
- }
-
- if (oldAction != null && (flags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
- // We are exiting the special mode, and have been asked to return
- // to the main home screen while doing so. To keep this clean, we
- // have the activity manager switch the configuration for us at the
- // same time as the switch.
- try {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mHoldingConfiguration = false;
- updateConfigurationLocked(false);
- ActivityManagerNative.getDefault().startActivityWithConfig(
- null, intent, null, null, 0, null, null, 0, false, false,
- mConfiguration);
- } catch (RemoteException e) {
- Slog.w(TAG, e.getCause());
- }
} else {
- updateConfigurationLocked(true);
+ Intent homeIntent = null;
+ if (mCarModeEnabled) {
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ homeIntent = buildHomeIntent(Intent.CATEGORY_CAR_DOCK);
+ }
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ if ((enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ homeIntent = buildHomeIntent(Intent.CATEGORY_DESK_DOCK);
+ }
+ } else {
+ if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+ homeIntent = buildHomeIntent(Intent.CATEGORY_HOME);
+ }
+ }
+ if (homeIntent != null) {
+ try {
+ mContext.startActivity(homeIntent);
+ } catch (ActivityNotFoundException e) {
+ }
+ }
}
+ updateConfigurationLocked(true);
+
// keep screen on when charging and in car mode
boolean keepScreenOn = mCharging &&
((mCarModeEnabled && mCarModeKeepsScreenOn) ||
@@ -569,7 +595,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
if (isDoingNightMode() && mLocation != null
&& mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
updateTwilightLocked();
- updateLocked(0);
+ updateLocked(0, 0);
}
}
break;
@@ -597,7 +623,7 @@ class UiModeManagerService extends IUiModeManager.Stub {
if (isDoingNightMode() && mLocation != null
&& mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
updateTwilightLocked();
- updateLocked(0);
+ updateLocked(0, 0);
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 70fdadf..1f8bbcf 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -310,7 +310,8 @@ public abstract class DataConnection extends HierarchicalStateMachine {
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, o));
} else {
if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
- sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, o));
+ AsyncResult ar = new AsyncResult(o, null, null);
+ sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, ar));
}
}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
index f313a90..64882aa 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
@@ -55,7 +55,11 @@ public class OneEditTextActivitySelected extends Activity
((ScrollView) mRootView).addView(layout);
setContentView(mRootView);
- }
+
+ // set to resize so IME is always shown (and also so
+ // ImfBaseTestCase#destructiveCheckImeInitialState thinks it should always be shown
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ }
public View getRootView() {
return mRootView;
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
index 1957640..50e2009 100755
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
@@ -19,6 +19,7 @@ package com.android.imftest.samples;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
import android.view.KeyEvent;
@@ -43,7 +44,6 @@ public abstract class ImfBaseTestCase<T extends Activity> extends Instrumentatio
public final int IME_MIN_HEIGHT = 150;
public final int IME_MAX_HEIGHT = 300;
- public final String TARGET_PACKAGE_NAME = "com.android.imftest";
protected InputMethodManager mImm;
protected T mTargetActivity;
protected boolean mExpectAutoPop;
@@ -56,9 +56,12 @@ public abstract class ImfBaseTestCase<T extends Activity> extends Instrumentatio
@Override
public void setUp() throws Exception {
super.setUp();
+ final String packageName = getInstrumentation().getTargetContext().getPackageName();
+ mTargetActivity = launchActivity(packageName, mTargetActivityClass, null);
+ // expect ime to auto pop up if device has no hard keyboard
+ mExpectAutoPop = mTargetActivity.getResources().getConfiguration().hardKeyboardHidden ==
+ Configuration.HARDKEYBOARDHIDDEN_YES;
- mTargetActivity = launchActivity(TARGET_PACKAGE_NAME, mTargetActivityClass, null);
- mExpectAutoPop = mTargetActivity.getResources().getBoolean(R.bool.def_expect_ime_autopop);
mImm = InputMethodManager.getInstance(mTargetActivity);
KeyguardManager keyguardManager =
@@ -104,9 +107,9 @@ public abstract class ImfBaseTestCase<T extends Activity> extends Instrumentatio
}
public void destructiveCheckImeInitialState(View rootView, View servedView) {
- if (mExpectAutoPop && (mTargetActivity.getWindow().getAttributes().
- softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ int windowSoftInputMode = mTargetActivity.getWindow().getAttributes().softInputMode;
+ int adjustMode = windowSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+ if (mExpectAutoPop && adjustMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
assertTrue(destructiveCheckImeUp(rootView, servedView));
} else {
assertFalse(destructiveCheckImeUp(rootView, servedView));
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
index e4f9794..619ab30 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint.java
@@ -208,6 +208,12 @@ public class Paint extends _Original_Paint {
this(0);
}
+ /*
+ * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails.
+ */
+ @Override
+ public void finalize() { }
+
public Paint(int flags) {
setFlags(flags | DEFAULT_PAINT_FLAGS);
initFont();