summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt32
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java19
-rw-r--r--core/java/android/app/ActivityManagerNative.java17
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--core/java/android/content/Context.java20
-rw-r--r--core/java/android/content/pm/PackageParser.java31
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java70
-rw-r--r--core/java/android/hardware/camera2/CameraProperties.java74
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java2
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java98
-rw-r--r--core/java/android/hardware/camera2/Face.java252
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java1
-rw-r--r--core/java/android/hardware/camera2/utils/CameraBinderDecorator.java5
-rw-r--r--core/java/android/nfc/NfcAdapter.java4
-rw-r--r--core/java/android/provider/Settings.java3
-rw-r--r--core/java/android/transition/Fade.java34
-rw-r--r--core/java/android/transition/Transition.java9
-rw-r--r--core/java/android/transition/TransitionManager.java55
-rw-r--r--core/java/android/transition/Visibility.java5
-rw-r--r--core/java/android/view/ViewTreeObserver.java2
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java47
-rw-r--r--core/java/com/android/internal/app/ProcessStats.java36
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp31
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_adb_am.pngbin1461 -> 243 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_adb_am.pngbin1102 -> 168 bytes
-rw-r--r--core/res/res/drawable-nodpi/platlogo.pngbin264785 -> 39802 bytes
-rw-r--r--core/res/res/drawable-xhdpi/stat_sys_adb_am.pngbin1810 -> 244 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/stat_sys_adb_am.pngbin2384 -> 322 bytes
-rw-r--r--core/res/res/layout/toast_bar.xml2
-rw-r--r--core/res/res/values-land/refs.xml20
-rw-r--r--core/res/res/values-sw600dp-port/refs.xml20
-rw-r--r--core/res/res/values/attrs_manifest.xml7
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/ConnectivityManagerTest/AndroidManifest.xml9
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java2
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java (renamed from core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java)147
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java2
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java317
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java33
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java64
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java38
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java81
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java6
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java8
-rw-r--r--core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java20
-rw-r--r--docs/html/guide/topics/renderscript/compute.jd83
-rw-r--r--docs/html/sdk/index.jd54
-rw-r--r--docs/html/sdk/installing/installing-adt.jd8
-rw-r--r--docs/html/tools/sdk/eclipse-adt.jd44
-rw-r--r--docs/html/tools/sdk/tools-notes.jd66
-rw-r--r--docs/html/tools/support-library/features.jd21
-rw-r--r--docs/html/tools/support-library/index.jd1
-rw-r--r--media/java/android/media/Image.java96
-rw-r--r--media/java/android/media/ImageReader.java340
-rw-r--r--media/java/android/media/audiofx/AudioEffect.java8
-rw-r--r--media/java/android/media/audiofx/LoudnessEnhancer.java302
-rw-r--r--media/jni/android_media_ImageReader.cpp43
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java5
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java14
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java181
-rw-r--r--media/tests/SoundPoolTest/AndroidManifest.xml1
-rw-r--r--media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java50
-rw-r--r--media/tests/audiotests/Android.mk21
-rw-r--r--media/tests/audiotests/shared_mem_test.cpp216
-rw-r--r--media/tests/audiotests/shared_mem_test.h27
-rw-r--r--packages/SystemUI/AndroidManifest.xml29
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/DessertCase.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/DessertCaseDream.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java75
-rw-r--r--policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java105
-rw-r--r--services/java/com/android/server/IdleMaintenanceService.java69
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java351
-rw-r--r--services/java/com/android/server/am/ActivityStackSupervisor.java3
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java14
-rw-r--r--services/java/com/android/server/am/ProcessStatsService.java20
-rwxr-xr-xservices/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/java/com/android/server/pm/Settings.java1
-rw-r--r--services/java/com/android/server/wifi/WifiService.java13
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java10
87 files changed, 2894 insertions, 1123 deletions
diff --git a/api/current.txt b/api/current.txt
index ab48c8d0a6be..a57423730de7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10862,6 +10862,7 @@ package android.hardware.camera2 {
public abstract class CameraMetadata {
method public abstract T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getKeys();
field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -10987,6 +10988,8 @@ package android.hardware.camera2 {
public final class CameraProperties extends android.hardware.camera2.CameraMetadata {
method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureRequestKeys();
+ method public java.util.List<android.hardware.camera2.CameraMetadata.Key<?>> getAvailableCaptureResultKeys();
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_COMPENSATION_RANGE;
@@ -11131,6 +11134,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_IDS;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_LANDMARKS;
@@ -11146,14 +11150,16 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
- public static class CaptureResult.Face {
- ctor public CaptureResult.Face();
+ public final class Face {
method public android.graphics.Rect getBounds();
method public int getId();
- method public android.graphics.Point getLeftEye();
- method public android.graphics.Point getMouth();
- method public android.graphics.Point getRightEye();
+ method public android.graphics.Point getLeftEyePosition();
+ method public android.graphics.Point getMouthPosition();
+ method public android.graphics.Point getRightEyePosition();
method public int getScore();
+ field public static final int ID_UNSUPPORTED = -1; // 0xffffffff
+ field public static final int SCORE_MAX = 100; // 0x64
+ field public static final int SCORE_MIN = 1; // 0x1
}
public final class Rational {
@@ -12334,7 +12340,7 @@ package android.media {
field public static final int EULER_Z = 2; // 0x2
}
- public abstract interface Image implements java.lang.AutoCloseable {
+ public abstract class Image implements java.lang.AutoCloseable {
method public abstract void close();
method public abstract int getFormat();
method public abstract int getHeight();
@@ -12343,23 +12349,23 @@ package android.media {
method public abstract int getWidth();
}
- public static abstract interface Image.Plane {
+ public static abstract class Image.Plane {
method public abstract java.nio.ByteBuffer getBuffer();
method public abstract int getPixelStride();
method public abstract int getRowStride();
}
- public final class ImageReader implements java.lang.AutoCloseable {
- ctor public ImageReader(int, int, int, int);
+ public class ImageReader implements java.lang.AutoCloseable {
+ method public android.media.Image acquireLatestImage();
+ method public android.media.Image acquireNextImage();
method public void close();
method public int getHeight();
method public int getImageFormat();
method public int getMaxImages();
- method public android.media.Image getNextImage();
method public android.view.Surface getSurface();
method public int getWidth();
- method public void releaseImage(android.media.Image);
- method public void setImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
+ method public static android.media.ImageReader newInstance(int, int, int, int);
+ method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
}
public static abstract interface ImageReader.OnImageAvailableListener {
@@ -15211,9 +15217,9 @@ package android.nfc {
field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
- field public static final int FLAG_READER_KOVIO = 16; // 0x10
field public static final int FLAG_READER_NFC_A = 1; // 0x1
field public static final int FLAG_READER_NFC_B = 2; // 0x2
+ field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
field public static final int FLAG_READER_NFC_F = 4; // 0x4
field public static final int FLAG_READER_NFC_V = 8; // 0x8
field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d78572b561d7..c18f54259678 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -100,6 +100,7 @@ public class Am extends BaseCommand {
" am monitor [--gdb <port>]\n" +
" am hang [--allow-restart]\n" +
" am restart\n" +
+ " am idle-maintenance\n" +
" am screen-compat [on|off] <PACKAGE>\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
@@ -189,6 +190,8 @@ public class Am extends BaseCommand {
"\n" +
"am restart: restart the user-space system.\n" +
"\n" +
+ "am idle-maintenance: perform idle maintenance now.\n" +
+ "\n" +
"am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
"\n" +
"am to-uri: print the given Intent specification as a URI.\n" +
@@ -295,6 +298,8 @@ public class Am extends BaseCommand {
runHang();
} else if (op.equals("restart")) {
runRestart();
+ } else if (op.equals("idle-maintenance")) {
+ runIdleMaintenance();
} else if (op.equals("screen-compat")) {
runScreenCompat();
} else if (op.equals("to-uri")) {
@@ -1393,6 +1398,20 @@ public class Am extends BaseCommand {
mAm.restart();
}
+ private void runIdleMaintenance() throws Exception {
+ String opt;
+ while ((opt=nextOption()) != null) {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+
+ System.out.println("Performing idle maintenance...");
+ Intent intent = new Intent(
+ "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
+ mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
+ android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
+ }
+
private void runScreenCompat() throws Exception {
String mode = nextArgRequired();
boolean enabled;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 370db3117663..a727b076e9bb 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1995,6 +1995,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeParcelableArray(uris, 0);
return true;
}
+
+ case PERFORM_IDLE_MAINTENANCE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ performIdleMaintenance();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -4578,5 +4585,15 @@ class ActivityManagerProxy implements IActivityManager
return uris;
}
+ public void performIdleMaintenance() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(PERFORM_IDLE_MAINTENANCE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b2ae298944f4..25c02df80840 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -403,6 +403,8 @@ public interface IActivityManager extends IInterface {
String sourcePackage, String targetPackage, int modeFlags, int modeMask)
throws RemoteException;
+ public void performIdleMaintenance() throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -685,4 +687,5 @@ public interface IActivityManager extends IInterface {
int REPORT_ACTIVITY_FULLY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+176;
int RESTART_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+177;
int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+178;
+ int PERFORM_IDLE_MAINTENANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 92a9c7c84ab1..02ccaa5ace22 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2132,13 +2132,8 @@ public abstract class Context {
public static final String UPDATE_LOCK_SERVICE = "updatelock";
/**
- * Use with {@link #getSystemService} to retrieve a {@link
- * android.net.NetworkManagementService} for handling management of
- * system network services
- *
+ * Constant for the internal network management service, not really a Context service.
* @hide
- * @see #getSystemService
- * @see android.net.NetworkManagementService
*/
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
@@ -2327,7 +2322,7 @@ public abstract class Context {
* android.hardware.SerialManager} for access to serial ports.
*
* @see #getSystemService
- * @see android.harware.SerialManager
+ * @see android.hardware.SerialManager
*
* @hide
*/
@@ -2353,17 +2348,6 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.os.SchedulingPolicyService} for managing scheduling policy.
- *
- * @see #getSystemService
- * @see android.os.SchedulingPolicyService
- *
- * @hide
- */
- public static final String SCHEDULING_POLICY_SERVICE = "scheduling_policy";
-
- /**
- * Use with {@link #getSystemService} to retrieve a
* {@link android.os.UserManager} for managing users on devices that support multiple users.
*
* @see #getSystemService
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4494e691ccfa..2e25177e49a9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1441,18 +1441,29 @@ public class PackageParser {
*/
boolean required = true; // Optional <uses-permission> not supported
+ int maxSdkVersion = 0;
+ TypedValue val = sa.peekValue(
+ com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+ if (val != null) {
+ if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+ maxSdkVersion = val.data;
+ }
+ }
+
sa.recycle();
- if (name != null) {
- int index = pkg.requestedPermissions.indexOf(name);
- if (index == -1) {
- pkg.requestedPermissions.add(name.intern());
- pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
- } else {
- if (pkg.requestedPermissionsRequired.get(index) != required) {
- outError[0] = "conflicting <uses-permission> entries";
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return false;
+ if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
+ if (name != null) {
+ int index = pkg.requestedPermissions.indexOf(name);
+ if (index == -1) {
+ pkg.requestedPermissions.add(name.intern());
+ pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+ } else {
+ if (pkg.requestedPermissionsRequired.get(index) != required) {
+ outError[0] = "conflicting <uses-permission> entries";
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return false;
+ }
}
}
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ec23f082f2f5..7f4ba4f1551a 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -18,12 +18,25 @@ package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* The base class for camera controls and information.
*
+ * <p>
* This class defines the basic key/value map used for querying for camera
* characteristics or capture results, and for setting camera request
* parameters.
+ * </p>
+ *
+ * <p>
+ * All instances of CameraMetadata are immutable. The list of keys with {@link #getKeys()}
+ * never changes, nor do the values returned by any key with {@link #get} throughout
+ * the lifetime of the object.
+ * </p>
*
* @see CameraDevice
* @see CameraManager
@@ -38,9 +51,14 @@ public abstract class CameraMetadata {
}
/**
- * Get a camera metadata field value. The field definitions can be
+ * Get a camera metadata field value.
+ *
+ * <p>The field definitions can be
* found in {@link CameraProperties}, {@link CaptureResult}, and
- * {@link CaptureRequest}.
+ * {@link CaptureRequest}.</p>
+ *
+ * <p>Querying the value for the same key more than once will return a value
+ * which is equal to the previous queried value.</p>
*
* @throws IllegalArgumentException if the key was not valid
*
@@ -49,6 +67,54 @@ public abstract class CameraMetadata {
*/
public abstract <T> T get(Key<T> key);
+ /**
+ * Returns a list of the keys contained in this map.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>All values retrieved by a key from this list with {@link #get} are guaranteed to be
+ * non-{@code null}. Each key is only listed once in the list. The order of the keys
+ * is undefined.</p>
+ *
+ * @return List of the keys contained in this map.
+ */
+ public List<Key<?>> getKeys() {
+ return Collections.unmodifiableList(getKeysStatic(this.getClass(), this));
+ }
+
+ /**
+ * Return a list of all the Key<?> that are declared as a field inside of the class
+ * {@code type}.
+ *
+ * <p>
+ * Optionally, if {@code instance} is not null, then filter out any keys with null values.
+ * </p>
+ */
+ /*package*/ static ArrayList<Key<?>> getKeysStatic(Class<? extends CameraMetadata> type,
+ CameraMetadata instance) {
+ ArrayList<Key<?>> keyList = new ArrayList<Key<?>>();
+
+ Field[] fields = type.getDeclaredFields();
+ for (Field field : fields) {
+ if (field.getDeclaringClass().isAssignableFrom(Key.class)) {
+ Key<?> key;
+ try {
+ key = (Key<?>) field.get(instance);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError("Can't get IllegalAccessException", e);
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError("Can't get IllegalArgumentException", e);
+ }
+ if (instance == null || instance.get(key) != null) {
+ keyList.add(key);
+ }
+ }
+ }
+
+ return keyList;
+ }
+
public static class Key<T> {
private boolean mHasTag;
diff --git a/core/java/android/hardware/camera2/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
index 45c009fbe925..58a1ee3175df 100644
--- a/core/java/android/hardware/camera2/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -18,6 +18,9 @@ package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import java.util.Collections;
+import java.util.List;
+
/**
* <p>The properties describing a
* {@link CameraDevice CameraDevice}.</p>
@@ -32,6 +35,8 @@ import android.hardware.camera2.impl.CameraMetadataNative;
public final class CameraProperties extends CameraMetadata {
private final CameraMetadataNative mProperties;
+ private List<Key<?>> mAvailableRequestKeys;
+ private List<Key<?>> mAvailableResultKeys;
/**
* Takes ownership of the passed-in properties object
@@ -46,6 +51,75 @@ public final class CameraProperties extends CameraMetadata {
return mProperties.get(key);
}
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} for querying
+ * with a {@link CaptureRequest}.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * <p>Note that there is no {@code getAvailableCameraPropertiesKeys()} -- use
+ * {@link #getKeys()} instead.</p>
+ *
+ * @return List of keys supported by this CameraDevice for CaptureRequests.
+ */
+ public List<Key<?>> getAvailableCaptureRequestKeys() {
+ if (mAvailableRequestKeys == null) {
+ mAvailableRequestKeys = getAvailableKeyList(CaptureRequest.class);
+ }
+ return mAvailableRequestKeys;
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} for querying
+ * with a {@link CaptureResult}.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * <p>Note that there is no {@code getAvailableCameraPropertiesKeys()} -- use
+ * {@link #getKeys()} instead.</p>
+ *
+ * @return List of keys supported by this CameraDevice for CaptureResults.
+ */
+ public List<Key<?>> getAvailableCaptureResultKeys() {
+ if (mAvailableResultKeys == null) {
+ mAvailableResultKeys = getAvailableKeyList(CaptureResult.class);
+ }
+ return mAvailableResultKeys;
+ }
+
+ /**
+ * Returns the list of keys supported by this {@link CameraDevice} by metadataClass.
+ *
+ * <p>The list returned is not modifiable, so any attempts to modify it will throw
+ * a {@code UnsupportedOperationException}.</p>
+ *
+ * <p>Each key is only listed once in the list. The order of the keys is undefined.</p>
+ *
+ * @param metadataClass The subclass of CameraMetadata that you want to get the keys for.
+ *
+ * @return List of keys supported by this CameraDevice for metadataClass.
+ *
+ * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
+ */
+ private <T extends CameraMetadata> List<Key<?>> getAvailableKeyList(Class<T> metadataClass) {
+
+ if (metadataClass.equals(CameraMetadata.class)) {
+ throw new AssertionError(
+ "metadataClass must be a strict subclass of CameraMetadata");
+ } else if (!CameraMetadata.class.isAssignableFrom(metadataClass)) {
+ throw new AssertionError(
+ "metadataClass must be a subclass of CameraMetadata");
+ }
+
+ return Collections.unmodifiableList(getKeysStatic(metadataClass, /*instance*/null));
+ }
+
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 4608ab913fa7..3ec5ca03c782 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -176,7 +176,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
*/
public final static class Builder {
- private CaptureRequest mRequest;
+ private final CaptureRequest mRequest;
/**
* Initialize the builder using the template; the request takes
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3fcd2f9c147c..377e78aa5477 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -51,89 +51,6 @@ public final class CaptureResult extends CameraMetadata {
return mResults.get(key);
}
- /**
- * Describes a face detected in an image.
- */
- public static class Face {
-
- /**
- * <p>Bounds of the face. A rectangle relative to the sensor's
- * {@link CameraProperties#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
- * representing the top-left corner of the active array rectangle.</p>
- */
- public Rect getBounds() {
- return mBounds;
- }
-
- /** <p>The confidence level for the detection of the face. The range is 1 to
- * 100. 100 is the highest confidence.</p>
- *
- * <p>Depending on the device, even very low-confidence faces may be
- * listed, so applications should filter out faces with low confidence,
- * depending on the use case. For a typical point-and-shoot camera
- * application that wishes to display rectangles around detected faces,
- * filtering out faces with confidence less than 50 is recommended.</p>
- *
- */
- public int getScore() {
- return mScore;
- }
-
- /**
- * An unique id per face while the face is visible to the tracker. If
- * the face leaves the field-of-view and comes back, it will get a new
- * id. This is an optional field, may not be supported on all devices.
- * If not supported, id will always be set to -1. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public int getId() {
- return mId;
- }
-
- /**
- * The coordinates of the center of the left eye. The coordinates are in
- * the same space as the ones for {@link #getBounds}. This is an
- * optional field, may not be supported on all devices. If not
- * supported, the value will always be set to null. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public Point getLeftEye() {
- return mLeftEye;
- }
-
- /**
- * The coordinates of the center of the right eye. The coordinates are
- * in the same space as the ones for {@link #getBounds}.This is an
- * optional field, may not be supported on all devices. If not
- * supported, the value will always be set to null. The optional fields
- * are supported as a set. Either they are all valid, or none of them
- * are.
- */
- public Point getRightEye() {
- return mRightEye;
- }
-
- /**
- * The coordinates of the center of the mouth. The coordinates are in
- * the same space as the ones for {@link #getBounds}. This is an optional
- * field, may not be supported on all devices. If not supported, the
- * value will always be set to null. The optional fields are supported
- * as a set. Either they are all valid, or none of them are.
- */
- public Point getMouth() {
- return mMouth;
- }
-
- private Rect mBounds;
- private int mScore;
- private int mId;
- private Point mLeftEye;
- private Point mRightEye;
- private Point mMouth;
- }
-
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* The key entries below this point are generated from metadata
* definitions in /system/media/camera/docs. Do not modify by hand or
@@ -1003,4 +920,19 @@ public final class CaptureResult extends CameraMetadata {
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+ /**
+ * <p>
+ * List of the {@link Face Faces} detected through camera face detection
+ * in this result.
+ * </p>
+ * <p>
+ * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
+ * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
+ * </p>
+ *
+ * @see Face
+ */
+ public static final Key<Face[]> STATISTICS_FACES =
+ new Key<Face[]>("android.statistics.faces", Face[].class);
}
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/Face.java
new file mode 100644
index 000000000000..6bfc5354359a
--- /dev/null
+++ b/core/java/android/hardware/camera2/Face.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.hardware.camera2;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Describes a face detected in an image.
+ */
+public final class Face {
+
+ /**
+ * The ID is {@code -1} when the optional set of fields is unsupported.
+ *
+ * @see Face#Face(Rect, int)
+ * @see #getId()
+ */
+ public static final int ID_UNSUPPORTED = -1;
+
+ /**
+ * The minimum possible value for the confidence level.
+ *
+ * @see #getScore()
+ */
+ public static final int SCORE_MIN = 1;
+
+ /**
+ * The maximum possible value for the confidence level.
+ *
+ * @see #getScore()
+ */
+ public static final int SCORE_MAX = 100;
+
+ private final Rect mBounds;
+ private final int mScore;
+ private final int mId;
+ private final Point mLeftEye;
+ private final Point mRightEye;
+ private final Point mMouth;
+
+ /**
+ * Create a new face with all fields set.
+ *
+ * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * @param bounds Bounds of the face.
+ * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ * @param id A unique ID per face visible to the tracker.
+ * @param leftEyePosition The position of the left eye.
+ * @param rightEyePosition The position of the right eye.
+ * @param mouthPosition The position of the mouth.
+ *
+ * @throws IllegalArgumentException
+ * if bounds is {@code null},
+ * or if the confidence is not in the range of
+ * {@value #SCORE_MIN}-{@value #SCORE_MAX},
+ * or if id is {@value #ID_UNSUPPORTED} and
+ * leftEyePosition/rightEyePosition/mouthPosition aren't all null,
+ * or else if id is negative.
+ *
+ * @hide
+ */
+ public Face(Rect bounds, int score, int id,
+ Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
+ checkNotNull("bounds", bounds);
+ if (score < SCORE_MIN || score > SCORE_MAX) {
+ throw new IllegalArgumentException("Confidence out of range");
+ } else if (id < 0 && id != ID_UNSUPPORTED) {
+ throw new IllegalArgumentException("Id out of range");
+ }
+ if (id == ID_UNSUPPORTED) {
+ checkNull("leftEyePosition", leftEyePosition);
+ checkNull("rightEyePosition", rightEyePosition);
+ checkNull("mouthPosition", mouthPosition);
+ }
+
+ mBounds = bounds;
+ mScore = score;
+ mId = id;
+ mLeftEye = leftEyePosition;
+ mRightEye = rightEyePosition;
+ mMouth = mouthPosition;
+ }
+
+ /**
+ * Create a new face without the optional fields.
+ *
+ * <p>The id, leftEyePosition, rightEyePosition, and mouthPosition are considered optional.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * @param bounds Bounds of the face.
+ * @param score Confidence level between {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ *
+ * @throws IllegalArgumentException
+ * if bounds is {@code null},
+ * or if the confidence is not in the range of
+ * {@value #SCORE_MIN}-{@value #SCORE_MAX}.
+ *
+ * @hide
+ */
+ public Face(Rect bounds, int score) {
+ this(bounds, score, ID_UNSUPPORTED,
+ /*leftEyePosition*/null, /*rightEyePosition*/null, /*mouthPosition*/null);
+ }
+
+ /**
+ * Bounds of the face.
+ *
+ * <p>A rectangle relative to the sensor's
+ * {@link CameraProperties#SENSOR_INFO_ACTIVE_ARRAY_SIZE}, with (0,0)
+ * representing the top-left corner of the active array rectangle.</p>
+ *
+ * <p>There is no constraints on the the Rectangle value other than it
+ * is not-{@code null}.</p>
+ */
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * The confidence level for the detection of the face.
+ *
+ * <p>The range is {@value #SCORE_MIN} to {@value #SCORE_MAX}.
+ * {@value #SCORE_MAX} is the highest confidence.</p>
+ *
+ * <p>Depending on the device, even very low-confidence faces may be
+ * listed, so applications should filter out faces with low confidence,
+ * depending on the use case. For a typical point-and-shoot camera
+ * application that wishes to display rectangles around detected faces,
+ * filtering out faces with confidence less than half of {@value #SCORE_MAX}
+ * is recommended.</p>
+ *
+ * @see #SCORE_MAX
+ * @see #SCORE_MIN
+ */
+ public int getScore() {
+ return mScore;
+ }
+
+ /**
+ * An unique id per face while the face is visible to the tracker.
+ *
+ * <p>
+ * If the face leaves the field-of-view and comes back, it will get a new
+ * id.</p>
+ *
+ * <p>This is an optional field, may not be supported on all devices.
+ * If the id is {@value #ID_UNSUPPORTED} then the leftEyePosition, rightEyePosition, and
+ * mouthPositions are guaranteed to be {@code null}. Otherwise, each of leftEyePosition,
+ * rightEyePosition, and mouthPosition may be independently null or not-null.</p>
+ *
+ * <p>This value will either be {@value #ID_UNSUPPORTED} or
+ * otherwise greater than {@code 0}.</p>
+ *
+ * @see #ID_UNSUPPORTED
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * The coordinates of the center of the left eye.
+ *
+ * <p>The coordinates are in
+ * the same space as the ones for {@link #getBounds}. This is an
+ * optional field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p>
+ *
+ * @return The left eye position, or {@code null} if unknown.
+ */
+ public Point getLeftEyePosition() {
+ return mLeftEye;
+ }
+
+ /**
+ * The coordinates of the center of the right eye.
+ *
+ * <p>The coordinates are
+ * in the same space as the ones for {@link #getBounds}.This is an
+ * optional field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p>
+ *
+ * @return The right eye position, or {@code null} if unknown.
+ */
+ public Point getRightEyePosition() {
+ return mRightEye;
+ }
+
+ /**
+ * The coordinates of the center of the mouth.
+ *
+ * <p>The coordinates are in
+ * the same space as the ones for {@link #getBounds}. This is an optional
+ * field, may not be supported on all devices. If not
+ * supported, the value will always be set to null.
+ * This value will always be null only if {@link #getId()} returns
+ * {@value #ID_UNSUPPORTED}.</p> them are.
+ * </p>
+ *
+ * @return The mouth position, or {@code null} if unknown.
+ */
+ public Point getMouthPosition() {
+ return mMouth;
+ }
+
+ /**
+ * Represent the Face as a string for debugging purposes.
+ */
+ @Override
+ public String toString() {
+ return String.format("{ bounds: %s, score: %s, id: %d, " +
+ "leftEyePosition: %s, rightEyePosition: %s, mouthPosition: %s }",
+ mBounds, mScore, mId, mLeftEye, mRightEye, mMouth);
+ }
+
+ private static void checkNotNull(String name, Object obj) {
+ if (obj == null) {
+ throw new IllegalArgumentException(name + " was required, but it was null");
+ }
+ }
+
+ private static void checkNull(String name, Object obj) {
+ if (obj != null) {
+ throw new IllegalArgumentException(name + " was required to be null, but it wasn't");
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 020d7b60f654..c13438a7f493 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -27,7 +27,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Map;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 2c05c58d852c..d0b3ec4f76a2 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -19,6 +19,7 @@ package android.hardware.camera2.utils;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
import android.os.DeadObjectException;
@@ -50,6 +51,7 @@ public class CameraBinderDecorator {
public static final int EBUSY = -16;
public static final int ENODEV = -19;
public static final int EOPNOTSUPP = -95;
+ public static final int EDQUOT = -122;
private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
@@ -83,6 +85,9 @@ public class CameraBinderDecorator {
case EBUSY:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_IN_USE));
+ case EDQUOT:
+ UncheckedThrow.throwAnyException(new CameraRuntimeException(
+ MAX_CAMERAS_IN_USE));
case ENODEV:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_DISCONNECTED));
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 2a1890002acc..486e75a5ca30 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -227,9 +227,9 @@ public final class NfcAdapter {
/**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
- * Setting this flag enables polling for Kovio technology.
+ * Setting this flag enables polling for NfcBarcode technology.
*/
- public static final int FLAG_READER_KOVIO = 0x10;
+ public static final int FLAG_READER_NFC_BARCODE = 0x10;
/**
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c1c826c35f90..c8312e3adec6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4365,6 +4365,9 @@ public final class Settings {
/** @hide */
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
+ /** @hide */
+ public static final String TRANSIENT_NAV_CONFIRMATIONS = "transient_nav_confirmations";
+
/**
* This are the settings to be backed up.
*
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 12e0d73db389..4cc2c4280d74 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -91,6 +91,9 @@ public class Fade extends Visibility {
return null;
}
final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+ if (DBG) {
+ Log.d(LOG_TAG, "Created animator " + anim);
+ }
if (listener != null) {
anim.addListener(listener);
anim.addPauseListener(listener);
@@ -146,12 +149,41 @@ public class Fade extends Visibility {
final View endView = endValues.view;
if (DBG) {
View startView = (startValues != null) ? startValues.view : null;
- Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
+ Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
}
// if alpha < 1, just fade it in from the current value
if (endView.getAlpha() == 1.0f) {
endView.setAlpha(0);
+ TransitionListener transitionListener = new TransitionListenerAdapter() {
+ boolean mCanceled = false;
+ float mPausedAlpha;
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ endView.setAlpha(1);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ if (!mCanceled) {
+ endView.setAlpha(1);
+ }
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ mPausedAlpha = endView.getAlpha();
+ endView.setAlpha(1);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ endView.setAlpha(mPausedAlpha);
+ }
+ };
+ addListener(transitionListener);
}
return createAnimation(endView, endView.getAlpha(), 1, null);
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index c588c6bf4c7a..60b47087fe44 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1240,12 +1240,13 @@ public abstract class Transition implements Cloneable {
View oldView = oldInfo.view;
TransitionValues newValues = mEndValues.viewValues != null ?
mEndValues.viewValues.get(oldView) : null;
+ if (newValues == null) {
+ newValues = mEndValues.idValues.get(oldView.getId());
+ }
if (oldValues != null) {
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
- if (newValues == null) {
- cancel = true;
- } else {
+ if (newValues != null) {
for (String key : oldValues.values.keySet()) {
Object oldValue = oldValues.values.get(key);
Object newValue = newValues.values.get(key);
@@ -1451,6 +1452,8 @@ public abstract class Transition implements Cloneable {
try {
clone = (Transition) super.clone();
clone.mAnimators = new ArrayList<Animator>();
+ clone.mStartValues = new TransitionValuesMaps();
+ clone.mEndValues = new TransitionValuesMaps();
} catch (CloneNotSupportedException e) {}
return clone;
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 54d801eba443..44ca4e58fd94 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -22,6 +22,7 @@ import android.util.Log;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -68,8 +69,9 @@ public class TransitionManager {
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
- private static ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>> sRunningTransitions =
- new ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>>();
+ private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
+ sRunningTransitions =
+ new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
@@ -184,20 +186,24 @@ public class TransitionManager {
}
private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
- ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
+ WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
sRunningTransitions.get();
- if (runningTransitions == null) {
- runningTransitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ if (runningTransitions == null || runningTransitions.get() == null) {
+ ArrayMap<ViewGroup, ArrayList<Transition>> transitions =
+ new ArrayMap<ViewGroup, ArrayList<Transition>>();
+ runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(
+ transitions);
sRunningTransitions.set(runningTransitions);
}
- return runningTransitions;
+ return runningTransitions.get();
}
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
final Transition transition) {
if (transition != null) {
final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
- observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ final ViewTreeObserver.OnPreDrawListener listener =
+ new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
sPendingTransitions.remove(sceneRoot);
@@ -236,7 +242,8 @@ public class TransitionManager {
// values set on them again and avoid artifacts.
return false;
}
- });
+ };
+ observer.addOnPreDrawListener(listener);
}
}
@@ -342,23 +349,19 @@ public class TransitionManager {
* value of null causes the TransitionManager to use the default transition.
*/
public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
-
- // TEMPORARY: disabling delayed transitions until a fix for the various ActionBar-
- // triggered artifacts is found
-
-// if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
-// if (Transition.DBG) {
-// Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
-// sceneRoot + ", " + transition);
-// }
-// sPendingTransitions.add(sceneRoot);
-// if (transition == null) {
-// transition = sDefaultTransition;
-// }
-// final Transition finalTransition = transition.clone();
-// sceneChangeSetup(sceneRoot, transition);
-// Scene.setCurrentScene(sceneRoot, null);
-// sceneChangeRunTransition(sceneRoot, finalTransition);
-// }
+ if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
+ sceneRoot + ", " + transition);
+ }
+ sPendingTransitions.add(sceneRoot);
+ if (transition == null) {
+ transition = sDefaultTransition;
+ }
+ final Transition transitionClone = transition.clone();
+ sceneChangeSetup(sceneRoot, transitionClone);
+ Scene.setCurrentScene(sceneRoot, null);
+ sceneChangeRunTransition(sceneRoot, transitionClone);
+ }
}
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 75d3e7c0b4e0..f49821fab1c3 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -65,9 +65,6 @@ public abstract class Visibility extends Transition {
ViewGroup endParent;
}
- // Temporary structure, used in calculating state in setup() and play()
- private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();
-
@Override
public String[] getTransitionProperties() {
return sTransitionProperties;
@@ -161,7 +158,7 @@ public abstract class Visibility extends Transition {
private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
TransitionValues endValues) {
- final VisibilityInfo visInfo = mTmpVisibilityInfo;
+ final VisibilityInfo visInfo = new VisibilityInfo();
visInfo.visibilityChange = false;
visInfo.fadeIn = false;
if (startValues != null) {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 730c4eb01cd0..ad8b51db4a1a 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -992,6 +992,8 @@ public final class ViewTreeObserver {
mData = mDataCopy;
}
mDataCopy = null;
+ mAccess.mData.clear();
+ mAccess.mSize = 0;
}
int size() {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 91c47d1450fa..76b857974bdb 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -30,6 +30,8 @@ import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -41,6 +43,7 @@ public class PlatLogoActivity extends Activity {
FrameLayout mContent;
int mCount;
final Handler mHandler = new Handler();
+ static final int BGCOLOR = 0xffed1d24;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -53,6 +56,7 @@ public class PlatLogoActivity extends Activity {
Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
mContent = new FrameLayout(this);
+ mContent.setBackgroundColor(0xC0000000);
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
@@ -64,13 +68,16 @@ public class PlatLogoActivity extends Activity {
logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
logo.setVisibility(View.INVISIBLE);
+ final View bg = new View(this);
+ bg.setBackgroundColor(BGCOLOR);
+ bg.setAlpha(0f);
+
final TextView letter = new TextView(this);
letter.setTypeface(bold);
letter.setTextSize(300);
letter.setTextColor(0xFFFFFFFF);
letter.setGravity(Gravity.CENTER);
- letter.setShadowLayer(12*metrics.density, 0, 0, 0xC085F985);
letter.setText(String.valueOf(Build.VERSION.RELEASE).substring(0, 1));
final int p = (int)(4 * metrics.density);
@@ -81,11 +88,11 @@ public class PlatLogoActivity extends Activity {
tv.setPadding(p, p, p, p);
tv.setTextColor(0xFFFFFFFF);
tv.setGravity(Gravity.CENTER);
- tv.setShadowLayer(4 * metrics.density, 0, 2 * metrics.density, 0x66000000);
tv.setTransformationMethod(new AllCapsTransformationMethod(this));
tv.setText("Android " + Build.VERSION.RELEASE);
tv.setVisibility(View.INVISIBLE);
+ mContent.addView(bg);
mContent.addView(letter, lp);
mContent.addView(logo, lp);
@@ -96,22 +103,52 @@ public class PlatLogoActivity extends Activity {
mContent.addView(tv, lp2);
mContent.setOnClickListener(new View.OnClickListener() {
+ int clicks;
@Override
public void onClick(View v) {
+ clicks++;
+ if (clicks >= 6) {
+ mContent.performLongClick();
+ return;
+ }
+ letter.animate().cancel();
+ final float offset = (int)letter.getRotation() % 360;
+ letter.animate()
+ .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
+ .setInterpolator(new DecelerateInterpolator())
+ .setDuration(700).start();
+ }
+ });
+
+ mContent.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
if (logo.getVisibility() != View.VISIBLE) {
- letter.animate().alpha(0.25f).scaleY(0.75f).scaleX(0.75f).setDuration(2000)
+ bg.setScaleX(0.01f);
+ bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
+ letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
+ .rotationBy(360)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(1000)
.start();
logo.setAlpha(0f);
logo.setVisibility(View.VISIBLE);
- logo.animate().alpha(1f).setDuration(1000).setStartDelay(500).start();
+ logo.setScaleX(0.5f);
+ logo.setScaleY(0.5f);
+ logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
+ .setDuration(1000).setStartDelay(500)
+ .setInterpolator(new AnticipateOvershootInterpolator())
+ .start();
tv.setAlpha(0f);
tv.setVisibility(View.VISIBLE);
tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
+ return true;
}
+ return false;
}
});
- mContent.setOnLongClickListener(new View.OnLongClickListener() {
+ logo.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
try {
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 07854e20f8af..d3fe34edb1c2 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -24,6 +24,7 @@ import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -969,6 +970,7 @@ public final class ProcessStats implements Parcelable {
if (ps.isInUse()) {
uids.valueAt(iu).resetSafely(now);
} else {
+ uids.valueAt(iu).makeDead();
uids.removeAt(iu);
}
}
@@ -986,6 +988,7 @@ public final class ProcessStats implements Parcelable {
if (ps.isInUse() || ps.mCommonProcess.isInUse()) {
pkgState.mProcesses.valueAt(iproc).resetSafely(now);
} else {
+ pkgState.mProcesses.valueAt(iproc).makeDead();
pkgState.mProcesses.removeAt(iproc);
}
}
@@ -2127,6 +2130,7 @@ public final class ProcessStats implements Parcelable {
int mNumExcessiveCpu;
boolean mMultiPackage;
+ boolean mDead;
public long mTmpTotalTime;
@@ -2230,6 +2234,18 @@ public final class ProcessStats implements Parcelable {
mNumExcessiveCpu = 0;
}
+ void makeDead() {
+ mDead = true;
+ }
+
+ private void ensureNotDead() {
+ if (!mDead) {
+ return;
+ }
+ throw new IllegalStateException("ProcessState dead: name=" + mName
+ + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ }
+
void writeToParcel(Parcel out, long now) {
out.writeInt(mMultiPackage ? 1 : 0);
out.writeInt(mDurationsTableSize);
@@ -2271,6 +2287,7 @@ public final class ProcessStats implements Parcelable {
}
public void makeActive() {
+ ensureNotDead();
mActive = true;
}
@@ -2279,7 +2296,8 @@ public final class ProcessStats implements Parcelable {
}
public boolean isInUse() {
- return mActive || mNumActiveServices > 0 || mNumStartedServices > 0;
+ return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
+ || mCurState != STATE_NOTHING;
}
/**
@@ -2315,6 +2333,7 @@ public final class ProcessStats implements Parcelable {
}
void setState(int state, long now) {
+ ensureNotDead();
if (mCurState != state) {
//Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
commitStateTime(now);
@@ -2392,6 +2411,7 @@ public final class ProcessStats implements Parcelable {
}
public void addPss(long pss, long uss, boolean always) {
+ ensureNotDead();
if (!always) {
if (mLastPssState == mCurState && SystemClock.uptimeMillis()
< (mLastPssTime+(30*1000))) {
@@ -2453,6 +2473,7 @@ public final class ProcessStats implements Parcelable {
}
public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+ ensureNotDead();
mCommonProcess.mNumExcessiveWake++;
if (!mCommonProcess.mMultiPackage) {
return;
@@ -2464,6 +2485,7 @@ public final class ProcessStats implements Parcelable {
}
public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+ ensureNotDead();
mCommonProcess.mNumExcessiveCpu++;
if (!mCommonProcess.mMultiPackage) {
return;
@@ -2489,9 +2511,17 @@ public final class ProcessStats implements Parcelable {
return this;
}
- private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList,
- int index) {
+ private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
ProcessState proc = pkgList.valueAt(index);
+ if (mDead && proc.mCommonProcess != proc) {
+ // Somehow we try to continue to use a process state that is dead, because
+ // it was not being told it was active during the last commit. We can recover
+ // from this by generating a fresh new state, but this is bad because we
+ // are losing whatever data we had in the old process state.
+ Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
+ + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
+ proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mName);
+ }
if (proc.mMultiPackage) {
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 2d06b681f73d..f773f59688fb 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -159,17 +159,26 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
}
-static SkMemoryStream* adaptor_to_mem_stream(SkStream* adaptor) {
- SkASSERT(adaptor != NULL);
- SkDynamicMemoryWStream wStream;
- const int bufferSize = 256 * 1024; // 256 KB, same as ViewStateSerializer.
- uint8_t buffer[bufferSize];
- do {
- size_t bytesRead = adaptor->read(buffer, bufferSize);
- wStream.write(buffer, bytesRead);
- } while (!adaptor->isAtEnd());
- SkAutoTUnref<SkData> data(wStream.copyToData());
- return new SkMemoryStream(data.get());
+static SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
+ SkASSERT(stream != NULL);
+ size_t bufferSize = 4096;
+ size_t streamLen = 0;
+ size_t len;
+ char* data = (char*)sk_malloc_throw(bufferSize);
+
+ while ((len = stream->read(data + streamLen,
+ bufferSize - streamLen)) != 0) {
+ streamLen += len;
+ if (streamLen == bufferSize) {
+ bufferSize *= 2;
+ data = (char*)sk_realloc_throw(data, bufferSize);
+ }
+ }
+ data = (char*)sk_realloc_throw(data, streamLen);
+
+ SkMemoryStream* streamMem = new SkMemoryStream();
+ streamMem->setMemoryOwned(data, streamLen);
+ return streamMem;
}
SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
index 0c133390ed31..382557e55e91 100644
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
index f0a50894de9e..4380035b5fbd 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 4fd0e3c53a5c..6351c2dea4a4 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
index 789a3f59d37f..3222a7601575 100644
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
index a36fa36e1466..e01ad3860ab6 100644
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
Binary files differ
diff --git a/core/res/res/layout/toast_bar.xml b/core/res/res/layout/toast_bar.xml
index b7443d55a149..a31d7cb14760 100644
--- a/core/res/res/layout/toast_bar.xml
+++ b/core/res/res/layout/toast_bar.xml
@@ -35,7 +35,7 @@
android:paddingRight="16dp"
android:singleLine="true"
android:textColor="@android:color/white"
- android:textSize="16sp" />
+ android:textSize="14sp" />
<LinearLayout
android:id="@android:id/button1"
diff --git a/core/res/res/values-land/refs.xml b/core/res/res/values-land/refs.xml
deleted file mode 100644
index cda38cf2f2a4..000000000000
--- a/core/res/res/values-land/refs.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources> \ No newline at end of file
diff --git a/core/res/res/values-sw600dp-port/refs.xml b/core/res/res/values-sw600dp-port/refs.xml
deleted file mode 100644
index cda38cf2f2a4..000000000000
--- a/core/res/res/values-sw600dp-port/refs.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-<resources>
- <item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
-</resources> \ No newline at end of file
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d2ada7a167ba..80810d549590 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1048,6 +1048,11 @@
tag; often this is one of the {@link android.Manifest.permission standard
system permissions}. -->
<attr name="name" />
+ <!-- Optional: specify the maximum version of the Android OS for which the
+ application wishes to request the permission. When running on a version
+ of Android higher than the number given here, the permission will not
+ be requested. -->
+ <attr name="maxSdkVersion" format="integer" />
<!-- Specify whether this permission is required for the application.
The default is true, meaning the application requires the
permission, and it must always be granted when it is installed.
@@ -1129,7 +1134,7 @@
on. You can use this to ensure your application is filtered out
of later versions of the platform when you know you have
incompatibility with them. -->
- <attr name="maxSdkVersion" format="integer" />
+ <attr name="maxSdkVersion" />
</declare-styleable>
<!-- The <code>library</code> tag declares that this apk is providing itself
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d4b834af5ab0..2c1a3c1d2d15 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1241,4 +1241,8 @@
To do this, add 21407 item to values-mcc214-mnc04/config.xml -->
<string-array translatable="false" name="config_operatorConsideredNonRoaming">
</string-array>
+
+ <!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
+ transient navigation confirmation prompt.-->
+ <integer name="config_transient_navigation_confirmation_panic">5000</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a03378e570f4..98368a162aaf 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4344,9 +4344,7 @@
<!-- PIN entry dialog tells the user to not enter a PIN for a while. [CHAR LIMIT=none] -->
<string name="restr_pin_try_later">Try again later</string>
- <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=35] -->
- <string name="transient_navigation_confirmation">Swipe edge of screen to reveal bar</string>
+ <!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=45] -->
+ <string name="transient_navigation_confirmation">Swipe down from the top to exit full screen</string>
- <!-- Longer version of toast bar message when hiding the transient navigation bar (if room) -->
- <string name="transient_navigation_confirmation_long">Swipe from edge of screen to reveal system bar</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4148f2048ea7..9cb0a371ce8d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -301,6 +301,7 @@
<java-symbol type="integer" name="config_ntpThreshold" />
<java-symbol type="integer" name="config_ntpTimeout" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
+ <java-symbol type="integer" name="config_transient_navigation_confirmation_panic" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
@@ -885,7 +886,6 @@
<java-symbol type="string" name="write_fail_reason_cancelled" />
<java-symbol type="string" name="write_fail_reason_cannot_write" />
<java-symbol type="string" name="transient_navigation_confirmation" />
- <java-symbol type="string" name="transient_navigation_confirmation_long" />
<java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
<java-symbol type="string" name="ssl_ca_cert_noti_managed" />
<java-symbol type="string" name="ssl_ca_cert_warning" />
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index b76c8beb7756..16492682d03d 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -23,13 +23,6 @@
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
- <activity android:name="ConnectivityManagerTestActivity"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
</application>
<!--
@@ -87,4 +80,6 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+
</manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 0461c0bfdc11..b942eb692e49 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -32,13 +32,11 @@ import android.net.wifi.WifiEnterpriseConfig;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
-import android.util.Log;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index a0cb1bb890f1..30eda75d714f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -16,7 +16,7 @@
package com.android.connectivitymanagertest;
-import android.app.Activity;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Intent;
@@ -26,21 +26,14 @@ import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.os.Bundle;
import android.os.Handler;
-import android.os.IPowerManager;
import android.os.Message;
import android.os.PowerManager;
-import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
+import android.test.InstrumentationTestCase;
import android.util.Log;
import android.view.KeyEvent;
-import android.widget.LinearLayout;
import com.android.internal.util.AsyncChannel;
@@ -52,13 +45,17 @@ import java.util.List;
/**
- * An activity registered with connectivity manager broadcast
- * provides network connectivity information and
- * can be used to set device states: Cellular, Wifi, Airplane mode.
+ * Base InstrumentationTestCase for Connectivity Manager (CM) test suite
+ *
+ * It registers connectivity manager broadcast and WiFi broadcast to provide
+ * network connectivity information, also provides a set of utility functions
+ * to modify and verify connectivity states.
+ *
+ * A CM test case should extend this base class.
*/
-public class ConnectivityManagerTestActivity extends Activity {
+public class ConnectivityManagerTestBase extends InstrumentationTestCase {
- public static final String LOG_TAG = "ConnectivityManagerTestActivity";
+ public static final String LOG_TAG = "ConnectivityManagerTestBase";
public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
public static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
public static final int SHORT_TIMEOUT = 5 * 1000; // 5 seconds
@@ -94,14 +91,9 @@ public class ConnectivityManagerTestActivity extends Activity {
private Context mContext;
public boolean scanResultAvailable = false;
- /*
- * Control Wifi States
- */
+ /* Control Wifi States */
public WifiManager mWifiManager;
-
- /*
- * Verify connectivity state
- */
+ /* Verify connectivity state */
public static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
NetworkState[] connectivityState = new NetworkState[NUM_NETWORK_TYPES];
@@ -208,26 +200,28 @@ public class ConnectivityManagerTestActivity extends Activity {
}
}
- public ConnectivityManagerTestActivity() {
+ @Override
+ public void setUp() throws Exception {
mState = State.UNKNOWN;
scanResultAvailable = false;
- }
+ mContext = getInstrumentation().getContext();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- log("onCreate, inst=" + Integer.toHexString(hashCode()));
+ // Get an instance of ConnectivityManager
+ mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ // Get an instance of WifiManager
+ mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
- // Create a simple layout
- LinearLayout contentView = new LinearLayout(this);
- contentView.setOrientation(LinearLayout.VERTICAL);
- setContentView(contentView);
- setTitle("ConnectivityManagerTestActivity");
+ if (mWifiManager.isWifiApEnabled()) {
+ // if soft AP is enabled, disable it
+ mWifiManager.setWifiApEnabled(null, false);
+ log("Disable soft ap");
+ }
+ initializeNetworkStates();
// register a connectivity receiver for CONNECTIVITY_ACTION;
mConnectivityReceiver = new ConnectivityReceiver();
- registerReceiver(mConnectivityReceiver,
+ mContext.registerReceiver(mConnectivityReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mWifiReceiver = new WifiReceiver();
@@ -238,28 +232,15 @@ public class ConnectivityManagerTestActivity extends Activity {
mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
- registerReceiver(mWifiReceiver, mIntentFilter);
+ mContext.registerReceiver(mWifiReceiver, mIntentFilter);
- // Get an instance of ConnectivityManager
- mCM = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
- // Get an instance of WifiManager
- mWifiManager =(WifiManager)getSystemService(Context.WIFI_SERVICE);
- mContext = this;
-
- if (mWifiManager.isWifiApEnabled()) {
- // if soft AP is enabled, disable it
- mWifiManager.setWifiApEnabled(null, false);
- log("Disable soft ap");
- }
-
- initializeNetworkStates();
log("Clear Wifi before we start the test.");
removeConfiguredNetworksAndDisableWifi();
mWifiRegexs = mCM.getTetherableWifiRegexs();
}
public List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
- InputStream in = getAssets().open(ACCESS_POINT_FILE);
+ InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE);
mParseHelper = new AccessPointParserHelper(in);
return mParseHelper.getNetworkConfigurations();
}
@@ -277,6 +258,12 @@ public class ConnectivityManagerTestActivity extends Activity {
public void recordNetworkState(int networkType, State networkState) {
log("record network state for network " + networkType +
", state is " + networkState);
+ if (connectivityState == null) {
+ log("ConnectivityState is null");
+ }
+ if (connectivityState[networkType] == null) {
+ log("connectivityState[networkType] is null");
+ }
connectivityState[networkType].recordState(networkState);
}
@@ -503,7 +490,7 @@ public class ConnectivityManagerTestActivity extends Activity {
public void turnScreenOff() {
log("Turn screen off");
PowerManager pm =
- (PowerManager) getSystemService(Context.POWER_SERVICE);
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
}
@@ -511,8 +498,13 @@ public class ConnectivityManagerTestActivity extends Activity {
public void turnScreenOn() {
log("Turn screen on");
PowerManager pm =
- (PowerManager) getSystemService(Context.POWER_SERVICE);
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(SystemClock.uptimeMillis());
+ // disable lock screen
+ KeyguardManager km = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ if (km.inKeyguardRestrictedInputMode()) {
+ sendKeys(KeyEvent.KEYCODE_MENU);
+ }
}
/**
@@ -607,7 +599,12 @@ public class ConnectivityManagerTestActivity extends Activity {
mWifiManager.setWifiEnabled(true);
sleep(SHORT_TIMEOUT);
}
+
List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+ if (wifiConfigList == null) {
+ log("no configuration list is null");
+ return true;
+ }
log("size of wifiConfigList: " + wifiConfigList.size());
for (WifiConfiguration wifiConfig: wifiConfigList) {
log("remove wifi configuration: " + wifiConfig.networkId);
@@ -656,57 +653,15 @@ public class ConnectivityManagerTestActivity extends Activity {
}
@Override
- protected void onDestroy() {
- super.onDestroy();
-
+ public void tearDown() throws Exception{
//Unregister receiver
if (mConnectivityReceiver != null) {
- unregisterReceiver(mConnectivityReceiver);
+ mContext.unregisterReceiver(mConnectivityReceiver);
}
if (mWifiReceiver != null) {
- unregisterReceiver(mWifiReceiver);
- }
- log("onDestroy, inst=" + Integer.toHexString(hashCode()));
- }
-
- @Override
- public void onStart() {
- super.onStart();
- mContext = this;
- Bundle bundle = this.getIntent().getExtras();
- if (bundle != null){
- mPowerSsid = bundle.getString("power_ssid");
- }
- }
- //A thread to set the device into airplane mode then turn on wifi.
- Thread setDeviceWifiAndAirplaneThread = new Thread(new Runnable() {
- public void run() {
- mCM.setAirplaneMode(true);
- connectToWifi(mPowerSsid);
- }
- });
-
- //A thread to set the device into wifi
- Thread setDeviceInWifiOnlyThread = new Thread(new Runnable() {
- public void run() {
- connectToWifi(mPowerSsid);
- }
- });
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- //This is a tricky way for the scripted monkey to
- //set the device in wifi and wifi in airplane mode.
- case KeyEvent.KEYCODE_1:
- setDeviceWifiAndAirplaneThread.start();
- break;
-
- case KeyEvent.KEYCODE_2:
- setDeviceInWifiOnlyThread.start();
- break;
+ mContext.unregisterReceiver(mWifiReceiver);
}
- return super.onKeyDown(keyCode, event);
+ super.tearDown();
}
private void log(String message) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
index 3a78f26bba39..0e57a006eed0 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerUnitTestRunner.java
@@ -16,10 +16,8 @@
package com.android.connectivitymanagertest;
-import android.os.Bundle;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
-import android.util.Log;
import com.android.connectivitymanagertest.unit.WifiClientTest;
import com.android.connectivitymanagertest.unit.WifiSoftAPTest;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 729e1d25160b..05462b4cdfc2 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -24,31 +24,24 @@ import android.net.wifi.WifiManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.provider.Settings;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import com.android.connectivitymanagertest.NetworkState;
public class ConnectivityManagerMobileTest extends
- ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
- private static final String LOG_TAG = "ConnectivityManagerMobileTest";
+ ConnectivityManagerTestBase {
+ private static final String TAG = "ConnectivityManagerMobileTest";
private String mTestAccessPoint;
- private ConnectivityManagerTestActivity cmActivity;
private WakeLock wl;
private boolean mWifiOnlyFlag;
- public ConnectivityManagerMobileTest() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- cmActivity = getActivity();
ConnectivityManagerTestRunner mRunner =
(ConnectivityManagerTestRunner)getInstrumentation();
mTestAccessPoint = mRunner.mTestSsid;
@@ -62,12 +55,12 @@ public class ConnectivityManagerMobileTest extends
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON) == 1) {
log("airplane is not disabled, disable it.");
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
+ if (!waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT)) {
// Note: When the test fails in setUp(), tearDown is not called. In that case,
// the activity is destroyed which blocks the next test at "getActivity()".
// tearDown() is called here to avoid that situation.
@@ -79,29 +72,22 @@ public class ConnectivityManagerMobileTest extends
@Override
public void tearDown() throws Exception {
- cmActivity.finish();
- log("tear down ConnectivityManagerTestActivity");
wl.release();
- cmActivity.removeConfiguredNetworksAndDisableWifi();
- // if airplane mode is set, disable it.
- if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON) == 1) {
- log("disable airplane mode if it is enabled");
- cmActivity.mCM.setAirplaneMode(false);
- }
+ removeConfiguredNetworksAndDisableWifi();
+ mCM.setAirplaneMode(false);
super.tearDown();
}
// help function to verify 3G connection
public void verifyCellularConnection() {
- NetworkInfo extraNetInfo = cmActivity.mCM.getActiveNetworkInfo();
+ NetworkInfo extraNetInfo = mCM.getActiveNetworkInfo();
assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
extraNetInfo.getType());
assertTrue("not connected to cellular network", extraNetInfo.isConnected());
}
private void log(String message) {
- Log.v(LOG_TAG, message);
+ Log.v(TAG, message);
}
private void sleep(long sleeptime) {
@@ -115,46 +101,46 @@ public class ConnectivityManagerMobileTest extends
@LargeTest
public void test3GToWifiNotification() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
// Enable Wi-Fi to avoid initial UNKNOWN state
- cmActivity.enableWifi();
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ enableWifi();
+ sleep(2 * SHORT_TIMEOUT);
// Wi-Fi is disabled
- cmActivity.disableWifi();
+ disableWifi();
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
// Wait for 10 seconds for broadcasts to be sent out
sleep(10 * 1000);
// As Wifi stays in DISCONNETED, Mobile statys in CONNECTED,
// the connectivity manager will not broadcast any network connectivity event for Wifi
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.DO_NOTHING, State.CONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.DO_NOTHING, State.DISCONNECTED);
// Eanble Wifi without associating with any AP
- cmActivity.enableWifi();
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ enableWifi();
+ sleep(2 * SHORT_TIMEOUT);
// validate state and broadcast
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("the state for WIFI is changed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("state validation fail", false);
}
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("the state for MOBILE is changed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation fail", false);
}
// Verify that the device is still connected to MOBILE
@@ -168,40 +154,39 @@ public class ConnectivityManagerMobileTest extends
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
//Prepare for connectivity verification
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// Enable Wifi and connect to a test access point
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
log("wifi state is enabled");
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
}
@@ -213,61 +198,59 @@ public class ConnectivityManagerMobileTest extends
assertNotNull("SSID is null", mTestAccessPoint);
// Connect to mTestAccessPoint
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ sleep(SHORT_TIMEOUT);
// Disable Wifi
log("Disable Wifi");
- if (!cmActivity.disableWifi()) {
+ if (!disableWifi()) {
log("disable Wifi failed");
return;
}
// Wait for the Wifi state to be DISABLED
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
}
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
//Prepare for connectivity state verification
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(), NetworkState.DO_NOTHING,
State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// wait for 2 minutes before restart wifi
- sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL);
+ sleep(WIFI_STOP_START_INTERVAL);
// Enable Wifi again
log("Enable Wifi again");
- cmActivity.enableWifi();
+ enableWifi();
// Wait for Wifi to be connected and mobile to be disconnected
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate wifi states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -279,48 +262,48 @@ public class ConnectivityManagerMobileTest extends
// connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// Wait for a few seconds to avoid the state that both Mobile and Wifi is connected
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ sleep(SHORT_TIMEOUT);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_CONNECTION,
State.CONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_DISCONNECTION, State.DISCONNECTED);
// clear Wifi
- cmActivity.removeConfiguredNetworksAndDisableWifi();
+ removeConfiguredNetworksAndDisableWifi();
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
}
// validate states
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
}
@@ -330,62 +313,62 @@ public class ConnectivityManagerMobileTest extends
@LargeTest
public void testDataConnectionWith3GToAmTo3G() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
//Prepare for state verification
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_DISCONNECTION,
State.DISCONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
// Enable airplane mode
log("Enable airplane mode");
- cmActivity.mCM.setAirplaneMode(true);
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ mCM.setAirplaneMode(true);
+ sleep(SHORT_TIMEOUT);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
// wait until mobile is turn off
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
// reset state recorder
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.TO_CONNECTION,
State.CONNECTED);
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.DO_NOTHING, State.DISCONNECTED);
// disable airplane mode
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, LONG_TIMEOUT));
// Validate the state transition
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue(false);
}
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -394,107 +377,107 @@ public class ConnectivityManagerMobileTest extends
@LargeTest
public void testDataConnectionOverAMWithWifi() {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
assertNotNull("SSID is null", mTestAccessPoint);
// Eanble airplane mode
log("Enable airplane mode");
- cmActivity.mCM.setAirplaneMode(true);
+ mCM.setAirplaneMode(true);
NetworkInfo networkInfo;
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
NetworkState.DO_NOTHING,
State.DISCONNECTED);
}
- networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
+ networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI, networkInfo.getState(),
NetworkState.TO_CONNECTION, State.CONNECTED);
// Connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// validate state and broadcast
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("state validate for Wifi failed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("State validation failed", false);
}
if (!mWifiOnlyFlag) {
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("state validation for Mobile failed");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
+ getTransitionFailureReason(ConnectivityManager.TYPE_MOBILE));
assertTrue("state validation failed", false);
}
}
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
}
// Test case 7: test connectivity while transit from Wifi->AM->Wifi
@LargeTest
public void testDataConnectionWithWifiToAMToWifi () {
if (mWifiOnlyFlag) {
- Log.v(LOG_TAG, this.getName() + " is excluded for wifi-only test");
+ Log.v(TAG, this.getName() + " is excluded for wifi-only test");
return;
}
// Connect to mTestAccessPoint
assertNotNull("SSID is null", mTestAccessPoint);
// Connect to Wifi
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
+ connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Enable airplane mode without clearing Wifi
- cmActivity.mCM.setAirplaneMode(true);
+ mCM.setAirplaneMode(true);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Prepare for state validation
- NetworkInfo networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ NetworkInfo networkInfo = mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
assertEquals(State.DISCONNECTED, networkInfo.getState());
- cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
+ setStateTransitionCriteria(ConnectivityManager.TYPE_WIFI,
networkInfo.getState(), NetworkState.TO_CONNECTION, State.CONNECTED);
// Disable airplane mode
- cmActivity.mCM.setAirplaneMode(false);
+ mCM.setAirplaneMode(false);
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
if (!mWifiOnlyFlag) {
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
- State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.DISCONNECTED, LONG_TIMEOUT));
}
// validate the state transition
- if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
+ if (!validateNetworkStates(ConnectivityManager.TYPE_WIFI)) {
log("Wifi state transition validation failed.");
log("reason: " +
- cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
+ getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
}
@@ -505,35 +488,33 @@ public class ConnectivityManagerMobileTest extends
assertNotNull("SSID is null", mTestAccessPoint);
//Connect to mTestAccessPoint
assertTrue("failed to connect to " + mTestAccessPoint,
- cmActivity.connectToWifi(mTestAccessPoint));
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifi(mTestAccessPoint));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
assertNotNull("Not associated with any AP",
- cmActivity.mWifiManager.getConnectionInfo().getBSSID());
+ mWifiManager.getConnectionInfo().getBSSID());
try {
- Thread.sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(SHORT_TIMEOUT);
} catch (Exception e) {
log("exception: " + e.toString());
}
// Disconnect from the current AP
log("disconnect from the AP");
- if (!cmActivity.disconnectAP()) {
+ if (!disconnectAP()) {
log("failed to disconnect from " + mTestAccessPoint);
}
// Verify the connectivity state for Wifi is DISCONNECTED
- assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.DISCONNECTED, LONG_TIMEOUT));
- if (!cmActivity.disableWifi()) {
+ if (!disableWifi()) {
log("disable Wifi failed");
return;
}
- assertTrue(cmActivity.waitForWifiState(WifiManager.WIFI_STATE_DISABLED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index f12e62e1fc4b..183f2a99e062 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -16,7 +16,7 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.WifiAssociationTestRunner;
import android.content.Context;
@@ -32,7 +32,6 @@ import android.net.wifi.WifiManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
/**
@@ -43,30 +42,22 @@ import android.util.Log;
* -w com.android.connectivitymanagertest/.WifiAssociationTestRunner"
*/
public class WifiAssociationTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private static final String TAG = "WifiAssociationTest";
- private ConnectivityManagerTestActivity mAct;
private String mSsid = null;
private String mPassword = null;
private String mSecurityType = null;
private String mFrequencyBand = null;
private int mBand;
- private WifiManager mWifiManager = null;
enum SECURITY_TYPE {
OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES
- };
-
- public WifiAssociationTest() {
- super(ConnectivityManagerTestActivity.class);
}
@Override
public void setUp() throws Exception {
super.setUp();
WifiAssociationTestRunner mRunner = (WifiAssociationTestRunner)getInstrumentation();
- mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
- mAct = getActivity();
Bundle arguments = mRunner.getArguments();
mSecurityType = arguments.getString("security-type");
mSsid = arguments.getString("ssid");
@@ -77,17 +68,15 @@ public class WifiAssociationTest
assertNotNull("Ssid is empty", mSsid);
validateFrequencyBand();
// enable Wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", mAct.enableWifi());
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interrupted while waiting for WPA_SUPPLICANT to start");
- WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+ assertTrue("enable Wifi failed", enableWifi());
+ sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+ WifiInfo mConnection = mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
- assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+ assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
}
@Override
public void tearDown() throws Exception {
- log("tearDown()");
super.tearDown();
}
@@ -107,16 +96,16 @@ public class WifiAssociationTest
private void connectToWifi(WifiConfiguration config) {
// step 1: connect to the test access point
assertTrue("failed to associate with " + config.SSID,
- mAct.connectToWifiWithConfiguration(config));
+ connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
assertTrue("failed to connect with " + config.SSID,
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
- assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
- assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
+ assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
}
private void sleep(long sometime, String errorMsg) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index de0298e8c325..ad73ee1f4ed9 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -16,35 +16,19 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-import android.R;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
import android.content.Context;
-import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiConfiguration.Status;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.ConnectivityManager;
-import android.net.DhcpInfo;
-import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
-import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
-import com.android.internal.util.AsyncChannel;
-
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -56,39 +40,25 @@ import java.util.Set;
* -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
*/
public class WifiConnectionTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private static final String TAG = "WifiConnectionTest";
private static final boolean DEBUG = false;
private List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
- private ConnectivityManagerTestActivity mAct;
- private ConnectivityManagerTestRunner mRunner;
- private WifiManager mWifiManager = null;
- private Set<WifiConfiguration> enabledNetworks = null;
-
- public WifiConnectionTest() {
- super(ConnectivityManagerTestActivity.class);
- }
@Override
public void setUp() throws Exception {
super.setUp();
- mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
- mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
-
- mAct = getActivity();
-
- networks = mAct.loadNetworkConfigurations();
+ networks = loadNetworkConfigurations();
if (DEBUG) {
printNetworkConfigurations();
}
// enable Wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", mAct.enableWifi());
- sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interrupted while waiting for WPA_SUPPLICANT to start");
- WifiInfo mConnection = mAct.mWifiManager.getConnectionInfo();
+ assertTrue("enable Wifi failed", enableWifi());
+ sleep(2 * SHORT_TIMEOUT, "interrupted while waiting for WPA_SUPPLICANT to start");
+ WifiInfo mConnection = mWifiManager.getConnectionInfo();
assertNotNull(mConnection);
- assertTrue("wpa_supplicant is not started ", mAct.mWifiManager.pingSupplicant());
+ assertTrue("wpa_supplicant is not started ", mWifiManager.pingSupplicant());
}
private void printNetworkConfigurations() {
@@ -101,8 +71,7 @@ public class WifiConnectionTest
@Override
public void tearDown() throws Exception {
- log("tearDown()");
- mAct.removeConfiguredNetworksAndDisableWifi();
+ removeConfiguredNetworksAndDisableWifi();
super.tearDown();
}
@@ -114,20 +83,20 @@ public class WifiConnectionTest
private void connectToWifi(WifiConfiguration config) {
// step 1: connect to the test access point
assertTrue("failed to connect to " + config.SSID,
- mAct.connectToWifiWithConfiguration(config));
+ connectToWifiWithConfiguration(config));
// step 2: verify Wifi state and network state;
- assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI,
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
- assertNotNull("Wifi connection returns null", mAct.mWifiManager.getConnectionInfo());
+ assertNotNull("Wifi connection returns null", mWifiManager.getConnectionInfo());
if (DEBUG) {
log("config.SSID = " + config.SSID);
- log("mAct.mWifiManager.getConnectionInfo.getSSID()" +
- mAct.mWifiManager.getConnectionInfo().getSSID());
+ log("mWifiManager.getConnectionInfo.getSSID()" +
+ mWifiManager.getConnectionInfo().getSSID());
}
- assertTrue(config.SSID.contains(mAct.mWifiManager.getConnectionInfo().getSSID()));
+ assertTrue(config.SSID.contains(mWifiManager.getConnectionInfo().getSSID()));
}
private void sleep(long sometime, String errorMsg) {
@@ -149,8 +118,7 @@ public class WifiConnectionTest
log("-- START Wi-Fi connection test to : " + ssid + " --");
connectToWifi(networks.get(i));
// wait for 2 minutes between wifi stop and start
- sleep(ConnectivityManagerTestActivity.WIFI_STOP_START_INTERVAL,
- "interruped while connected to wifi");
+ sleep(WIFI_STOP_START_INTERVAL, "interruped while connected to wifi");
log("-- END Wi-Fi connection test to " + ssid + " -- ");
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 60595fbf2fc1..790ca3840982 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -18,19 +18,13 @@ package com.android.connectivitymanagertest.stress;
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
-import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiManager;
import android.os.Environment;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -42,30 +36,24 @@ import java.io.FileWriter;
* Stress the wifi driver as access point.
*/
public class WifiApStress
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private final static String TAG = "WifiApStress";
private static String NETWORK_ID = "AndroidAPTest";
private static String PASSWD = "androidwifi";
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
- private ConnectivityManagerTestActivity mAct;
private int iterations;
private BufferedWriter mOutputWriter = null;
private int mLastIteration = 0;
private boolean mWifiOnlyFlag;
- public WifiApStress() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- mAct = getActivity();
ConnectivityManagerStressTestRunner mRunner =
(ConnectivityManagerStressTestRunner)getInstrumentation();
iterations = mRunner.mSoftapIterations;
mWifiOnlyFlag = mRunner.mWifiOnlyFlag;
- mAct.turnScreenOn();
+ turnScreenOn();
}
@Override
@@ -92,30 +80,28 @@ public class WifiApStress
config.preSharedKey = PASSWD;
// If Wifi is enabled, disable it
- if (mAct.mWifiManager.isWifiEnabled()) {
- mAct.disableWifi();
+ if (mWifiManager.isWifiEnabled()) {
+ disableWifi();
}
int i;
for (i = 0; i < iterations; i++) {
Log.v(TAG, "iteration: " + i);
mLastIteration = i;
// enable Wifi tethering
- assertTrue(mAct.mWifiManager.setWifiApEnabled(config, true));
+ assertTrue(mWifiManager.setWifiApEnabled(config, true));
// Wait for wifi ap state to be ENABLED
- assertTrue(mAct.waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED,
- 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue(waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED, 2 * LONG_TIMEOUT));
// Wait for wifi tethering result
- assertEquals(ConnectivityManagerTestActivity.SUCCESS,
- mAct.waitForTetherStateChange(2*ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ assertEquals(SUCCESS, waitForTetherStateChange(2 * SHORT_TIMEOUT));
// Allow the wifi tethering to be enabled for 10 seconds
try {
- Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
+ Thread.sleep(2 * SHORT_TIMEOUT);
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
- assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
+ assertTrue("no uplink data connection after Wi-Fi tethering", pingTest(null));
// Disable soft AP
- assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
+ assertTrue(mWifiManager.setWifiApEnabled(config, false));
// Wait for 30 seconds until Wi-Fi tethering is stopped
try {
Thread.sleep(30 * 1000);
@@ -123,7 +109,7 @@ public class WifiApStress
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
- assertFalse("Wi-Fi AP disable failed", mAct.mWifiManager.isWifiApEnabled());
+ assertFalse("Wi-Fi AP disable failed", mWifiManager.isWifiApEnabled());
}
if (i == iterations) {
mLastIteration = iterations;
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index e3c7cc402a9d..04ce4b75486c 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -29,12 +29,11 @@ import android.os.Environment;
import android.os.PowerManager;
import android.provider.Settings;
import android.view.KeyEvent;
-import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import java.io.BufferedWriter;
import java.io.File;
@@ -50,7 +49,7 @@ import java.util.List;
* -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
*/
public class WifiStressTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ extends ConnectivityManagerTestBase {
private final static String TAG = "WifiStressTest";
/**
@@ -67,7 +66,6 @@ public class WifiStressTest
private final static long WIFI_SHUTDOWN_DELAY = 2 * 60 * 1000;
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
- private ConnectivityManagerTestActivity mAct;
private int mReconnectIterations;
private int mWifiSleepTime;
private int mScanIterations;
@@ -77,15 +75,10 @@ public class WifiStressTest
private BufferedWriter mOutputWriter = null;
private boolean mWifiOnlyFlag;
- public WifiStressTest() {
- super(ConnectivityManagerTestActivity.class);
- }
-
@Override
public void setUp() throws Exception {
super.setUp();
- mAct = getActivity();
mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation();
mReconnectIterations = mRunner.mReconnectIterations;
mSsid = mRunner.mReconnectSsid;
@@ -98,15 +91,14 @@ public class WifiStressTest
mPassword, mScanIterations, mWifiSleepTime));
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
- mAct.turnScreenOn();
- if (!mAct.mWifiManager.isWifiEnabled()) {
+ turnScreenOn();
+ if (!mWifiManager.isWifiEnabled()) {
log("Enable wi-fi before stress tests.");
- if (!mAct.enableWifi()) {
+ if (!enableWifi()) {
tearDown();
fail("enable wifi failed.");
}
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "Interruped while waiting for wifi on");
+ sleep(SHORT_TIMEOUT, "Interruped while waiting for wifi on");
}
}
@@ -166,33 +158,32 @@ public class WifiStressTest
writeOutput(String.format("ssid appear %d out of %d scan iterations",
ssidAppearInScanResultsCount, i));
long startTime = System.currentTimeMillis();
- mAct.scanResultAvailable = false;
- assertTrue("start scan failed", mAct.mWifiManager.startScan());
+ scanResultAvailable = false;
+ assertTrue("start scan failed", mWifiManager.startScan());
while (true) {
if ((System.currentTimeMillis() - startTime) >
- ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
- fail("Wifi scanning takes more than " +
- ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT + " ms");
+ WIFI_SCAN_TIMEOUT) {
+ fail("Wifi scanning takes more than " + WIFI_SCAN_TIMEOUT + " ms");
}
- synchronized(mAct) {
+ synchronized(this) {
try {
- mAct.wait(ConnectivityManagerTestActivity.WAIT_FOR_SCAN_RESULT);
+ wait(WAIT_FOR_SCAN_RESULT);
} catch (InterruptedException e) {
e.printStackTrace();
}
- if (mAct.scanResultAvailable) {
+ if (scanResultAvailable) {
long scanTime = (System.currentTimeMillis() - startTime);
scanTimeSum += scanTime;
break;
}
}
}
- if ((mAct.mWifiManager.getScanResults() == null) ||
- (mAct.mWifiManager.getScanResults().size() <= 0)) {
+ if ((mWifiManager.getScanResults() == null) ||
+ (mWifiManager.getScanResults().size() <= 0)) {
fail("Scan results are empty ");
}
- List<ScanResult> netList = mAct.mWifiManager.getScanResults();
+ List<ScanResult> netList = mWifiManager.getScanResults();
if (netList != null) {
log("size of scan result list: " + netList.size());
for (int s = 0; s < netList.size(); s++) {
@@ -244,13 +235,13 @@ public class WifiStressTest
config.proxySettings = ProxySettings.NONE;
assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
- mAct.connectToWifiWithConfiguration(config));
- assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
- assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ connectToWifiWithConfiguration(config));
+ assertTrue(waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ SHORT_TIMEOUT));
+ assertTrue(waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
// Run ping test to verify the data connection
- assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
+ assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null));
int i;
long sum = 0;
@@ -263,33 +254,33 @@ public class WifiStressTest
writeOutput(String.format("iteration %d out of %d",
i, mReconnectIterations));
log("iteration: " + i);
- mAct.turnScreenOff();
+ turnScreenOff();
PowerManager pm =
(PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
assertFalse(pm.isScreenOn());
sleep(WIFI_IDLE_MS + WIFI_SHUTDOWN_DELAY, "Interruped while wait for wifi to be idle");
assertTrue("Wait for Wi-Fi to idle timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
- 6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ 6 * SHORT_TIMEOUT));
if (!mWifiOnlyFlag) {
// use long timeout as the pppd startup may take several retries.
assertTrue("Wait for cellular connection timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- 2 * ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ 2 * LONG_TIMEOUT));
}
sleep(mWifiSleepTime, "Interrupted while device is in sleep mode");
// Verify the wi-fi is still off and data connection is on
assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
+ mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
if (!mWifiOnlyFlag) {
assertEquals("Cellular connection is down", State.CONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
- assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+ mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+ assertTrue("Mobile is connected, but no data connection.", pingTest(null));
}
// Turn screen on again
- mAct.turnScreenOn();
+ turnScreenOn();
// Wait for 2 seconds for the lock screen
sleep(2 * 1000, "wait 2 seconds for lock screen");
// Disable lock screen by inject menu key event
@@ -298,16 +289,16 @@ public class WifiStressTest
// Measure the time for Wi-Fi to get connected
long startTime = System.currentTimeMillis();
assertTrue("Wait for Wi-Fi enable timeout after wake up",
- mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
- ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ SHORT_TIMEOUT));
assertTrue("Wait for Wi-Fi connection timeout after wake up",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
- ConnectivityManagerTestActivity.WIFI_CONNECTION_TIMEOUT));
+ waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ WIFI_CONNECTION_TIMEOUT));
long connectionTime = System.currentTimeMillis() - startTime;
sum += connectionTime;
log("average reconnection time is: " + sum/(i+1));
- assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null));
+ assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
}
if (i == mReconnectIterations) {
writeOutput(String.format("iteration %d out of %d",
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
index e44023bff472..7a9bc7815d97 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiClientTest.java
@@ -20,9 +20,6 @@ import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration;
@@ -33,11 +30,8 @@ import android.net.wifi.SupplicantState;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
import java.util.List;
-import android.util.Log;
-
/**
* Test wifi client
*/
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
index 3f43e4851c4f..f202862f6dbf 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/unit/WifiSoftAPTest.java
@@ -16,13 +16,7 @@
package com.android.connectivitymanagertest.unit;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
import android.content.Context;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -30,8 +24,6 @@ import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
-
import android.util.Log;
/**
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index ebecf2e38e6f..a2e9ae89e255 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -83,8 +83,8 @@ public class VirtualDisplayTest extends AndroidTestCase {
mImageReaderLock.lock();
try {
- mImageReader = new ImageReader(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
- mImageReader.setImageAvailableListener(mImageListener, mHandler);
+ mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888, 2);
+ mImageReader.setOnImageAvailableListener(mImageListener, mHandler);
mSurface = mImageReader.getSurface();
} finally {
mImageReaderLock.unlock();
@@ -409,19 +409,11 @@ public class VirtualDisplayTest extends AndroidTestCase {
}
Log.d(TAG, "New image available from virtual display.");
- Image image = reader.getNextImage();
+
+ // Get the latest buffer.
+ Image image = reader.acquireLatestImage();
if (image != null) {
try {
- // Get the latest buffer.
- for (;;) {
- Image nextImage = reader.getNextImage();
- if (nextImage == null) {
- break;
- }
- reader.releaseImage(image);
- image = nextImage;
- }
-
// Scan for colors.
int color = scanImage(image);
synchronized (this) {
@@ -431,7 +423,7 @@ public class VirtualDisplayTest extends AndroidTestCase {
}
}
} finally {
- reader.releaseImage(image);
+ image.close();
}
}
} finally {
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 607d16e03665..14a16822c613 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -10,6 +10,11 @@ parent.link=index.html
<ol>
<li><a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a></li>
+ <li><a href="#access-rs-apis">Accessing RenderScript Java APIs</a>
+ <ol>
+ <li><a href="#ide-setup">Setting Up Your Development Environment</a></li>
+ </ol>
+ </li>
<li><a href="#using-rs-from-java">Using RenderScript from Java Code</a></li>
</ol>
@@ -144,9 +149,85 @@ different level of floating point precision:</p>
beneficial on some architectures due to additional optimizations only available with relaxed
precision (such as SIMD CPU instructions).</p>
+
+<h2 id="access-rs-apis">Accessing RenderScript Java APIs</h2>
+
+<p>When developing an Android application that uses RenderScript, you can access its Java API in
+ one of two ways. The APIs are available in the {@link android.renderscript} package
+ on devices running Android 3.0 (API level 11) and higher. These are the original APIs for
+ RenderScript. The APIs are also available as a Support Library in the
+ {@link android.support.v8.renderscript} package, which allow you to use them on devices running
+ Android 2.2 (API level 8) and higher.</p>
+
+<p>We strongly recommend using the Support Library APIs for accessing RenderScript because they
+ include the latest improvements to the RenderScript compute framework and provide a wider range
+ of device compatibility. Using the RenderScript APIs in the Support Library requires specific
+ setup procedures for your development environment, which is described in the next section.</p>
+
+
+<h3 id="ide-setup">Using the RenderScript Support Library APIs</h3>
+
+<p>In order to use the Support Library RenderScript APIs, you must configure your development
+ environment to be able to access them. The following Android SDK tools are required for using
+ these APIs:</p>
+
+<ul>
+ <li>Android SDK Tools revision 22.2 or higher</li>
+ <li>Android SDK Build-tools revision 18.1.0 or higher</li>
+</ul>
+
+<p>You can check and update the installed version of these tools in the
+ <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</p>
+
+<p class="note">
+ <strong>Note:</strong> Use of Support Library RenderScript APIs is not currently supported with
+ Android Studio or Gradle-based builds.
+</p>
+
+<p>To use the Support Library RenderScript APIs in Eclipse:</p>
+
+<ol>
+ <li>Make sure you have the required Android SDK version and Build Tools version installed.</li>
+ <li>Open the {@code project.properties} file in the root folder of your application project.</li>
+ <li>Add the following lines to the file:
+<pre>
+renderscript.target=18
+renderscript.support.mode=true
+sdk.buildtools=18.1.0
+</pre>
+ </li>
+ <li>In your application classes that use RenderScript, add an import for the Support Library
+ classes:
+<pre>
+import android.support.v8.renderscript.*;
+</pre>
+ </li>
+</ol>
+
+<p>The {@code project.properties} settings listed above control specific behavior in the Android
+ build process:</p>
+
+<ul>
+ <li>{@code renderscript.target} - Specifies the bytecode version to be generated. We
+ recommend you set this value the highest available API level and set {@code
+ renderscript.support.mode} to {@code true}. Valid values for this setting are any integer value
+ from 11 to the most recently released API level. If your minimum SDK version specified in your
+ application manifest is set to a higher value, this value is ignored and the target value is set
+ to the minimum SDK version.</li>
+ <li>{@code renderscript.support.mode} - Specifies that the generated bytecode should fall
+ back to a compatible version if the device it is running on does not support the target version.
+ </li>
+ <li>{@code sdk.buildtools} - The version of the Android SDK build tools to use. This value
+ should be set to 18.1.0 or higher. If this option is not specified, the highest installed build
+ tools version is used. You should always set this value to ensure the consistency of builds
+ across development machines with different configurations.</li>
+</ul>
+
+
<h2 id="using-rs-from-java">Using RenderScript from Java Code</h2>
-<p>Using RenderScript from Java code relies on the {@link android.renderscript} APIs. Most
+<p>Using RenderScript from Java code relies on the API classes located in the
+{@link android.renderscript} or the {@link android.support.v8.renderscript} package. Most
applications follow the same basic usage patterns:</p>
<ol>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 4ea375263d7d..05814350311b 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@ header.hide=1
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130729.zip
-sdk.linux32_bundle_bytes=457716139
-sdk.linux32_bundle_checksum=b3686d10dc1cbceba1074404d4386283
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130911.zip
+sdk.linux32_bundle_bytes=474916528
+sdk.linux32_bundle_checksum=7eacc7124299ea99a8fa15c59123540f
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130729.zip
-sdk.linux64_bundle_bytes=458006784
-sdk.linux64_bundle_checksum=1fabcc3f772ba8b2fc194d6e0449da17
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130911.zip
+sdk.linux64_bundle_bytes=475207785
+sdk.linux64_bundle_checksum=daa5794a27be7c7fa708c3d28833b0d3
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130729.zip
-sdk.mac64_bundle_bytes=428792424
-sdk.mac64_bundle_checksum=6c42b9966abcfa8a75c0ee83d0d95882
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130911.zip
+sdk.mac64_bundle_bytes=448575446
+sdk.mac64_bundle_checksum=a1e0cbcc820ae734cfdf439c40811b4c
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130729.zip
-sdk.win32_bundle_bytes=463931746
-sdk.win32_bundle_checksum=51faf4e5fdf9c5b4a176179a99ce3511
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130911.zip
+sdk.win32_bundle_bytes=481794820
+sdk.win32_bundle_checksum=88a2f4f242aac44f4b1c53e6eccc8710
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130729.zip
-sdk.win64_bundle_bytes=464064756
-sdk.win64_bundle_checksum=e8f05c1fddb8e609e880de23113c7426
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130911.zip
+sdk.win64_bundle_bytes=481927327
+sdk.win64_bundle_checksum=e3fa9b7e38af9ed9ac0e99fce3c7026c
-sdk.linux_download=android-sdk_r22.0.5-linux.tgz
-sdk.linux_bytes=105641005
-sdk.linux_checksum=8201b10c21510f082c54f58a9bb082c8
+sdk.linux_download=android-sdk_r22.2-linux.tgz
+sdk.linux_bytes=100909403
+sdk.linux_checksum=2a3776839e823ba9acb7a87a3fe26e02
-sdk.mac_download=android-sdk_r22.0.5-macosx.zip
-sdk.mac_bytes=77225724
-sdk.mac_checksum=94f3cbe896c332b94ee0408ae610a4b8
+sdk.mac_download=android-sdk_r22.2-macosx.zip
+sdk.mac_bytes=74857114
+sdk.mac_checksum=9dfef6404e2f842c433073796aed8b7d
-sdk.win_download=android-sdk_r22.0.5-windows.zip
-sdk.win_bytes=113510621
-sdk.win_checksum=30695dffc41e0d7cf9ff948ab0c48920
+sdk.win_download=android-sdk_r22.2-windows.zip
+sdk.win_bytes=108790714
+sdk.win_checksum=1ac4c104378cd53049daa6c4458ec544
-sdk.win_installer=installer_r22.0.5-windows.exe
-sdk.win_installer_bytes=93505782
-sdk.win_installer_checksum=940849be19ac6151e3e35c8706c81d86
+sdk.win_installer=installer_r22.2-windows.exe
+sdk.win_installer_bytes=88788974
+sdk.win_installer_checksum=e5503fa059297d2b18475c086ac6e80c
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index bdc07d02283d..e038d2089e3b 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
-adt.zip.version=22.0.5
-adt.zip.download=ADT-22.0.5.zip
-adt.zip.bytes=16839757
-adt.zip.checksum=1097fccf32063e3638a9d27aa0f295ca
+adt.zip.version=22.2.0
+adt.zip.download=ADT-22.2.0.zip
+adt.zip.bytes=14474195
+adt.zip.checksum=52892c9e3b1ad2d1e6edd50e48b2a127
@jd:body
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index e9c514e064d3..151707a3fa84 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,44 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 22.2</a> <em>(September 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.2</a>.
+ If you haven't already installed SDK Tools r22.2 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Updated build tools to allow use of RenderScript on older versions of Android
+ using new features in the
+ <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+ <li>Reverted signing changes that sometimes trigger a signing verification problem on older
+ platforms.</li>
+ <li>Fixed problem with gradle export function for the Windows platform.</li>
+ </ul>
+ </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 22.0.5</a> <em>(July 2013)</em>
</p>
@@ -78,7 +116,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed Renderscript compilation issue for Windows platforms.</li>
+ <li>Fixed RenderScript compilation issue for Windows platforms.</li>
<li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> report generation
in the Monitor and DDMS perspectives.</li>
</ul>
@@ -113,7 +151,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed problem with compiling Renderscript code.</li>
+ <li>Fixed problem with compiling RenderScript code.</li>
<li>Improved Gradle export with better workflow and error reporting.</li>
<li>Improved Gradle multi-module export feature.</li>
<li>Updated build logic to force exporting of the classpath containers unless you are using
@@ -1005,7 +1043,7 @@ href="http://tools.android.com/recent/lint">more info</a>)</li>
<dt>Bug fixes:</dt>
<dd>
<ul>
- <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+ <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
(<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
<li>Fixed issue when creating projects from existing source code.</li>
<li>Fixed issues in the SDK Manager
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 4aef8a028505..e8c471765011 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -30,6 +30,54 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 22.2</a> <em>(September 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 16 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+ designed for use with ADT 22.2 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.2.</li>
+ <li>If you are developing outside Eclipse, you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Updated build tools to allow use of RenderScript on older versions of Android
+ using new features in the
+ <a href="{@docRoot}tools/support-library/features.html#v8">Support Library</a>.</li>
+ <li>Moved the Systrace tool to the {@code &gt;sdk&lt;/platform-tools/} directory. </li>
+ <li>Modified <a href="{@docRoot}tools/help/gltracer.html">Tracer for OpenGL ES</a> to
+ support OpenGL ES 3.0.</li>
+ <li>Lint
+ <ul>
+ <li>Fixed problem with lint not detecting custom namespaces.
+ (<a href="http://b.android.com/55673">Issue 55673</a>)</li>
+ <li>Fixed problem with the XML report including invalid characters.
+ (<a href="http://b.android.com/56205">Issue 56205</a>)</li>
+ <li>Fixed command-line execution of lint to work in headless mode to support execution
+ by build servers. (<a href="http://b.android.com/55820">Issue 55820</a>)</li>
+ </ul>
+ </li>
+ <li>Improved support for path names with spaces in the Windows command-line tools.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 22.0.5</a> <em>(July 2013)</em>
</p>
@@ -55,10 +103,10 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed Renderscript compilation issue for Windows platforms with ant.</li>
+ <li>Fixed RenderScript compilation issue for Windows platforms with ant.</li>
<li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> to work with the
Android 4.3 platform image.</li>
- <li>Fixed packaging of Renderscript compiler.</li>
+ <li>Fixed packaging of RenderScript compiler.</li>
<li>Build tools 18.0.0 is obsolete and 18.0.1 should be used instead.</li>
</ul>
</dd>
@@ -95,7 +143,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<dt>General Notes:</dt>
<dd>
<ul>
- <li>Fixed problem with compiling Renderscript code.</li>
+ <li>Fixed problem with compiling RenderScript code.</li>
</ul>
</dd>
</dl>
@@ -274,17 +322,17 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
</ul>
</li>
- <li>Renderscript
+ <li>RenderScript
<ul>
<li>Added support for
<a href="{@docRoot}guide/topics/renderscript/compute.html#filterscript">Filterscript</a>
compilation.</li>
- <li>Added new project setting to control the Renderscript compilation target separately
+ <li>Added new project setting to control the RenderScript compilation target separately
from an Android project. Adding the following line to a {@code project.properties}
- file causes Renderscript code to be compiled for Android API Level 17, while the
+ file causes RenderScript code to be compiled for Android API Level 17, while the
containing application can target a different (lower) API level:
<pre>renderscript.target = 17</pre>
- Previously, the Renderscript compilation target was tied to the
+ Previously, the RenderScript compilation target was tied to the
{@code android:minSdkVersion} setting in the manifest.
(<a href="http://code.google.com/p/android/issues/detail?id=40487">Issue 40487</a>)
</li>
@@ -483,7 +531,7 @@ with GPU acceleration.</li>
<li>Improved resize algorithm for better rendering on scaled emulator windows.</li>
<li>Fixed a bug in the {@code lint} check for unprotected broadcast receivers to ignore
unprotected receivers for default Android actions.</li>
- <li>Fixed build issue for projects using Renderscript.</li>
+ <li>Fixed build issue for projects using RenderScript.</li>
<li>Fixed memory leak in the emulator.</li>
</ul>
</dd>
@@ -823,7 +871,7 @@ ignore attribute. (<a
<li>Fixed emulator crash on Linux due to improper webcam detection
(<a href="http://code.google.com/p/android/issues/detail?id=20952">Issue 20952</a>).</li>
<li>Fixed emulator issue when using the <code>-wipe-data</code> argument.</li>
- <li>Fixed build issue when using Renderscript in projects that target API levels 11-13
+ <li>Fixed build issue when using RenderScript in projects that target API levels 11-13
(<a href="http://code.google.com/p/android/issues/detail?id=21006">Issue 21006</a>).</li>
<li>Fixed issue when creating an AVD using the GoogleTV addon
(<a href="http://code.google.com/p/android/issues/detail?id=20963">Issue 20963</a>).</li>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 8d25d96c9116..65148bf2d2ff 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -15,6 +15,7 @@ page.title=Support Library Features
<li><a href="#v7-mediarouter">v7 mediarouter library</a></li>
</ol>
</li>
+ <li><a href="#v8">v8 Support Library</a></li>
<li><a href="#v13">v13 Support Library</a></li>
</ol>
@@ -252,7 +253,7 @@ script dependency identifier <code>com.android.support:support-v7-mediarouter:&l
where "18.0.0" is the minimum revision at which the library is available. For example:</p>
<pre>
-com.android.support:support-v7-mediarouter:18.0.0
+com.android.support:mediarouter-v7:18.0.+
</pre>
<p class="caution">The v7 mediarouter library APIs introduced in Support Library
@@ -262,6 +263,24 @@ href="https://developers.google.com/cast/">Google Cast
developer preview</a>. </p>
+<h2 id="v8">v8 Support Library</h2>
+
+<p>This library is designed to be used with Android (API level 8) and higher. It adds support for
+ the <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> computation
+ framework. These APIs are included in the {@link android.support.v8.renderscript} package. You
+ should be aware that the steps for including these APIs in your application is <em>very
+ different</em> from other support library APIs. For more information about using these APIs
+ in your application, see the
+ <a href="{@docRoot}guide/topics/renderscript/compute.html#access-rs-apis">RenderScript</a>
+ developer guide.</p>
+
+<p class="note">
+ <strong>Note:</strong> Use of RenderScript with the support library is supported with the Android
+ Eclipse plugin and Ant build tools. It is <em>not currently</em> supported with Android Studio or
+ Gradle-based builds.
+</p>
+
+
<h2 id="v13">v13 Support Library</h2>
<p>This library is designed to be used for Android 3.2 (API level 13) and higher. It adds support
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 06c7a3ff638a..4ee8c1289fc5 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -58,6 +58,7 @@ page.title=Support Library
<p>This section provides details about the Support Library package releases.</p>
+
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 9f442f57f9b1..a346e176984e 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -16,20 +16,19 @@
package android.media;
-import android.graphics.ImageFormat;
import java.nio.ByteBuffer;
import java.lang.AutoCloseable;
/**
* <p>A single complete image buffer to use with a media source such as a
* {@link MediaCodec} or a
- * {@link android.hardware.camera2.CameraDevice}.</p>
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
*
* <p>This class allows for efficient direct application access to the pixel
* data of the Image through one or more
* {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
* {@link Plane} that describes the layout of the pixel data in that plane. Due
- * to this direct access, and unlike the {@link android.graphics.Bitmap} class,
+ * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
* Images are not directly usable as as UI resources.</p>
*
* <p>Since Images are often directly produced or consumed by hardware
@@ -40,19 +39,28 @@ import java.lang.AutoCloseable;
* from various media sources, not closing old Image objects will prevent the
* availability of new Images once
* {@link ImageReader#getMaxImages the maximum outstanding image count} is
- * reached.</p>
+ * reached. When this happens, the function acquiring new Images will typically
+ * throw an {@link IllegalStateException}.</p>
*
* @see ImageReader
*/
-public interface Image extends AutoCloseable {
+public abstract class Image implements AutoCloseable {
+ /**
+ * @hide
+ */
+ protected Image() {
+ }
+
/**
* Get the format for this image. This format determines the number of
* ByteBuffers needed to represent the image, and the general layout of the
* pixel data in each in ByteBuffer.
*
+ * <p>
* The format is one of the values from
- * {@link android.graphics.ImageFormat}. The mapping between the formats and
- * the planes is as follows:
+ * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
+ * formats and the planes is as follows:
+ * </p>
*
* <table>
* <tr>
@@ -61,13 +69,14 @@ public interface Image extends AutoCloseable {
* <th>Layout details</th>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#JPEG}</td>
+ * <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
* <td>1</td>
* <td>Compressed data, so row and pixel strides are 0. To uncompress, use
- * {@link android.graphics.BitmapFactory#decodeByteArray}.</td>
+ * {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
+ * </td>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#YUV_420_888}</td>
+ * <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
* <td>3</td>
* <td>A luminance plane followed by the Cb and Cr chroma planes.
* The chroma planes have half the width and height of the luminance
@@ -75,53 +84,60 @@ public interface Image extends AutoCloseable {
* Each plane has its own row stride and pixel stride.</td>
* </tr>
* <tr>
- * <td>{@link android.graphics.ImageFormat#RAW_SENSOR}</td>
+ * <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
* <td>1</td>
* <td>A single plane of raw sensor image data, with 16 bits per color
* sample. The details of the layout need to be queried from the source of
* the raw sensor data, such as
- * {@link android.hardware.camera2.CameraDevice}.
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.
* </td>
* </tr>
* </table>
*
* @see android.graphics.ImageFormat
*/
- public int getFormat();
+ public abstract int getFormat();
/**
* The width of the image in pixels. For formats where some color channels
* are subsampled, this is the width of the largest-resolution plane.
*/
- public int getWidth();
+ public abstract int getWidth();
/**
* The height of the image in pixels. For formats where some color channels
* are subsampled, this is the height of the largest-resolution plane.
*/
- public int getHeight();
+ public abstract int getHeight();
/**
- * Get the timestamp associated with this frame. The timestamp is measured
- * in nanoseconds, and is monotonically increasing. However, the zero point
- * and whether the timestamp can be compared against other sources of time
- * or images depend on the source of this image.
+ * Get the timestamp associated with this frame.
+ * <p>
+ * The timestamp is measured in nanoseconds, and is monotonically
+ * increasing. However, the zero point and whether the timestamp can be
+ * compared against other sources of time or images depend on the source of
+ * this image.
+ * </p>
*/
- public long getTimestamp();
+ public abstract long getTimestamp();
/**
* Get the array of pixel planes for this Image. The number of planes is
* determined by the format of the Image.
*/
- public Plane[] getPlanes();
+ public abstract Plane[] getPlanes();
/**
- * Free up this frame for reuse. After calling this method, calling any
- * methods on this Image will result in an IllegalStateException, and
- * attempting to read from ByteBuffers returned by an earlier
- * {@code Plane#getBuffer} call will have undefined behavior.
+ * Free up this frame for reuse.
+ * <p>
+ * After calling this method, calling any methods on this {@code Image} will
+ * result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Plane#getBuffer} call will have undefined behavior.
+ * </p>
*/
- public void close();
+ @Override
+ public abstract void close();
/**
* <p>A single color plane of image data.</p>
@@ -134,29 +150,41 @@ public interface Image extends AutoCloseable {
*
* @see #getFormat
*/
- public interface Plane {
+ public static abstract class Plane {
/**
- * <p>The row stride for this color plane, in bytes.
+ * @hide
+ */
+ protected Plane() {
+ }
+
+ /**
+ * <p>The row stride for this color plane, in bytes.</p>
*
* <p>This is the distance between the start of two consecutive rows of
- * pixels in the image.</p>
+ * pixels in the image. The row stride is always greater than 0.</p>
*/
- public int getRowStride();
+ public abstract int getRowStride();
/**
* <p>The distance between adjacent pixel samples, in bytes.</p>
*
* <p>This is the distance between two consecutive pixel values in a row
* of pixels. It may be larger than the size of a single pixel to
- * account for interleaved image data or padded formats.</p>
+ * account for interleaved image data or padded formats.
+ * The pixel stride is always greater than 0.</p>
*/
- public int getPixelStride();
+ public abstract int getPixelStride();
/**
- * <p>Get a set of direct {@link java.nio.ByteBuffer byte buffers}
+ * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
* containing the frame data.</p>
*
+ * <p>In particular, the buffer returned will always have
+ * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
+ * the underlying data could be mapped as a pointer in JNI without doing
+ * any copies with {@code GetDirectBufferAddress}.</p>
+ *
* @return the byte buffer containing the image data for this plane.
*/
- public ByteBuffer getBuffer();
+ public abstract ByteBuffer getBuffer();
}
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index b14a899f33fa..aee83627bb0e 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -40,41 +40,67 @@ import java.nio.ByteOrder;
* <p>The image data is encapsulated in {@link Image} objects, and multiple such
* objects can be accessed at the same time, up to the number specified by the
* {@code maxImages} constructor parameter. New images sent to an ImageReader
- * through its Surface are queued until accessed through the
- * {@link #getNextImage} call. Due to memory limits, an image source will
+ * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
+ * or {@link #acquireNextImage} call. Due to memory limits, an image source will
* eventually stall or drop Images in trying to render to the Surface if the
* ImageReader does not obtain and release Images at a rate equal to the
* production rate.</p>
*/
-public final class ImageReader implements AutoCloseable {
+public class ImageReader implements AutoCloseable {
+
+ /**
+ * Returned by nativeImageSetup when acquiring the image was successful.
+ */
+ private static final int ACQUIRE_SUCCESS = 0;
+ /**
+ * Returned by nativeImageSetup when we couldn't acquire the buffer,
+ * because there were no buffers available to acquire.
+ */
+ private static final int ACQUIRE_NO_BUFS = 1;
+ /**
+ * Returned by nativeImageSetup when we couldn't acquire the buffer
+ * because the consumer has already acquired {@maxImages} and cannot
+ * acquire more than that.
+ */
+ private static final int ACQUIRE_MAX_IMAGES = 2;
/**
* <p>Create a new reader for images of the desired size and format.</p>
*
- * <p>The maxImages parameter determines the maximum number of {@link Image}
- * objects that can be be acquired from the ImageReader
+ * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
+ * objects that can be be acquired from the {@code ImageReader}
* simultaneously. Requesting more buffers will use up more memory, so it is
* important to use only the minimum number necessary for the use case.</p>
*
* <p>The valid sizes and formats depend on the source of the image
* data.</p>
*
- * @param width the width in pixels of the Images that this reader will
- * produce.
- * @param height the height in pixels of the Images that this reader will
- * produce.
- * @param format the format of the Image that this reader will produce. This
- * must be one of the {@link android.graphics.ImageFormat} or
- * {@link android.graphics.PixelFormat} constants.
- * @param maxImages the maximum number of images the user will want to
- * access simultaneously. This should be as small as possible to limit
- * memory use. Once maxImages Images are obtained by the user, one of them
- * has to be released before a new Image will become available for access
- * through getNextImage(). Must be greater than 0.
+ * @param width
+ * The width in pixels of the Images that this reader will produce.
+ * @param height
+ * The height in pixels of the Images that this reader will produce.
+ * @param format
+ * The format of the Image that this reader will produce. This
+ * must be one of the {@link android.graphics.ImageFormat} or
+ * {@link android.graphics.PixelFormat} constants.
+ * @param maxImages
+ * The maximum number of images the user will want to
+ * access simultaneously. This should be as small as possible to limit
+ * memory use. Once maxImages Images are obtained by the user, one of them
+ * has to be released before a new Image will become available for access
+ * through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
+ * Must be greater than 0.
*
* @see Image
*/
- public ImageReader(int width, int height, int format, int maxImages) {
+ public static ImageReader newInstance(int width, int height, int format, int maxImages) {
+ return new ImageReader(width, height, format, maxImages);
+ }
+
+ /**
+ * @hide
+ */
+ protected ImageReader(int width, int height, int format, int maxImages) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -96,33 +122,79 @@ public final class ImageReader implements AutoCloseable {
mSurface = nativeGetSurface();
}
+ /**
+ * The width of each {@link Image}, in pixels.
+ *
+ * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+ * {@link #acquireNextImage}) will have the same dimensions as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the width of an Image
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * The height of each {@link Image}, in pixels.
+ *
+ * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
+ * {@link #acquireNextImage}) will have the same dimensions as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the height of an Image
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * The {@link ImageFormat image format} of each Image.
+ *
+ * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
+ * (for example, with {@link #acquireNextImage}) will have the same format as specified in
+ * {@link #newInstance}.</p>
+ *
+ * @return the format of an Image
+ *
+ * @see ImageFormat
+ */
public int getImageFormat() {
return mFormat;
}
+ /**
+ * Maximum number of images that can be acquired from the ImageReader by any time (for example,
+ * with {@link #acquireNextImage}).
+ *
+ * <p>An image is considered acquired after it's returned by a function from ImageReader, and
+ * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
+ * </p>
+ *
+ * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
+ * acquire function throwing a {@link IllegalStateException}. Furthermore,
+ * while the max number of images have been acquired by the ImageReader user, the producer
+ * enqueueing additional images may stall until at least one image has been released. </p>
+ *
+ * @return Maximum number of images for this ImageReader.
+ *
+ * @see Image#close
+ */
public int getMaxImages() {
return mMaxImages;
}
/**
- * <p>Get a Surface that can be used to produce Images for this
- * ImageReader.</p>
+ * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
+ * {@code ImageReader}.</p>
*
- * <p>Until valid image data is rendered into this Surface, the
- * {@link #getNextImage} method will return {@code null}. Only one source
+ * <p>Until valid image data is rendered into this {@link Surface}, the
+ * {@link #acquireNextImage} method will return {@code null}. Only one source
* can be producing data into this Surface at the same time, although the
- * same Surface can be reused with a different API once the first source is
- * disconnected from the Surface.</p>
+ * same {@link Surface} can be reused with a different API once the first source is
+ * disconnected from the {@link Surface}.</p>
*
- * @return A Surface to use for a drawing target for various APIs.
+ * @return A {@link Surface} to use for a drawing target for various APIs.
*/
public Surface getSurface() {
return mSurface;
@@ -130,41 +202,154 @@ public final class ImageReader implements AutoCloseable {
/**
* <p>
- * Get the next Image from the ImageReader's queue. Returns {@code null} if
+ * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
+ * {@link Image images}. Returns {@code null} if no new image is available.
+ * </p>
+ * <p>
+ * This operation will acquire all the images possible from the ImageReader,
+ * but {@link #close} all images that aren't the latest. This function is
+ * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
+ * more suited for real-time processing.
+ * </p>
+ * <p>
+ * Note that {@link #getMaxImages maxImages} should be at least 2 for
+ * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
+ * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
+ * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
+ * with less than two images of margin, that is
+ * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
+ * </p>
+ * <p>
+ * This operation will fail by throwing an {@link IllegalStateException} if
+ * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
+ * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
+ * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
+ * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
+ * will be thrown until more images are
+ * released with {@link Image#close}.
+ * </p>
+ *
+ * @return latest frame of image data, or {@code null} if no image data is available.
+ * @throws IllegalStateException if too many images are currently acquired
+ */
+ public Image acquireLatestImage() {
+ Image image = acquireNextImage();
+ if (image == null) {
+ return null;
+ }
+ try {
+ for (;;) {
+ Image next = acquireNextImageNoThrowISE();
+ if (next == null) {
+ Image result = image;
+ image = null;
+ return result;
+ }
+ image.close();
+ image = next;
+ }
+ } finally {
+ if (image != null) {
+ image.close();
+ }
+ }
+ }
+
+ /**
+ * Don't throw IllegalStateException if there are too many images acquired.
+ *
+ * @return Image if acquiring succeeded, or null otherwise.
+ *
+ * @hide
+ */
+ public Image acquireNextImageNoThrowISE() {
+ SurfaceImage si = new SurfaceImage();
+ return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
+ }
+
+ /**
+ * Attempts to acquire the next image from the underlying native implementation.
+ *
+ * <p>
+ * Note that unexpected failures will throw at the JNI level.
+ * </p>
+ *
+ * @param si A blank SurfaceImage.
+ * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
+ *
+ * @see #ACQUIRE_MAX_IMAGES
+ * @see #ACQUIRE_NO_BUFS
+ * @see #ACQUIRE_SUCCESS
+ */
+ private int acquireNextSurfaceImage(SurfaceImage si) {
+
+ int status = nativeImageSetup(si);
+
+ switch (status) {
+ case ACQUIRE_SUCCESS:
+ si.createSurfacePlanes();
+ si.setImageValid(true);
+ case ACQUIRE_NO_BUFS:
+ case ACQUIRE_MAX_IMAGES:
+ break;
+ default:
+ throw new AssertionError("Unknown nativeImageSetup return code " + status);
+ }
+
+ return status;
+ }
+
+ /**
+ * <p>
+ * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
* no new image is available.
* </p>
+ *
+ * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
+ * automatically release older images, and allow slower-running processing routines to catch
+ * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
+ * batch/background processing. Incorrectly using this function can cause images to appear
+ * with an ever-increasing delay, followed by a complete stall where no new images seem to
+ * appear.
+ * </p>
+ *
* <p>
- * This operation will fail by throwing an
- * {@link Surface.OutOfResourcesException OutOfResourcesException} if too
- * many images have been acquired with {@link #getNextImage}. In particular
- * a sequence of {@link #getNextImage} calls greater than {@link #getMaxImages}
- * without calling {@link Image#close} or {@link #releaseImage} in-between
- * will exhaust the underlying queue. At such a time,
- * {@link Surface.OutOfResourcesException OutOfResourcesException} will be
- * thrown until more images are released with {@link Image#close} or
- * {@link #releaseImage}.
+ * This operation will fail by throwing an {@link IllegalStateException} if
+ * {@code maxImages} have been acquired with {@link #acquireNextImage} or
+ * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
+ * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
+ * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
+ * {@link IllegalStateException} will be thrown until more images are released with
+ * {@link Image#close}.
* </p>
*
- * @return a new frame of image data, or {@code null} if no image data is
- * available.
- * @throws Surface.OutOfResourcesException if too many images are currently
- * acquired
+ * @return a new frame of image data, or {@code null} if no image data is available.
+ * @throws IllegalStateException if {@code maxImages} images are currently acquired
+ * @see #acquireLatestImage
*/
- public Image getNextImage() {
+ public Image acquireNextImage() {
SurfaceImage si = new SurfaceImage();
- if (nativeImageSetup(si)) {
- // create SurfacePlane objects
- si.createSurfacePlanes();
- si.setImageValid(true);
- return si;
+ int status = acquireNextSurfaceImage(si);
+
+ switch (status) {
+ case ACQUIRE_SUCCESS:
+ return si;
+ case ACQUIRE_NO_BUFS:
+ return null;
+ case ACQUIRE_MAX_IMAGES:
+ throw new IllegalStateException(
+ String.format(
+ "maxImages (%d) has already been acquired, " +
+ "call #close before acquiring more.", mMaxImages));
+ default:
+ throw new AssertionError("Unknown nativeImageSetup return code " + status);
}
- return null;
}
/**
* <p>Return the frame to the ImageReader for reuse.</p>
*/
- public void releaseImage(Image i) {
+ private void releaseImage(Image i) {
if (! (i instanceof SurfaceImage) ) {
throw new IllegalArgumentException(
"This image was not produced by an ImageReader");
@@ -183,13 +368,16 @@ public final class ImageReader implements AutoCloseable {
/**
* Register a listener to be invoked when a new image becomes available
* from the ImageReader.
- * @param listener the listener that will be run
- * @param handler The handler on which the listener should be invoked, or null
- * if the listener should be invoked on the calling thread's looper.
*
- * @throws IllegalArgumentException if no handler specified and the calling thread has no looper
+ * @param listener
+ * The listener that will be run.
+ * @param handler
+ * The handler on which the listener should be invoked, or null
+ * if the listener should be invoked on the calling thread's looper.
+ * @throws IllegalArgumentException
+ * If no handler specified and the calling thread has no looper.
*/
- public void setImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
mImageListener = listener;
Looper looper;
@@ -206,12 +394,16 @@ public final class ImageReader implements AutoCloseable {
/**
* Callback interface for being notified that a new image is available.
+ *
+ * <p>
* The onImageAvailable is called per image basis, that is, callback fires for every new frame
* available from ImageReader.
+ * </p>
*/
public interface OnImageAvailableListener {
/**
* Callback that is called when a new image is available from ImageReader.
+ *
* @param reader the ImageReader the callback is associated with.
* @see ImageReader
* @see Image
@@ -220,12 +412,17 @@ public final class ImageReader implements AutoCloseable {
}
/**
- * Free up all the resources associated with this ImageReader. After
- * Calling this method, this ImageReader can not be used. calling
- * any methods on this ImageReader and Images previously provided by {@link #getNextImage}
- * will result in an IllegalStateException, and attempting to read from
- * ByteBuffers returned by an earlier {@code Plane#getBuffer} call will
+ * Free up all the resources associated with this ImageReader.
+ *
+ * <p>
+ * After calling this method, this ImageReader can not be used. Calling
+ * any methods on this ImageReader and Images previously provided by
+ * {@link #acquireNextImage} or {@link #acquireLatestImage}
+ * will result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Image.Plane#getBuffer Plane#getBuffer} call will
* have undefined behavior.
+ * </p>
*/
@Override
public void close() {
@@ -242,11 +439,14 @@ public final class ImageReader implements AutoCloseable {
}
/**
- * Only a subset of the formats defined in {@link android.graphics.ImageFormat} and
- * {@link android.graphics.PixelFormat} are supported by ImageReader. When reading RGB
- * data from a surface, the formats defined in {@link android.graphics.PixelFormat}
- * can be used, when reading YUV, JPEG or raw sensor data ( for example, from camera
- * or video decoder), formats from {@link android.graphics.ImageFormat} are used.
+ * Only a subset of the formats defined in
+ * {@link android.graphics.ImageFormat ImageFormat} and
+ * {@link android.graphics.PixelFormat PixelFormat} are supported by
+ * ImageReader. When reading RGB data from a surface, the formats defined in
+ * {@link android.graphics.PixelFormat PixelFormat} can be used, when
+ * reading YUV, JPEG or raw sensor data (for example, from camera or video
+ * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
+ * are used.
*/
private int getNumPlanesFromFormat() {
switch (mFormat) {
@@ -308,7 +508,7 @@ public final class ImageReader implements AutoCloseable {
*/
private long mNativeContext;
- private class SurfaceImage implements android.media.Image {
+ private class SurfaceImage extends android.media.Image {
public SurfaceImage() {
mIsImageValid = false;
}
@@ -404,7 +604,7 @@ public final class ImageReader implements AutoCloseable {
mPlanes[i] = nativeCreatePlane(i);
}
}
- private class SurfacePlane implements android.media.Image.Plane {
+ private class SurfacePlane extends android.media.Image.Plane {
// SurfacePlane instance is created by native code when a new SurfaceImage is created
private SurfacePlane(int index, int rowStride, int pixelStride) {
mIndex = index;
@@ -479,9 +679,17 @@ public final class ImageReader implements AutoCloseable {
private synchronized native void nativeClose();
private synchronized native void nativeReleaseImage(Image i);
private synchronized native Surface nativeGetSurface();
- private synchronized native boolean nativeImageSetup(Image i);
- /*
+ /**
+ * @return A return code {@code ACQUIRE_*}
+ *
+ * @see #ACQUIRE_SUCCESS
+ * @see #ACQUIRE_NO_BUFS
+ * @see #ACQUIRE_MAX_IMAGES
+ */
+ private synchronized native int nativeImageSetup(Image i);
+
+ /**
* We use a class initializer to allow the native code to cache some
* field offsets.
*/
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 52c0c2d9f5fa..12f7bd9a9956 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -120,6 +120,14 @@ public class AudioEffect {
.fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * UUID for Loudness Enhancer
+ */
+ public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
+ .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1");
+
+ /**
* Null effect UUID. Used when the UUID for effect type of
* @hide
*/
diff --git a/media/java/android/media/audiofx/LoudnessEnhancer.java b/media/java/android/media/audiofx/LoudnessEnhancer.java
new file mode 100644
index 000000000000..f6e3e6bf5146
--- /dev/null
+++ b/media/java/android/media/audiofx/LoudnessEnhancer.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.audiofx;
+
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.media.audiofx.AudioEffect;
+import android.util.Log;
+
+import java.util.StringTokenizer;
+
+
+/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * LoudnessEnhancer is an audio effect for increasing audio loudness.
+ * The processing is parametrized by a target gain value, which determines the maximum amount
+ * by which an audio signal will be amplified; signals amplified outside of the sample
+ * range supported by the platform are compressed.
+ * An application creates a LoudnessEnhancer object to instantiate and control a
+ * this audio effect in the audio framework.
+ * To attach the LoudnessEnhancer to a particular AudioTrack or MediaPlayer,
+ * specify the audio session ID of this AudioTrack or MediaPlayer when constructing the effect
+ * (see {@link AudioTrack#getAudioSessionId()} and {@link MediaPlayer#getAudioSessionId()}).
+ */
+
+public class LoudnessEnhancer extends AudioEffect {
+
+ private final static String TAG = "LoudnessEnhancer";
+
+ // These parameter constants must be synchronized with those in
+ // /system/media/audio_effects/include/audio_effects/effect_loudnessenhancer.h
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * The maximum gain applied applied to the signal to process.
+ * It is expressed in millibels (100mB = 1dB) where 0mB corresponds to no amplification.
+ */
+ public static final int PARAM_TARGET_GAIN_MB = 0;
+
+ /**
+ * Registered listener for parameter changes.
+ */
+ private OnParameterChangeListener mParamListener = null;
+
+ /**
+ * Listener used internally to to receive raw parameter change events
+ * from AudioEffect super class
+ */
+ private BaseParameterListener mBaseParamListener = null;
+
+ /**
+ * Lock for access to mParamListener
+ */
+ private final Object mParamListenerLock = new Object();
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Class constructor.
+ * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public LoudnessEnhancer(int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, 0, audioSession);
+
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+ }
+ }
+
+ /**
+ * @hide
+ * Class constructor.
+ * @param priority the priority level requested by the application for controlling the
+ * LoudnessEnhancer engine. As the same engine can be shared by several applications,
+ * this parameter indicates how much the requesting application needs control of effect
+ * parameters. The normal priority is 0, above normal is a positive number, below normal a
+ * negative number.
+ * @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
+ * will be attached to the MediaPlayer or AudioTrack in the same audio session.
+ *
+ * @throws java.lang.IllegalStateException
+ * @throws java.lang.IllegalArgumentException
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+ public LoudnessEnhancer(int priority, int audioSession)
+ throws IllegalStateException, IllegalArgumentException,
+ UnsupportedOperationException, RuntimeException {
+ super(EFFECT_TYPE_LOUDNESS_ENHANCER, EFFECT_TYPE_NULL, priority, audioSession);
+
+ if (audioSession == 0) {
+ Log.w(TAG, "WARNING: attaching a LoudnessEnhancer to global output mix is deprecated!");
+ }
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Set the target gain for the audio effect.
+ * The target gain is the maximum value by which a sample value will be amplified when the
+ * effect is enabled.
+ * @param gainmB the effect target gain expressed in mB. 0mB corresponds to no amplification.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setTargetGain(int gainmB)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_TARGET_GAIN_MB, gainmB));
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Return the target gain.
+ * @return the effect target gain expressed in mB.
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public float getTargetGain()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ int[] value = new int[1];
+ checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+ return value[0];
+ }
+
+ /**
+ * @hide
+ * The OnParameterChangeListener interface defines a method called by the LoudnessEnhancer
+ * when a parameter value has changed.
+ */
+ public interface OnParameterChangeListener {
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Method called when a parameter value has changed. The method is called only if the
+ * parameter was changed by another application having the control of the same
+ * LoudnessEnhancer engine.
+ * @param effect the LoudnessEnhancer on which the interface is registered.
+ * @param param ID of the modified parameter. See {@link #PARAM_GENERIC_PARAM1} ...
+ * @param value the new parameter value.
+ */
+ void onParameterChange(LoudnessEnhancer effect, int param, int value);
+ }
+
+ /**
+ * Listener used internally to receive unformatted parameter change events from AudioEffect
+ * super class.
+ */
+ private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+ private BaseParameterListener() {
+
+ }
+ public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+ // only notify when the parameter was successfully change
+ if (status != AudioEffect.SUCCESS) {
+ return;
+ }
+ OnParameterChangeListener l = null;
+ synchronized (mParamListenerLock) {
+ if (mParamListener != null) {
+ l = mParamListener;
+ }
+ }
+ if (l != null) {
+ int p = -1;
+ int v = Integer.MIN_VALUE;
+
+ if (param.length == 4) {
+ p = byteArrayToInt(param, 0);
+ }
+ if (value.length == 4) {
+ v = byteArrayToInt(value, 0);
+ }
+ if (p != -1 && v != Integer.MIN_VALUE) {
+ l.onParameterChange(LoudnessEnhancer.this, p, v);
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Registers an OnParameterChangeListener interface.
+ * @param listener OnParameterChangeListener interface registered
+ */
+ public void setParameterListener(OnParameterChangeListener listener) {
+ synchronized (mParamListenerLock) {
+ if (mParamListener == null) {
+ mBaseParamListener = new BaseParameterListener();
+ super.setParameterListener(mBaseParamListener);
+ }
+ mParamListener = listener;
+ }
+ }
+
+ /**
+ * @hide
+ * The Settings class regroups the LoudnessEnhancer parameters. It is used in
+ * conjunction with the getProperties() and setProperties() methods to backup and restore
+ * all parameters in a single call.
+ */
+ public static class Settings {
+ public int targetGainmB;
+
+ public Settings() {
+ }
+
+ /**
+ * Settings class constructor from a key=value; pairs formatted string. The string is
+ * typically returned by Settings.toString() method.
+ * @throws IllegalArgumentException if the string is not correctly formatted.
+ */
+ public Settings(String settings) {
+ StringTokenizer st = new StringTokenizer(settings, "=;");
+ //int tokens = st.countTokens();
+ if (st.countTokens() != 3) {
+ throw new IllegalArgumentException("settings: " + settings);
+ }
+ String key = st.nextToken();
+ if (!key.equals("LoudnessEnhancer")) {
+ throw new IllegalArgumentException(
+ "invalid settings for LoudnessEnhancer: " + key);
+ }
+ try {
+ key = st.nextToken();
+ if (!key.equals("targetGainmB")) {
+ throw new IllegalArgumentException("invalid key name: " + key);
+ }
+ targetGainmB = Integer.parseInt(st.nextToken());
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("invalid value for key: " + key);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String str = new String (
+ "LoudnessEnhancer"+
+ ";targetGainmB="+Integer.toString(targetGainmB)
+ );
+ return str;
+ }
+ };
+
+
+ /**
+ * @hide
+ * Gets the LoudnessEnhancer properties. This method is useful when a snapshot of current
+ * effect settings must be saved by the application.
+ * @return a LoudnessEnhancer.Settings object containing all current parameters values
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public LoudnessEnhancer.Settings getProperties()
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ Settings settings = new Settings();
+ int[] value = new int[1];
+ checkStatus(getParameter(PARAM_TARGET_GAIN_MB, value));
+ settings.targetGainmB = value[0];
+ return settings;
+ }
+
+ /**
+ * @hide
+ * Sets the LoudnessEnhancer properties. This method is useful when bass boost settings
+ * have to be applied from a previous backup.
+ * @param settings a LoudnessEnhancer.Settings object containing the properties to apply
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @throws UnsupportedOperationException
+ */
+ public void setProperties(LoudnessEnhancer.Settings settings)
+ throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ checkStatus(setParameter(PARAM_TARGET_GAIN_MB, settings.targetGainmB));
+ }
+}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 94f20bcb3171..a03dbf325e50 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -43,13 +43,16 @@
using namespace android;
-static const char* const OutOfResourcesException =
- "android/view/Surface$OutOfResourcesException";
-
enum {
IMAGE_READER_MAX_NUM_PLANES = 3,
};
+enum {
+ ACQUIRE_SUCCESS = 0,
+ ACQUIRE_NO_BUFFERS = 1,
+ ACQUIRE_MAX_IMAGES = 2,
+};
+
static struct {
jfieldID mNativeContext;
jmethodID postEventFromNative;
@@ -685,14 +688,14 @@ static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
ctx->returnLockedBuffer(buffer);
}
-static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz,
jobject image)
{
ALOGV("%s:", __FUNCTION__);
JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
if (ctx == NULL) {
jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
- return false;
+ return -1;
}
CpuConsumer* consumer = ctx->getCpuConsumer();
@@ -700,27 +703,22 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
if (buffer == NULL) {
ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
" maxImages buffers");
- jniThrowException(env, OutOfResourcesException,
- "Too many outstanding images, close existing images"
- " to be able to acquire more.");
- return false;
+ return ACQUIRE_MAX_IMAGES;
}
status_t res = consumer->lockNextBuffer(buffer);
if (res != NO_ERROR) {
if (res != BAD_VALUE /*no buffers*/) {
if (res == NOT_ENOUGH_DATA) {
- jniThrowException(env, OutOfResourcesException,
- "Too many outstanding images, close existing images"
- " to be able to acquire more.");
+ return ACQUIRE_MAX_IMAGES;
} else {
ALOGE("%s Fail to lockNextBuffer with error: %d ",
__FUNCTION__, res);
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ jniThrowExceptionFmt(env, "java/lang/AssertionError",
"Unknown error (%d) when we tried to lock buffer.",
res);
}
}
- return false;
+ return ACQUIRE_NO_BUFFERS;
}
// Check if the left-top corner of the crop rect is origin, we currently assume this point is
@@ -730,7 +728,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
ALOGE("crop left: %d, top = %d", lt.x, lt.y);
jniThrowException(env, "java/lang/UnsupportedOperationException",
"crop left top corner need to at origin");
- return false;
+ return -1;
}
// Check if the producer buffer configurations match what ImageReader configured.
@@ -739,11 +737,9 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
int outputHeight = buffer->height;
// Correct width/height when crop is set.
- if (buffer->crop.getWidth() > 0) {
- outputWidth = buffer->crop.getWidth() + 1;
- }
- if (buffer->crop.getHeight() > 0) {
- outputHeight = buffer->crop.getHeight() + 1;
+ if (!buffer->crop.isEmpty()) {
+ outputWidth = buffer->crop.getWidth();
+ outputHeight = buffer->crop.getHeight();
}
int imageReaderWidth = ctx->getBufferWidth();
@@ -761,6 +757,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
"Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+ return -1;
}
if (ctx->getBufferFormat() != buffer->format) {
@@ -777,14 +774,14 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
buffer->format, ctx->getBufferFormat());
jniThrowException(env, "java/lang/UnsupportedOperationException",
msg.string());
- return false;
+ return -1;
}
// Set SurfaceImage instance member variables
Image_setBuffer(env, image, buffer);
env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
static_cast<jlong>(buffer->timestamp));
- return true;
+ return ACQUIRE_SUCCESS;
}
static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
@@ -855,7 +852,7 @@ static JNINativeMethod gImageReaderMethods[] = {
{"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init },
{"nativeClose", "()V", (void*)ImageReader_close },
{"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease },
- {"nativeImageSetup", "(Landroid/media/Image;)Z", (void*)ImageReader_imageSetup },
+ {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
{"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface },
};
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index ecdc287e79ea..64b12b7648ce 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -49,6 +49,7 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
addMediaPlayerStateUnitTests(suite);
addMediaScannerUnitTests(suite);
addCameraUnitTests(suite);
+ addImageReaderTests(suite);
return suite;
}
@@ -65,6 +66,10 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
suite.addTestSuite(CameraMetadataTest.class);
}
+ private void addImageReaderTests(TestSuite suite) {
+ suite.addTestSuite(ImageReaderTest.class);
+ }
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaMetadataRetrieverTest.class);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 2d26ac7f6c18..7b2a20ea4dbd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -61,6 +61,7 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
private SurfaceHolder mSurfaceHolder = null;
private static final int NUM_STRESS_LOOP = 10;
private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20;
+ private static final int SHORT_WAIT = 2 * 1000; // 2 seconds
private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds
private static final String MEDIA_MEMORY_OUTPUT =
"/sdcard/mediaMemOutput.txt";
@@ -99,16 +100,17 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
@Override
protected void setUp() throws Exception {
super.setUp();
+ //Insert a 2 second before launching the test activity. This is
+ //the workaround for the race condition of requesting the updated surface.
+ Thread.sleep(SHORT_WAIT);
+ getActivity();
//Check if the device support the camcorder
- CamcorderProfile mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
+ mCamcorderProfile = CamcorderProfile.get(CAMERA_ID);
if (mCamcorderProfile != null) {
mVideoWidth = mCamcorderProfile.videoFrameWidth;
mVideoHeight = mCamcorderProfile.videoFrameHeight;
+ Log.v(TAG, "height = " + mVideoHeight + " width= " + mVideoWidth);
}
- //Insert a 2 second before launching the test activity. This is
- //the workaround for the race condition of requesting the updated surface.
- Thread.sleep(2000);
- getActivity();
if (MediaFrameworkPerfTestRunner.mGetNativeHeapDump)
MediaTestUtil.getNativeHeapDump(this.getName() + "_before");
@@ -246,6 +248,8 @@ public class MediaPlayerPerformance extends ActivityInstrumentationTestCase2<Med
Thread.sleep(MEDIA_STRESS_WAIT_TIME);
mRecorder.stop();
mRecorder.release();
+ //Insert 2 seconds to make sure the camera released.
+ Thread.sleep(SHORT_WAIT);
} catch (Exception e) {
Log.v("record video failed ", e.toString());
mRecorder.release();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
new file mode 100644
index 000000000000..f6cd9901cd39
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ImageReaderTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.unit;
+
+import static org.mockito.Mockito.*;
+
+import android.graphics.ImageFormat;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.media.ImageReader.OnImageAvailableListener;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ImageReaderTest extends AndroidTestCase {
+
+ private static final String TAG = "ImageReaderTest-unit";
+
+ private static final int DEFAULT_WIDTH = 640;
+ private static final int DEFAULT_HEIGHT = 480;
+ private static final int DEFAULT_FORMAT = ImageFormat.YUV_420_888;
+ private static final int DEFAULT_MAX_IMAGES = 3;
+
+ private ImageReader mReader;
+ private Image mImage1;
+ private Image mImage2;
+ private Image mImage3;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ /**
+ * Workaround for mockito and JB-MR2 incompatibility
+ *
+ * Avoid java.lang.IllegalArgumentException: dexcache == null
+ * https://code.google.com/p/dexmaker/issues/detail?id=2
+ */
+ System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
+
+ // TODO: refactor above into one of the test runners
+
+ mReader = spy(ImageReader.newInstance(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ DEFAULT_MAX_IMAGES));
+ mImage1 = mock(Image.class);
+ mImage2 = mock(Image.class);
+ mImage3 = mock(Image.class);
+
+ /**
+ * Ensure rest of classes are mockable
+ */
+ {
+ mock(Plane.class);
+ mock(OnImageAvailableListener.class);
+ }
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mReader.close();
+
+ super.tearDown();
+ }
+
+ /**
+ * Return null when there is nothing in the image queue.
+ */
+ @SmallTest
+ public void testGetLatestImageEmpty() {
+ when(mReader.acquireNextImage()).thenReturn(null);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+ assertEquals(null, mReader.acquireLatestImage());
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage1() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(null);
+ assertEquals(mImage1, mReader.acquireLatestImage());
+ verify(mImage1, never()).close();
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage2() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).thenReturn(null);
+ assertEquals(mImage2, mReader.acquireLatestImage());
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, never()).close();
+ }
+
+ /**
+ * Return the last image from the image queue, close up the rest.
+ */
+ @SmallTest
+ public void testGetLatestImage3() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenReturn(null);
+ assertEquals(mImage3, mReader.acquireLatestImage());
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, never()).close();
+ }
+
+ /**
+ * Return null if get a IllegalStateException with no images in the queue.
+ */
+ @SmallTest
+ public void testGetLatestImageTooManyBuffersAcquiredEmpty() {
+ when(mReader.acquireNextImage()).thenThrow(new IllegalStateException());
+ try {
+ mReader.acquireLatestImage();
+ fail("Expected IllegalStateException to be thrown");
+ } catch(IllegalStateException e) {
+ }
+ }
+
+ /**
+ * All images are cleaned up when we get an unexpected Error.
+ */
+ @SmallTest
+ public void testGetLatestImageExceptionalError() {
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenThrow(new OutOfMemoryError());
+ try {
+ mReader.acquireLatestImage();
+ fail("Impossible");
+ } catch(OutOfMemoryError e) {
+ }
+
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, atLeastOnce()).close();
+ }
+
+ /**
+ * All images are cleaned up when we get an unexpected RuntimeException.
+ */
+ @SmallTest
+ public void testGetLatestImageExceptionalRuntime() {
+
+ when(mReader.acquireNextImage()).thenReturn(mImage1);
+ when(mReader.acquireNextImageNoThrowISE()).thenReturn(mImage2).
+ thenReturn(mImage3).
+ thenThrow(new RuntimeException());
+ try {
+ mReader.acquireLatestImage();
+ fail("Impossible");
+ } catch(RuntimeException e) {
+ }
+
+ verify(mImage1, atLeastOnce()).close();
+ verify(mImage2, atLeastOnce()).close();
+ verify(mImage3, atLeastOnce()).close();
+ }
+}
diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml
index 126276c04d5e..8a29052ba50b 100644
--- a/media/tests/SoundPoolTest/AndroidManifest.xml
+++ b/media/tests/SoundPoolTest/AndroidManifest.xml
@@ -8,4 +8,5 @@ package="com.android.soundpooltest">
</intent-filter>
</activity>
</application>
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
</manifest>
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
index 33db2ddb900f..cc3306c79d3f 100644
--- a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -143,7 +143,7 @@ public class SoundPoolTest extends Activity
if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
sleep(50);
}
- if (DEBUG) Log.d(LOG_TAG, "End scale test");
+ if (DEBUG) Log.d(LOG_TAG, "End sounds test");
return true;
}
@@ -165,7 +165,7 @@ public class SoundPoolTest extends Activity
if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
sleep(50);
}
- if (DEBUG) Log.d(LOG_TAG, "End sounds test");
+ if (DEBUG) Log.d(LOG_TAG, "End scale test");
return true;
}
@@ -189,6 +189,7 @@ public class SoundPoolTest extends Activity
if (DEBUG) Log.d(LOG_TAG, "Change rate " + mScale[step]);
}
mSoundPool.stop(id);
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
if (DEBUG) Log.d(LOG_TAG, "End rate test");
return true;
}
@@ -205,34 +206,38 @@ public class SoundPoolTest extends Activity
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(1000);
// play a low priority sound
- int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+ int id = mSoundPool.play(mSounds[1], DEFAULT_VOLUME, DEFAULT_VOLUME,
LOW_PRIORITY, DEFAULT_LOOP, 1.0f);
- if (id > 0) {
+ if (id != 0) {
Log.e(LOG_TAG, "Normal > Low priority test failed");
result = false;
mSoundPool.stop(id);
} else {
- Log.e(LOG_TAG, "Normal > Low priority test passed");
+ sleep(1000);
+ Log.i(LOG_TAG, "Normal > Low priority test passed");
}
- sleep(250);
// play a high priority sound
- id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+ id = mSoundPool.play(mSounds[2], DEFAULT_VOLUME, DEFAULT_VOLUME,
HIGH_PRIORITY, DEFAULT_LOOP, 1.0f);
if (id == 0) {
Log.e(LOG_TAG, "High > Normal priority test failed");
result = false;
} else {
- Log.e(LOG_TAG, "High > Normal priority test passed");
+ sleep(1000);
+ Log.i(LOG_TAG, "Stopping high priority");
+ mSoundPool.stop(id);
+ sleep(1000);
+ Log.i(LOG_TAG, "High > Normal priority test passed");
}
- sleep(250);
- mSoundPool.stop(id);
// stop normal note
+ Log.i(LOG_TAG, "Stopping normal priority");
mSoundPool.stop(normalId);
+ sleep(1000);
if (DEBUG) Log.d(LOG_TAG, "End priority test");
return result;
@@ -250,17 +255,21 @@ public class SoundPoolTest extends Activity
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(2500);
// pause and resume sound a few times
for (int count = 0; count < 5; count++) {
+ if (DEBUG) Log.d(LOG_TAG, "Pause note " + id);
mSoundPool.pause(id);
- sleep(250);
+ sleep(1000);
+ if (DEBUG) Log.d(LOG_TAG, "Resume note " + id);
mSoundPool.resume(id);
- sleep(250);
+ sleep(1000);
}
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
mSoundPool.stop(id);
+ sleep(1000);
// play 5 sounds, forces one to be stolen
int ids[] = new int[5];
@@ -272,18 +281,21 @@ public class SoundPoolTest extends Activity
Log.e(LOG_TAG, "Error occurred starting note");
return false;
}
- sleep(250);
+ sleep(1000);
}
// pause and resume sound a few times
for (int count = 0; count < 5; count++) {
+ if (DEBUG) Log.d(LOG_TAG, "autoPause");
mSoundPool.autoPause();
- sleep(250);
+ sleep(1000);
+ if (DEBUG) Log.d(LOG_TAG, "autoResume");
mSoundPool.autoResume();
- sleep(250);
+ sleep(1000);
}
for (int i = 0; i < 5; i++) {
+ if (DEBUG) Log.d(LOG_TAG, "Stop note " + ids[i]);
mSoundPool.stop(ids[i]);
}
@@ -302,9 +314,9 @@ public class SoundPoolTest extends Activity
return false;
}
- // pan from left to right
+ // pan from right to left
for (int count = 0; count < 101; count++) {
- sleep(20);
+ sleep(50);
double radians = PI_OVER_2 * count / 100.0;
float leftVolume = (float) Math.sin(radians);
float rightVolume = (float) Math.cos(radians);
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
new file mode 100644
index 000000000000..69f0bb5d185b
--- /dev/null
+++ b/media/tests/audiotests/Android.mk
@@ -0,0 +1,21 @@
+ifeq ($(TARGET_ARCH),arm)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= shared_mem_test
+LOCAL_SRC_FILES := \
+ shared_mem_test.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libc \
+ libcutils \
+ libutils \
+ libbinder \
+ libhardware_legacy \
+ libmedia
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/media/tests/audiotests/shared_mem_test.cpp b/media/tests/audiotests/shared_mem_test.cpp
new file mode 100644
index 000000000000..992c900d31a2
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.cpp
@@ -0,0 +1,216 @@
+// Copyright 2008, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+#define LOG_NDEBUG 0
+#define LOG_TAG "shared_mem_test"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <cutils/properties.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <math.h>
+
+#include "shared_mem_test.h"
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+#include <binder/ProcessState.h>
+
+
+#include <utils/Log.h>
+
+#include <fcntl.h>
+
+namespace android {
+
+/************************************************************
+*
+* Constructor
+*
+************************************************************/
+AudioTrackTest::AudioTrackTest(void) {
+
+ InitSine(); // init sine table
+
+}
+
+
+/************************************************************
+*
+*
+************************************************************/
+void AudioTrackTest::Execute(void) {
+ if (Test01() == 0) {
+ ALOGD("01 passed\n");
+ } else {
+ ALOGD("01 failed\n");
+ }
+}
+
+/************************************************************
+*
+* Shared memory test
+*
+************************************************************/
+#define BUF_SZ 44100
+
+int AudioTrackTest::Test01() {
+
+ sp<MemoryDealer> heap;
+ sp<IMemory> iMem;
+ uint8_t* p;
+
+ short smpBuf[BUF_SZ];
+ long rate = 44100;
+ unsigned long phi;
+ unsigned long dPhi;
+ long amplitude;
+ long freq = 1237;
+ float f0;
+
+ f0 = pow(2., 32.) * freq / (float)rate;
+ dPhi = (unsigned long)f0;
+ amplitude = 1000;
+ phi = 0;
+ Generate(smpBuf, BUF_SZ, amplitude, phi, dPhi); // fill buffer
+
+ for (int i = 0; i < 1024; i++) {
+ heap = new MemoryDealer(1024*1024, "AudioTrack Heap Base");
+
+ iMem = heap->allocate(BUF_SZ*sizeof(short));
+
+ p = static_cast<uint8_t*>(iMem->pointer());
+ memcpy(p, smpBuf, BUF_SZ*sizeof(short));
+
+ sp<AudioTrack> track = new AudioTrack(AUDIO_STREAM_MUSIC,// stream type
+ rate,
+ AUDIO_FORMAT_PCM_16_BIT,// word length, PCM
+ AUDIO_CHANNEL_OUT_MONO,
+ iMem);
+
+ status_t status = track->initCheck();
+ if(status != NO_ERROR) {
+ track.clear();
+ ALOGD("Failed for initCheck()");
+ return -1;
+ }
+
+ // start play
+ ALOGD("start");
+ track->start();
+
+ usleep(20000);
+
+ ALOGD("stop");
+ track->stop();
+ iMem.clear();
+ heap.clear();
+ usleep(20000);
+ }
+
+ return 0;
+
+}
+
+/************************************************************
+*
+* Generate a mono buffer
+* Error is less than 3lsb
+*
+************************************************************/
+void AudioTrackTest::Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi)
+{
+ long pi13 = 25736; // 2^13*pi
+ // fill buffer
+ for(int i0=0; i0<bufferSz; i0++) {
+ long sample;
+ long l0, l1;
+
+ buffer[i0] = ComputeSine( amplitude, phi);
+ phi += dPhi;
+ }
+}
+
+/************************************************************
+*
+* Generate a sine
+* Error is less than 3lsb
+*
+************************************************************/
+short AudioTrackTest::ComputeSine(long amplitude, long phi)
+{
+ long pi13 = 25736; // 2^13*pi
+ long sample;
+ long l0, l1;
+
+ sample = (amplitude*sin1024[(phi>>22) & 0x3ff]) >> 15;
+ // correct with interpolation
+ l0 = (phi>>12) & 0x3ff; // 2^20 * x / (2*pi)
+ l1 = (amplitude*sin1024[((phi>>22) + 256) & 0x3ff]) >> 15; // 2^15*cosine
+ l0 = (l0 * l1) >> 10;
+ l0 = (l0 * pi13) >> 22;
+ sample = sample + l0;
+
+ return (short)sample;
+}
+
+
+/************************************************************
+*
+* init sine table
+*
+************************************************************/
+void AudioTrackTest::InitSine(void) {
+ double phi = 0;
+ double dPhi = 2 * M_PI / SIN_SZ;
+ for(int i0 = 0; i0<SIN_SZ; i0++) {
+ long d0;
+
+ d0 = 32768. * sin(phi);
+ phi += dPhi;
+ if(d0 >= 32767) d0 = 32767;
+ if(d0 <= -32768) d0 = -32768;
+ sin1024[i0] = (short)d0;
+ }
+}
+
+/************************************************************
+*
+* main in name space
+*
+************************************************************/
+int main() {
+ ProcessState::self()->startThreadPool();
+ AudioTrackTest *test;
+
+ test = new AudioTrackTest();
+ test->Execute();
+ delete test;
+
+ return 0;
+}
+
+}
+
+/************************************************************
+*
+* global main
+*
+************************************************************/
+int main(int argc, char *argv[]) {
+
+ return android::main();
+}
diff --git a/media/tests/audiotests/shared_mem_test.h b/media/tests/audiotests/shared_mem_test.h
new file mode 100644
index 000000000000..f4959557b0b5
--- /dev/null
+++ b/media/tests/audiotests/shared_mem_test.h
@@ -0,0 +1,27 @@
+// Copyright 2008 The Android Open Source Project
+
+#ifndef AUDIOTRACKTEST_H_
+#define AUDIOTRACKTEST_H_
+
+namespace android {
+
+class AudioTrackTest{
+ public:
+ AudioTrackTest(void);
+ ~AudioTrackTest() {};
+
+ void Execute(void);
+ int Test01();
+
+ void Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi);
+ void InitSine();
+ short ComputeSine(long amplitude, long phi);
+
+ #define SIN_SZ 1024
+ short sin1024[SIN_SZ]; // sine table 2*pi = 1024
+};
+
+};
+
+
+#endif /*AUDIOTRACKTEST_H_*/
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5e198a2f1639..fa5c76907767 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -189,6 +189,35 @@
android:taskAffinity="com.android.systemui.net"
android:excludeFromRecents="true" />
+ <!-- platform logo easter egg activity -->
+ <activity
+ android:name=".DessertCase"
+ android:exported="true"
+ android:label="@string/dessert_case"
+ android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:hardwareAccelerated="true"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
+
+ <!-- a gallery of delicious treats -->
+ <service
+ android:name=".DessertCaseDream"
+ android:exported="true"
+ android:label="@string/dessert_case"
+ android:enabled="false"
+ >
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </service>
+
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
android:icon="@mipmap/ic_launcher_dreams"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bbfe383d5c52..7fdd30847dda 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -431,8 +431,8 @@
<!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is off. [CHAR LIMIT=NONE] -->
<string name="accessibility_rotation_lock_on_portrait">Screen is locked in portrait orientation.</string>
- <!-- Name of the Jelly Bean platlogo screensaver -->
- <string name="jelly_bean_dream_name">BeanFlinger</string>
+ <!-- Name of the K-release easter egg: a display case for all our tastiest desserts. [CHAR LIMIT=30] -->
+ <string name="dessert_case">Dessert Case</string>
<!-- Name of the launcher shortcut icon that allows dreams to be started immediately [CHAR LIMIT=20] -->
<string name="start_dreams">Daydream</string>
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java
new file mode 100644
index 000000000000..b6424af03f77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCase.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.util.Slog;
+
+public class DessertCase extends Activity {
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED");
+ PackageManager pm = getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName(this, DessertCaseDream.class),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
new file mode 100644
index 000000000000..022e4d83a194
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseDream.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.service.dreams.DreamService;
+
+public class DessertCaseDream extends DreamService {
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setInteractive(true);
+ setFullscreen(true);
+ }
+
+ @Override
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ super.onDreamingStopped();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index ada30acc68cf..5ebd11e03160 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -23,6 +23,7 @@ import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -698,6 +699,8 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
new UserHandle(UserHandle.USER_CURRENT));
} catch (SecurityException e) {
Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Error launching activity " + intent, e);
}
}
if (usingDrawingCache) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 46830308a80e..b56d7be8ac32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -424,7 +424,7 @@ public class NavigationBarView extends LinearLayout {
mCurrentView.getWidth(), mCurrentView.getHeight(),
visibilityToString(mCurrentView.getVisibility())));
- pw.println(String.format(" disabled=0x%08x vertical=%s hidden=%s low=%s menu=%s",
+ pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
mDisabledFlags,
mVertical ? "true" : "false",
mShowMenu ? "true" : "false"));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index a3e6e3830ee3..d15626b59c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1378,6 +1378,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
+ private void releaseFocus() {
+ WindowManager.LayoutParams lp =
+ (WindowManager.LayoutParams) mStatusBarWindow.getLayoutParams();
+ lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mWindowManager.updateViewLayout(mStatusBarWindow, lp);
+ }
+
public void animateCollapsePanels() {
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
@@ -1389,6 +1397,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
+ " flags=" + flags);
}
+ // release focus immediately to kick off focus change transition
+ releaseFocus();
+
if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index ceed30ef588e..25ffbd4db698 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -671,7 +671,7 @@ class QuickSettings {
alarmTile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- startSettingsActivity(AlarmClock.ACTION_SET_ALARM);
+ startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
}
});
mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8a285e30e7f9..0782cfbe9f7a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -34,7 +34,6 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -105,7 +104,6 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.HashSet;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -531,7 +529,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
- ImmersiveModeTesting.ENABLED_SETTING), false, this,
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS), false, this,
UserHandle.USER_ALL);
updateSettings();
}
@@ -947,9 +945,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
public void onDebug() {
- if (ImmersiveModeTesting.enabled) {
- ImmersiveModeTesting.toggleForceImmersiveMode(mFocusedWindow, mContext);
- }
+ // no-op
}
});
mTransientNavigationConfirmation = new TransientNavigationConfirmation(mContext);
@@ -1168,8 +1164,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
- ImmersiveModeTesting.enabled = Settings.System.getIntForUser(resolver,
- ImmersiveModeTesting.ENABLED_SETTING, 0, UserHandle.USER_CURRENT) != 0;
+ if (mTransientNavigationConfirmation != null) {
+ mTransientNavigationConfirmation.loadSetting();
+ }
}
if (updateRotation) {
updateRotation(true);
@@ -2819,7 +2816,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient && !statusBarTransparent) {
+ if (mStatusBar.isVisibleLw() && !statusBarTransient) {
// Status bar may go away, so the screen area it occupies
// is available to apps but just covering them when the
// status bar is visible.
@@ -3892,9 +3889,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- if (isScreenOn && isTransientNavigationAllowed(mLastSystemUiFlags)) {
- mTransientNavigationConfirmation.unconfirmLastPackage();
- }
+ mTransientNavigationConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+ isTransientNavigationAllowed(mLastSystemUiFlags));
if (isScreenOn && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
@@ -4173,6 +4169,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (sb) mStatusBarController.showTransient();
if (nb) mNavigationBarController.showTransient();
+ mTransientNavigationConfirmation.confirmCurrentPrompt();
updateSystemUiVisibilityLw();
}
}
@@ -5039,10 +5036,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private int updateSystemBarsLw(int oldVis, int vis) {
- if (ImmersiveModeTesting.enabled) {
- vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
- }
-
// prevent status bar interaction from clearing certain flags
boolean statusBarHasFocus = mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
if (statusBarHasFocus) {
@@ -5086,8 +5079,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean isTransientNav = isTransientNavigationAllowed(vis);
if (mFocusedWindow != null && oldTransientNav != isTransientNav) {
final String pkg = mFocusedWindow.getOwningPackage();
- mTransientNavigationConfirmation.transientNavigationChanged(mCurrentUserId, pkg,
- isTransientNav);
+ mTransientNavigationConfirmation.transientNavigationChanged(pkg, isTransientNav);
}
vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
@@ -5104,53 +5096,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
}
- // Temporary helper that allows testing immersive mode on existing apps
- // TODO remove
- private static final class ImmersiveModeTesting {
- static String ENABLED_SETTING = "immersive_mode_testing_enabled";
- static boolean enabled = false;
- private static final HashSet<String> sForced = new HashSet<String>();
-
- private static String parseActivity(WindowState win) {
- if (win != null && win.getAppToken() != null) {
- String str = win.getAppToken().toString();
- int end = str.lastIndexOf(' ');
- if (end > 0) {
- int start = str.lastIndexOf(' ', end - 1);
- if (start > -1) {
- return str.substring(start + 1, end);
- }
- }
- }
- return null;
- }
-
- public static int applyForced(WindowState focused, int vis) {
- if (sForced.contains(parseActivity(focused))) {
- vis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_IMMERSIVE;
- }
- return vis;
- }
-
- public static void toggleForceImmersiveMode(WindowState focused, Context context) {
- String activity = parseActivity(focused);
- if (activity != null) {
- String action;
- if (sForced.contains(activity)) {
- sForced.remove(activity);
- action = "Force immersive mode disabled";
- } else {
- sForced.add(activity);
- action = "Force immersive mode enabled";
- }
- android.widget.Toast.makeText(context,
- action + " for " + activity, android.widget.Toast.LENGTH_SHORT).show();
- }
- }
- }
-
// Use this instead of checking config_showNavigationBar so that it can be consistently
// overridden by qemu.hw.mainkeys in the emulator.
@Override
diff --git a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
index 3c4f0925eb7a..8613088fc09e 100644
--- a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java
@@ -19,16 +19,20 @@ package com.android.internal.policy.impl;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.view.View;
import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.widget.Toast;
import com.android.internal.R;
+import java.util.Arrays;
+
/**
* Helper to manage showing/hiding a confirmation prompt when the transient navigation bar
* is hidden.
@@ -39,16 +43,22 @@ public class TransientNavigationConfirmation {
private final Context mContext;
private final H mHandler;
- private final ArraySet<String> mConfirmedUserPackages = new ArraySet<String>();
+ private final ArraySet<String> mConfirmedPackages = new ArraySet<String>();
private final long mShowDelayMs;
+ private final long mPanicThresholdMs;
private Toast mToast;
- private String mLastUserPackage;
+ private String mLastPackage;
+ private String mPromptPackage;
+ private long mPanicTime;
+ private String mPanicPackage;
public TransientNavigationConfirmation(Context context) {
mContext = context;
mHandler = new H();
mShowDelayMs = getNavBarExitDuration() * 3;
+ mPanicThresholdMs = context.getResources()
+ .getInteger(R.integer.config_transient_navigation_confirmation_panic);
}
private long getNavBarExitDuration() {
@@ -56,44 +66,97 @@ public class TransientNavigationConfirmation {
return exit != null ? exit.getDuration() : 0;
}
- public void transientNavigationChanged(int userId, String pkg, boolean isNavTransient) {
+ public void loadSetting() {
+ if (DEBUG) Slog.d(TAG, "loadSetting()");
+ mConfirmedPackages.clear();
+ String packages = null;
+ try {
+ packages = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+ UserHandle.USER_CURRENT);
+ if (packages != null) {
+ mConfirmedPackages.addAll(Arrays.asList(packages.split(",")));
+ if (DEBUG) Slog.d(TAG, "Loaded mConfirmedPackages=" + mConfirmedPackages);
+ }
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error loading confirmations, packages=" + packages, t);
+ }
+ }
+
+ private void saveSetting() {
+ if (DEBUG) Slog.d(TAG, "saveSetting()");
+ try {
+ final String packages = TextUtils.join(",", mConfirmedPackages);
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
+ packages,
+ UserHandle.USER_CURRENT);
+ if (DEBUG) Slog.d(TAG, "Saved packages=" + packages);
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error saving confirmations, mConfirmedPackages=" + mConfirmedPackages, t);
+ }
+ }
+
+ public void transientNavigationChanged(String pkg, boolean isNavTransient) {
if (pkg == null) {
return;
}
- String userPkg = userId + ":" + pkg;
mHandler.removeMessages(H.SHOW);
if (isNavTransient) {
- mLastUserPackage = userPkg;
- if (!mConfirmedUserPackages.contains(userPkg)) {
- if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + userPkg);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, userPkg), mShowDelayMs);
+ mLastPackage = pkg;
+ if (!mConfirmedPackages.contains(pkg)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, pkg), mShowDelayMs);
}
} else {
- mLastUserPackage = null;
- if (DEBUG) Slog.d(TAG, "Hiding transient navigation confirmation for " + userPkg);
+ mLastPackage = null;
mHandler.sendEmptyMessage(H.HIDE);
}
}
- public void unconfirmLastPackage() {
- if (mLastUserPackage != null) {
- if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + mLastUserPackage);
- mConfirmedUserPackages.remove(mLastUserPackage);
+ public void onPowerKeyDown(boolean isScreenOn, long time, boolean transientNavigationAllowed) {
+ if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
+ // turning the screen back on within the panic threshold
+ unconfirmPackage(mPanicPackage);
+ }
+ if (isScreenOn && transientNavigationAllowed) {
+ // turning the screen off, remember if we were hiding the transient nav
+ mPanicTime = time;
+ mPanicPackage = mLastPackage;
+ } else {
+ mPanicTime = 0;
+ mPanicPackage = null;
+ }
+ }
+
+ public void confirmCurrentPrompt() {
+ mHandler.post(confirmAction(mPromptPackage));
+ }
+
+ private void unconfirmPackage(String pkg) {
+ if (pkg != null) {
+ if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + pkg);
+ mConfirmedPackages.remove(pkg);
+ saveSetting();
}
}
private void handleHide() {
if (mToast != null) {
+ if (DEBUG) Slog.d(TAG,
+ "Hiding transient navigation confirmation for " + mPromptPackage);
mToast.cancel();
mToast = null;
}
}
- private void handleShow(String userPkg) {
+ private void handleShow(String pkg) {
+ mPromptPackage = pkg;
+ if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + pkg);
+
// create the confirmation toast bar
final int msg = R.string.transient_navigation_confirmation;
mToast = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE);
- mToast.setAction(R.string.ok, confirmAction(userPkg));
+ mToast.setAction(R.string.ok, confirmAction(pkg));
// we will be hiding the nav bar, so layout as if it's already hidden
mToast.getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
@@ -102,11 +165,15 @@ public class TransientNavigationConfirmation {
mToast.show();
}
- private Runnable confirmAction(final String userPkg) {
+ private Runnable confirmAction(final String pkg) {
return new Runnable() {
@Override
public void run() {
- mConfirmedUserPackages.add(userPkg);
+ if (pkg != null && !mConfirmedPackages.contains(pkg)) {
+ if (DEBUG) Slog.d(TAG, "Confirming transient navigation for " + pkg);
+ mConfirmedPackages.add(pkg);
+ saveSetting();
+ }
handleHide();
}
};
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/java/com/android/server/IdleMaintenanceService.java
index 584d4bc5f4c8..b0a1aca37d7c 100644
--- a/services/java/com/android/server/IdleMaintenanceService.java
+++ b/services/java/com/android/server/IdleMaintenanceService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.Activity;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -24,12 +25,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
-import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
/**
* This service observes the device state and when applicable sends
@@ -69,6 +71,9 @@ public class IdleMaintenanceService extends BroadcastReceiver {
private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
"com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
+ private static final String ACTION_FORCE_IDLE_MAINTENANCE =
+ "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
+
private static final Intent sIdleMaintenanceStartIntent;
static {
sIdleMaintenanceStartIntent = new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
@@ -115,10 +120,10 @@ public class IdleMaintenanceService extends BroadcastReceiver {
mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
- register(mContext.getMainLooper());
+ register(mHandler);
}
- public void register(Looper looper) {
+ public void register(Handler handler) {
IntentFilter intentFilter = new IntentFilter();
// Alarm actions.
@@ -136,7 +141,12 @@ public class IdleMaintenanceService extends BroadcastReceiver {
intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, null, new Handler(looper));
+ intentFilter, null, mHandler);
+
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE);
+ mContext.registerReceiverAsUser(this, UserHandle.ALL,
+ intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler);
}
private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
@@ -149,7 +159,7 @@ public class IdleMaintenanceService extends BroadcastReceiver {
mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
}
- private void updateIdleMaintenanceState() {
+ private void updateIdleMaintenanceState(boolean noisy) {
if (mIdleMaintenanceStarted) {
// Idle maintenance can be interrupted by user activity, or duration
// time out, or low battery.
@@ -170,9 +180,9 @@ public class IdleMaintenanceService extends BroadcastReceiver {
getNextIdleMaintenanceIntervalStartFromNow());
}
}
- } else if (deviceStatePermitsIdleMaintenanceStart()
- && lastUserActivityPermitsIdleMaintenanceStart()
- && lastRunPermitsIdleMaintenanceStart()) {
+ } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
+ && lastUserActivityPermitsIdleMaintenanceStart(noisy)
+ && lastRunPermitsIdleMaintenanceStart(noisy)) {
// Now that we started idle maintenance, we should schedule another
// update for the moment when the idle maintenance times out.
scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
@@ -182,8 +192,8 @@ public class IdleMaintenanceService extends BroadcastReceiver {
isBatteryCharging() ? 1 : 0);
mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
sendIdleMaintenanceStartIntent();
- } else if (lastUserActivityPermitsIdleMaintenanceStart()) {
- if (lastRunPermitsIdleMaintenanceStart()) {
+ } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
+ if (lastRunPermitsIdleMaintenanceStart(noisy)) {
// The user does not use the device and we did not run maintenance in more
// than the min interval between runs, so schedule an update - maybe the
// battery will be charged latter.
@@ -204,6 +214,10 @@ public class IdleMaintenanceService extends BroadcastReceiver {
private void sendIdleMaintenanceStartIntent() {
mWakeLock.acquire();
+ try {
+ ActivityManagerNative.getDefault().performIdleMaintenance();
+ } catch (RemoteException e) {
+ }
mContext.sendOrderedBroadcastAsUser(sIdleMaintenanceStartIntent, UserHandle.ALL,
null, this, mHandler, Activity.RESULT_OK, null, null);
}
@@ -214,25 +228,37 @@ public class IdleMaintenanceService extends BroadcastReceiver {
null, this, mHandler, Activity.RESULT_OK, null, null);
}
- private boolean deviceStatePermitsIdleMaintenanceStart() {
+ private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
final int minBatteryLevel = isBatteryCharging()
? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
: MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
&& mBatteryService.getBatteryLevel() > minBatteryLevel);
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power");
+ }
+ return allowed;
}
- private boolean lastUserActivityPermitsIdleMaintenanceStart() {
+ private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
// The last time the user poked the device is above the threshold.
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
&& SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
> MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity");
+ }
+ return allowed;
}
- private boolean lastRunPermitsIdleMaintenanceStart() {
+ private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
// Enough time passed since the last maintenance run.
- return SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
+ boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
> MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ if (!allowed && noisy) {
+ Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last");
+ }
+ return allowed;
}
private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
@@ -266,7 +292,7 @@ public class IdleMaintenanceService extends BroadcastReceiver {
// next release. The only client for this for now is internal an holds
// a wake lock correctly.
if (mIdleMaintenanceStarted) {
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
}
} else if (Intent.ACTION_SCREEN_ON.equals(action)
|| Intent.ACTION_DREAMING_STOPPED.equals(action)) {
@@ -276,7 +302,7 @@ public class IdleMaintenanceService extends BroadcastReceiver {
unscheduleUpdateIdleMaintenanceState();
// If the screen went on/stopped dreaming, we know the user is using the
// device which means that idle maintenance should be stopped if running.
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
} else if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_DREAMING_STARTED.equals(action)) {
mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
@@ -285,7 +311,12 @@ public class IdleMaintenanceService extends BroadcastReceiver {
// this timeout elapses since the device may go to sleep by then.
scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
} else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
- updateIdleMaintenanceState();
+ updateIdleMaintenanceState(false);
+ } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
+ long now = SystemClock.elapsedRealtime() - 1;
+ mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
+ mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
+ updateIdleMaintenanceState(true);
} else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
|| Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
// We were holding a wake lock while broadcasting the idle maintenance
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d38756f6fb13..ef50df722fe0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -217,8 +217,7 @@ class ServerThread {
ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Scheduling Policy");
- ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
- new SchedulingPolicyService());
+ ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
AttributeCache.init(context);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e208f10f7371..2bac96ede974 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -172,7 +172,6 @@ import android.view.WindowManager;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
@@ -850,10 +849,39 @@ public final class ActivityManagerService extends ActivityManagerNative
int mNewNumServiceProcs = 0;
/**
- * System monitoring: number of processes that died since the last
- * N procs were started.
+ * Allow the current computed overall memory level of the system to go down?
+ * This is set to false when we are killing processes for reasons other than
+ * memory management, so that the now smaller process list will not be taken as
+ * an indication that memory is tighter.
*/
- int[] mProcDeaths = new int[20];
+ boolean mAllowLowerMemLevel = false;
+
+ /**
+ * The last computed memory level, for holding when we are in a state that
+ * processes are going away for other reasons.
+ */
+ int mLastMemoryLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+
+ /**
+ * The last total number of process we have, to determine if changes actually look
+ * like a shrinking number of process due to lower RAM.
+ */
+ int mLastNumProcesses;
+
+ /**
+ * The uptime of the last time we performed idle maintenance.
+ */
+ long mLastIdleTime = SystemClock.uptimeMillis();
+
+ /**
+ * Total time spent with RAM that has been added in the past since the last idle time.
+ */
+ long mLowRamTimeSinceLastIdle = 0;
+
+ /**
+ * If RAM is currently low, when that horrible situatin started.
+ */
+ long mLowRamStartTime = 0;
/**
* This is set if we had to do a delayed dexopt of an app before launching
@@ -978,17 +1006,18 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
- static final int CLEAR_DNS_CACHE = 28;
- static final int UPDATE_HTTP_PROXY = 29;
+ static final int CLEAR_DNS_CACHE_MSG = 28;
+ static final int UPDATE_HTTP_PROXY_MSG = 29;
static final int SHOW_COMPAT_MODE_DIALOG_MSG = 30;
static final int DISPATCH_PROCESSES_CHANGED = 31;
static final int DISPATCH_PROCESS_DIED = 32;
- static final int REPORT_MEM_USAGE = 33;
+ static final int REPORT_MEM_USAGE_MSG = 33;
static final int REPORT_USER_SWITCH_MSG = 34;
static final int CONTINUE_USER_SWITCH_MSG = 35;
static final int USER_SWITCH_TIMEOUT_MSG = 36;
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
- static final int PERSIST_URI_GRANTS = 38;
+ static final int PERSIST_URI_GRANTS_MSG = 38;
+ static final int REQUEST_ALL_PSS_MSG = 39;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1169,7 +1198,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} break;
- case CLEAR_DNS_CACHE: {
+ case CLEAR_DNS_CACHE_MSG: {
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
@@ -1183,7 +1212,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} break;
- case UPDATE_HTTP_PROXY: {
+ case UPDATE_HTTP_PROXY_MSG: {
ProxyProperties proxy = (ProxyProperties)msg.obj;
String host = "";
String port = "";
@@ -1369,7 +1398,7 @@ public final class ActivityManagerService extends ActivityManagerNative
dispatchProcessDied(pid, uid);
break;
}
- case REPORT_MEM_USAGE: {
+ case REPORT_MEM_USAGE_MSG: {
final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
Thread thread = new Thread() {
@Override public void run() {
@@ -1583,10 +1612,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
break;
}
- case PERSIST_URI_GRANTS: {
+ case PERSIST_URI_GRANTS_MSG: {
writeGrantedUriPermissions();
break;
}
+ case REQUEST_ALL_PSS_MSG: {
+ requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ break;
+ }
}
}
};
@@ -1630,6 +1663,10 @@ public final class ActivityManagerService extends ActivityManagerNative
num++;
proc.lastPssTime = SystemClock.uptimeMillis();
proc.baseProcessTracker.addPss(pss, tmp[0], true);
+ if (proc.initialIdlePss == 0) {
+ proc.initialIdlePss = pss;
+ }
+ proc.lastPss = pss;
}
}
}
@@ -2250,8 +2287,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- final void updateLruProcessLocked(ProcessRecord app,
- boolean oomAdj) {
+ final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj) {
mLruSeq++;
updateLruProcessInternalLocked(app, 0);
@@ -2417,9 +2453,6 @@ public final class ActivityManagerService extends ActivityManagerNative
updateCpuStats();
- System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
- mProcDeaths[0] = 0;
-
try {
int uid = app.uid;
@@ -3428,7 +3461,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (doReport) {
- Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE, memInfos);
+ Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
mHandler.sendMessage(msg);
}
scheduleAppGcsLocked();
@@ -3438,8 +3471,6 @@ public final class ActivityManagerService extends ActivityManagerNative
final void appDiedLocked(ProcessRecord app, int pid,
IApplicationThread thread) {
- mProcDeaths[0]++;
-
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteProcessDiedLocked(app.info.uid, pid);
@@ -3448,17 +3479,27 @@ public final class ActivityManagerService extends ActivityManagerNative
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- if (!app.killedBackground) {
+ boolean doLowMem = app.instrumentationClass == null;
+ boolean doOomAdj = doLowMem;
+ if (!app.killedByAm) {
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died.");
+ mAllowLowerMemLevel = true;
+ } else {
+ // Note that we always want to do oom adj to update our state with the
+ // new number of procs.
+ mAllowLowerMemLevel = false;
+ doLowMem = false;
}
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
if (DEBUG_CLEANUP) Slog.v(
TAG, "Dying app: " + app + ", pid: " + pid
+ ", thread: " + thread.asBinder());
- boolean doLowMem = app.instrumentationClass == null;
handleAppDiedLocked(app, false, true);
+ if (doOomAdj) {
+ updateOomAdjLocked();
+ }
if (doLowMem) {
doLowMemReportIfNeededLocked(app);
}
@@ -3791,10 +3832,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
- Slog.w(TAG, "Killing " + app + ": background ANR");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "background ANR");
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "background ANR");
return;
}
@@ -3979,6 +4017,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), false, true, "kill all background");
}
+ mAllowLowerMemLevel = true;
updateOomAdjLocked();
doLowMemReportIfNeededLocked(null);
}
@@ -4478,10 +4517,9 @@ public final class ActivityManagerService extends ActivityManagerNative
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
- Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
+ killUnneededProcessLocked(app, reason);
handleAppDiedLocked(app, true, allowRestart);
mLruProcesses.remove(app);
- Process.killProcessQuiet(pid);
if (app.persistent && !app.isolated) {
if (!callerWillRestart) {
@@ -4523,9 +4561,7 @@ public final class ActivityManagerService extends ActivityManagerNative
checkAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, pid,
- app.processName, app.setAdj, "start timeout");
- Process.killProcessQuiet(pid);
+ killUnneededProcessLocked(app, "start timeout");
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
try {
@@ -5769,8 +5805,8 @@ public final class ActivityManagerService extends ActivityManagerNative
pi.packageName, targetPkg, targetUid, uri);
final boolean persistChanged = perm.grantModes(modeFlags, persist, owner);
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -5994,8 +6030,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -6079,8 +6115,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (persistChanged) {
- mHandler.removeMessages(PERSIST_URI_GRANTS);
- mHandler.obtainMessage(PERSIST_URI_GRANTS).sendToTarget();
+ mHandler.removeMessages(PERSIST_URI_GRANTS_MSG);
+ mHandler.obtainMessage(PERSIST_URI_GRANTS_MSG).sendToTarget();
}
}
@@ -6508,6 +6544,16 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private void killUnneededProcessLocked(ProcessRecord pr, String reason) {
+ if (!pr.killedByAm) {
+ Slog.i(TAG, "Killing " + pr.toShortString() + " (adj " + pr.setAdj + "): " + reason);
+ EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
+ pr.processName, pr.setAdj, reason);
+ pr.killedByAm = true;
+ Process.killProcessQuiet(pr.pid);
+ }
+ }
+
private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) {
mRecentTasks.remove(tr);
mStackSupervisor.removeTask(tr);
@@ -6546,11 +6592,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=0; i<procs.size(); i++) {
ProcessRecord pr = procs.get(i);
if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + pr.toShortString() + ": remove task");
- EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
- pr.processName, pr.setAdj, "remove task");
- pr.killedBackground = true;
- Process.killProcessQuiet(pr.pid);
+ killUnneededProcessLocked(pr, "remove task");
} else {
pr.waitingToKill = "remove task";
}
@@ -8401,13 +8443,9 @@ public final class ActivityManagerService extends ActivityManagerNative
continue;
}
int adj = proc.setAdj;
- if (adj >= worstType && !proc.killedBackground) {
- Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId, proc.pid,
- proc.processName, adj, reason);
+ if (adj >= worstType && !proc.killedByAm) {
+ killUnneededProcessLocked(proc, reason);
killed = true;
- proc.killedBackground = true;
- Process.killProcessQuiet(pids[i]);
}
}
}
@@ -8449,13 +8487,9 @@ public final class ActivityManagerService extends ActivityManagerNative
if (proc == null) continue;
final int adj = proc.setAdj;
- if (adj > belowAdj && !proc.killedBackground) {
- Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId,
- proc.pid, proc.processName, adj, reason);
+ if (adj > belowAdj && !proc.killedByAm) {
+ killUnneededProcessLocked(proc, reason);
killed = true;
- proc.killedBackground = true;
- Process.killProcessQuiet(pid);
}
}
}
@@ -8533,6 +8567,61 @@ public final class ActivityManagerService extends ActivityManagerNative
br.onReceive(mContext, intent);
}
+ private long getLowRamTimeSinceIdle(long now) {
+ return mLowRamTimeSinceLastIdle + (mLowRamStartTime > 0 ? (now-mLowRamStartTime) : 0);
+ }
+
+ @Override
+ public void performIdleMaintenance() {
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ synchronized (this) {
+ final long now = SystemClock.uptimeMillis();
+ final long timeSinceLastIdle = now - mLastIdleTime;
+ final long lowRamSinceLastIdle = getLowRamTimeSinceIdle(now);
+ mLastIdleTime = now;
+ mLowRamTimeSinceLastIdle = 0;
+ if (mLowRamStartTime != 0) {
+ mLowRamStartTime = now;
+ }
+
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Idle maintenance over ");
+ TimeUtils.formatDuration(timeSinceLastIdle, sb);
+ sb.append(" low RAM for ");
+ TimeUtils.formatDuration(lowRamSinceLastIdle, sb);
+ Slog.i(TAG, sb.toString());
+
+ // If at least 1/3 of our time since the last idle period has been spent
+ // with RAM low, then we want to kill processes.
+ boolean doKilling = lowRamSinceLastIdle > (timeSinceLastIdle/3);
+
+ for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord proc = mLruProcesses.get(i);
+ if (proc.notCachedSinceIdle) {
+ if (proc.setProcState > ActivityManager.PROCESS_STATE_TOP
+ && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
+ if (doKilling && proc.initialIdlePss != 0
+ && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+ killUnneededProcessLocked(proc, "idle maint (pss " + proc.lastPss
+ + " from " + proc.initialIdlePss + ")");
+ }
+ }
+ } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
+ proc.notCachedSinceIdle = true;
+ proc.initialIdlePss = 0;
+ }
+ }
+
+ mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
+ mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
+ }
+ }
+
public final void startRunning(String pkg, String cls, String action,
String data) {
synchronized(this) {
@@ -8967,10 +9056,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app.pid > 0 && app.pid != MY_PID) {
handleAppCrashLocked(app);
- Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "user's request after error");
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "user request after error");
}
}
}
@@ -10444,6 +10530,15 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
+ " mNumServiceProcs=" + mNumServiceProcs
+ " mNewNumServiceProcs=" + mNewNumServiceProcs);
+ pw.println(" mAllowLowerMemLevel=" + mAllowLowerMemLevel
+ + " mLastMemoryLevel" + mLastMemoryLevel
+ + " mLastNumProcesses" + mLastNumProcesses);
+ long now = SystemClock.uptimeMillis();
+ pw.print(" mLastIdleTime=");
+ TimeUtils.formatDuration(now, mLastIdleTime, pw);
+ pw.print(" mLowRamSinceLastIdle=");
+ TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
+ pw.println();
}
}
@@ -11704,13 +11799,9 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!capp.persistent && capp.thread != null
&& capp.pid != 0
&& capp.pid != MY_PID) {
- Slog.i(TAG, "Kill " + capp.processName
- + " (pid " + capp.pid + "): provider " + cpr.info.name
- + " in dying process " + (proc != null ? proc.processName : "??"));
- EventLog.writeEvent(EventLogTags.AM_KILL, capp.userId, capp.pid,
- capp.processName, capp.setAdj, "dying provider "
- + cpr.name.toShortString());
- Process.killProcessQuiet(capp.pid);
+ killUnneededProcessLocked(capp, "depends on provider "
+ + cpr.name.flattenToShortString()
+ + " in dying proc " + (proc != null ? proc.processName : "??"));
}
} else if (capp.thread != null && conn.provider.provider != null) {
try {
@@ -12791,12 +12882,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) {
- mHandler.sendEmptyMessage(CLEAR_DNS_CACHE);
+ mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
}
if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
ProxyProperties proxy = intent.getParcelableExtra("proxy");
- mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY, proxy));
+ mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
}
// Add to the sticky list if requested.
@@ -14527,26 +14618,18 @@ public final class ActivityManagerService extends ActivityManagerNative
stats.reportExcessiveWakeLocked(app.info.uid, app.processName,
realtimeSince, wtimeUsed);
}
- Slog.w(TAG, "Excessive wake lock in " + app.processName
- + " (pid " + app.pid + "): held " + wtimeUsed
+ killUnneededProcessLocked(app, "excessive wake held " + wtimeUsed
+ " during " + realtimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "excessive wake lock");
app.baseProcessTracker.reportExcessiveWake(app.pkgList);
- Process.killProcessQuiet(app.pid);
} else if (doCpuKills && uptimeSince > 0
&& ((cputimeUsed*100)/uptimeSince) >= 50) {
synchronized (stats) {
stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
uptimeSince, cputimeUsed);
}
- Slog.w(TAG, "Excessive CPU in " + app.processName
- + " (pid " + app.pid + "): used " + cputimeUsed
+ killUnneededProcessLocked(app, "excessive cpu " + cputimeUsed
+ " during " + uptimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "excessive cpu");
app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
- Process.killProcessQuiet(app.pid);
} else {
app.lastWakeTime = wtime;
app.lastCpuTime = app.curCpuTime;
@@ -14593,11 +14676,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " to " + app.curSchedGroup);
if (app.waitingToKill != null &&
app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, app.waitingToKill);
success = false;
} else {
if (true) {
@@ -14657,6 +14736,9 @@ public final class ActivityManagerService extends ActivityManagerNative
"Proc state change of " + app.processName
+ " to " + app.curProcState);
app.setProcState = app.curProcState;
+ if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
+ app.notCachedSinceIdle = false;
+ }
if (!doingAll) {
setProcessTrackerState(app, mProcessStats.getMemFactorLocked(), now);
} else {
@@ -14783,7 +14865,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int nextEmptyAdj = curEmptyAdj+2;
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (!app.killedBackground && app.thread != null) {
+ if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
final boolean wasKeeping = app.keeping;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
@@ -14858,34 +14940,19 @@ public final class ActivityManagerService extends ActivityManagerNative
mNumCachedHiddenProcs++;
numCached++;
if (numCached > cachedProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): cached #" + numCached);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "cached #" + numCached);
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
if (numEmpty > ProcessList.TRIM_EMPTY_APPS
&& app.lastActivityTime < oldTime) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty for "
- + ((oldTime+ProcessList.MAX_EMPTY_TIME-app.lastActivityTime)
- / 1000) + "s");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "old background process");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "empty for "
+ + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
+ / 1000) + "s");
} else {
numEmpty++;
if (numEmpty > emptyProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty #" + numEmpty);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "empty #" + numEmpty);
}
}
break;
@@ -14901,16 +14968,11 @@ public final class ActivityManagerService extends ActivityManagerNative
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
// left sitting around after no longer needed.
- Slog.i(TAG, "Isolated process " + app.processName
- + " (pid " + app.pid + ") no longer needed");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "isolated not needed");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
+ killUnneededProcessLocked(app, "isolated not needed");
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
- && !app.killedBackground) {
+ && !app.killedByAm) {
numTrimming++;
}
}
@@ -14924,31 +14986,60 @@ public final class ActivityManagerService extends ActivityManagerNative
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
- boolean allChanged;
+ final int numCachedAndEmpty = numCached + numEmpty;
+ int memFactor;
if (numCached <= ProcessList.TRIM_CACHED_APPS
&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
- final int numCachedAndEmpty = numCached + numEmpty;
- int factor = numTrimming/3;
- int minFactor = 2;
- if (mHomeProcess != null) minFactor++;
- if (mPreviousProcess != null) minFactor++;
- if (factor < minFactor) factor = minFactor;
- int step = 0;
- int fgTrimLevel;
- int memFactor;
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
} else {
- fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
}
+ } else {
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+ }
+ // We always allow the memory level to go up (better). We only allow it to go
+ // down if we are in a state where that is allowed, *and* the total number of processes
+ // has gone down since last time.
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "oom: memFactor=" + memFactor + " last=" + mLastMemoryLevel
+ + " allowLow=" + mAllowLowerMemLevel + " numProcs=" + mLruProcesses.size()
+ + " last=" + mLastNumProcesses);
+ if (memFactor > mLastMemoryLevel) {
+ if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
+ memFactor = mLastMemoryLevel;
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "Keeping last mem factor!");
+ }
+ }
+ mLastMemoryLevel = memFactor;
+ mLastNumProcesses = mLruProcesses.size();
+ boolean allChanged = mProcessStats.setMemFactorLocked(
+ ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
+ final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
+ if (mLowRamStartTime == 0) {
+ mLowRamStartTime = now;
+ }
+ int step = 0;
+ int fgTrimLevel;
+ switch (memFactor) {
+ case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+ break;
+ case ProcessStats.ADJ_MEM_FACTOR_LOW:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+ break;
+ default:
+ fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+ break;
+ }
+ int factor = numTrimming/3;
+ int minFactor = 2;
+ if (mHomeProcess != null) minFactor++;
+ if (mPreviousProcess != null) minFactor++;
+ if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -14956,7 +15047,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.procStateChanged = false;
}
if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
- && !app.killedBackground) {
+ && !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
@@ -15036,9 +15127,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} else {
- allChanged = mProcessStats.setMemFactorLocked(
- ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ if (mLowRamStartTime != 0) {
+ mLowRamTimeSinceLastIdle += now - mLowRamStartTime;
+ mLowRamStartTime = 0;
+ }
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -15107,6 +15199,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (app.pid > 0 && app.pid != MY_PID) {
EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "empty");
+ app.killedByAm = true;
Process.killProcessQuiet(app.pid);
} else {
try {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index e0eb2c431ce7..f5d45b343b3f 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1417,7 +1417,8 @@ public final class ActivityStackSupervisor {
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);
- if (curTop != null && curTop.task != intentActivity.task) {
+ if (curTop != null && (curTop.task != intentActivity.task) ||
+ curTop.task != lastStack.topTask()) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 35e06b655d98..4fdacb3733ce 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -66,6 +66,8 @@ final class ProcessRecord {
long lastPssTime; // Last time we retrieved PSS data
long nextPssTime; // Next time we want to request PSS data
long lastStateTime; // Last time setProcState changed
+ long initialIdlePss; // Initial memory pss of process for idle maintenance.
+ long lastPss; // Last computed memory pss.
int maxAdj; // Maximum OOM adjustment for this process
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
@@ -82,6 +84,7 @@ final class ProcessRecord {
boolean serviceb; // Process currently is on the service B list
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
+ boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
boolean hasActivities; // Are there any activities running in this process?
boolean hasClientActivities; // Are there any client services with activities?
boolean hasStartedServices; // Are there any started services running in this process?
@@ -92,7 +95,7 @@ final class ProcessRecord {
boolean pendingUiClean; // Want to clean up resources from showing UI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean bad; // True if disabled in the bad process list
- boolean killedBackground; // True when proc has been killed due to too many bg
+ boolean killedByAm; // True when proc has been killed by activity manager, not for RAM
boolean procStateChanged; // Keep track of whether we changed 'setAdj'.
String waitingToKill; // Process is waiting to be killed when in the bg; reason
IBinder forcingToForeground;// Token that is forcing this process to be foreground
@@ -216,6 +219,11 @@ final class ProcessRecord {
pw.print(" keeping="); pw.print(keeping);
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
+ if (notCachedSinceIdle) {
+ pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
+ pw.print(" initialIdlePss="); pw.print(initialIdlePss);
+ pw.print(" lastPss="); pw.println(lastPss);
+ }
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
pw.print(" setRaw="); pw.print(setRawAdj);
@@ -280,8 +288,8 @@ final class ProcessRecord {
pw.print(" lastLowMemory=");
TimeUtils.formatDuration(lastLowMemory, now, pw);
pw.print(" reportLowMemory="); pw.println(reportLowMemory);
- if (killedBackground || waitingToKill != null) {
- pw.print(prefix); pw.print("killedBackground="); pw.print(killedBackground);
+ if (killedByAm || waitingToKill != null) {
+ pw.print(prefix); pw.print("killedByAm="); pw.print(killedByAm);
pw.print(" waitingToKill="); pw.println(waitingToKill);
}
if (debugging || crashing || crashDialog != null || notResponding
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index c180f6e38b28..f5f43ab29548 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -551,17 +551,23 @@ public final class ProcessStatsService extends IProcessStats.Stub {
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
- mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
- writeStateLocked(true, true);
- pw.println("Process stats committed.");
+ synchronized (mAm) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+ writeStateLocked(true, true);
+ pw.println("Process stats committed.");
+ }
return;
} else if ("--write".equals(arg)) {
- writeStateSyncLocked();
- pw.println("Process stats written.");
+ synchronized (mAm) {
+ writeStateSyncLocked();
+ pw.println("Process stats written.");
+ }
return;
} else if ("--read".equals(arg)) {
- readLocked(mProcessStats, mFile);
- pw.println("Process stats read.");
+ synchronized (mAm) {
+ readLocked(mProcessStats, mFile);
+ pw.println("Process stats read.");
+ }
return;
} else if ("-h".equals(arg)) {
dumpHelp(pw);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7cc568e25d99..decda96060fe 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5509,10 +5509,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// version of the one on the data partition, but which
// granted a new system permission that it didn't have
// before. In this case we do want to allow the app to
- // now get the new permission, because it is allowed by
- // the system image.
- allowed = false;
- if (sysPs.pkg != null) {
+ // now get the new permission if the new system-partition
+ // apk is privileged to get it.
+ if (sysPs.pkg != null && isPrivilegedApp(pkg)) {
for (int j=0;
j<sysPs.pkg.requestedPermissions.size(); j++) {
if (perm.equals(
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 8e0c92a2084f..377c390f7275 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2853,6 +2853,7 @@ final class Settings {
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index 5a24ebb4cb1f..bbcd01a87bd3 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -172,10 +172,16 @@ public final class WifiService extends IWifiManager.Stub {
case WifiManager.CONNECT_NETWORK:
case WifiManager.SAVE_NETWORK: {
WifiConfiguration config = (WifiConfiguration) msg.obj;
- if (config.isValid()) {
+ int networkId = msg.arg1;
+ if (config != null && config.isValid()) {
+ if (DBG) Slog.d(TAG, "Connect with config" + config);
+ mWifiStateMachine.sendMessage(Message.obtain(msg));
+ } else if (config == null
+ && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+ if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else {
- Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
+ Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
if (msg.what == WifiManager.CONNECT_NETWORK) {
replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
} else {
@@ -582,7 +588,8 @@ public final class WifiService extends IWifiManager.Stub {
*/
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
- if (wifiConfig.isValid()) {
+ // null wifiConfig is a meaningful input for CMD_SET_AP
+ if (wifiConfig == null || wifiConfig.isValid()) {
mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
} else {
Slog.e(TAG, "Invalid WifiConfiguration");
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 2ce584b2b206..2b3c9e21bed1 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -355,7 +355,15 @@ public class WifiConfiguration implements Parcelable {
*/
public boolean isValid() {
if (allowedKeyManagement.cardinality() > 1) {
- return false;
+ if (allowedKeyManagement.cardinality() != 2) {
+ return false;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) {
+ return false;
+ }
+ if (allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false) {
+ return false;
+ }
}
// TODO: Add more checks