summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--api/current.txt106
-rw-r--r--core/java/android/animation/TypeEvaluator.java2
-rw-r--r--core/java/android/app/ContextImpl.java8
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java40
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl4
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java43
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java9
-rw-r--r--core/java/android/bluetooth/BluetoothGattServer.java6
-rw-r--r--core/java/android/bluetooth/BluetoothManager.java22
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java1
-rw-r--r--core/java/android/bluetooth/BluetoothTetheringDataTracker.java8
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java63
-rw-r--r--core/java/android/bluetooth/IBluetoothGatt.aidl4
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/Intent.java16
-rw-r--r--core/java/android/content/pm/ActivityInfo.java39
-rw-r--r--core/java/android/content/pm/PackageParser.java31
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java315
-rw-r--r--core/java/android/os/UserManager.java91
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/service/fingerprint/FingerprintManager.java200
-rw-r--r--core/java/android/service/fingerprint/FingerprintManagerReceiver.java59
-rw-r--r--core/java/android/service/fingerprint/FingerprintService.java219
-rw-r--r--core/java/android/service/fingerprint/FingerprintUtils.java85
-rw-r--r--core/java/android/service/fingerprint/IFingerprintService.aidl38
-rw-r--r--core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl30
-rw-r--r--core/java/android/speech/tts/BlockingAudioTrack.java13
-rw-r--r--core/java/android/speech/tts/FileSynthesisCallback.java3
-rw-r--r--core/java/android/view/SurfaceControl.java25
-rw-r--r--core/java/android/view/TextureView.java30
-rw-r--r--core/java/android/view/View.java15
-rw-r--r--core/java/android/view/ViewGroup.java1
-rw-r--r--core/java/android/view/WindowInsets.java54
-rw-r--r--core/java/android/webkit/PermissionRequest.java13
-rw-r--r--core/java/android/webkit/WebChromeClient.java4
-rw-r--r--core/java/android/webkit/WebView.java8
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl3
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl3
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/android/graphics/SurfaceTexture.cpp4
-rw-r--r--core/jni/android_media_AudioFormat.h3
-rw-r--r--core/jni/android_server_FingerprintManager.cpp73
-rw-r--r--core/jni/android_view_SurfaceControl.cpp66
-rw-r--r--core/res/res/values/attrs_manifest.xml43
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java50
-rw-r--r--docs/html/guide/components/intents-common.jd2
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java105
-rw-r--r--media/java/android/media/AudioFormat.java19
-rw-r--r--media/java/android/media/AudioRecord.java2
-rw-r--r--media/java/android/media/AudioTrack.java2
-rw-r--r--media/java/android/media/JetPlayer.java6
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/res/values/ids.xml30
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java150
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Constants.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java396
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java3
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java28
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java66
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java18
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java8
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp81
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java109
85 files changed, 2784 insertions, 362 deletions
diff --git a/Android.mk b/Android.mk
index 8e283d7..c80a9ab 100644
--- a/Android.mk
+++ b/Android.mk
@@ -199,6 +199,8 @@ LOCAL_SRC_FILES += \
core/java/android/service/dreams/IDozeHardware.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
+ core/java/android/service/fingerprint/IFingerprintService.aidl \
+ core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/service/trust/ITrustAgentService.aidl \
core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
core/java/android/service/voice/IVoiceInteractionService.aidl \
diff --git a/api/current.txt b/api/current.txt
index cca12be..1c9f871 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -314,6 +314,7 @@ package android {
field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
+ field public static final int autoRemoveFromRecents = 16843859; // 0x1010453
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -463,6 +464,7 @@ package android {
field public static final int dividerHorizontal = 16843564; // 0x101032c
field public static final int dividerPadding = 16843562; // 0x101032a
field public static final int dividerVertical = 16843530; // 0x101030a
+ field public static final int documentLaunchMode = 16843858; // 0x1010452
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
@@ -5013,6 +5015,8 @@ package android.app.admin {
method public void clearForwardingIntentFilters(android.content.ComponentName);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public void enableSystemApp(android.content.ComponentName, java.lang.String);
+ method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -6614,6 +6618,7 @@ package android.content {
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
+ field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
@@ -7149,6 +7154,7 @@ package android.content {
field public static final int FILL_IN_PACKAGE = 16; // 0x10
field public static final int FILL_IN_SELECTOR = 64; // 0x40
field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
+ field public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
@@ -7667,8 +7673,12 @@ package android.content.pm {
field public static final int CONFIG_TOUCHSCREEN = 8; // 0x8
field public static final int CONFIG_UI_MODE = 512; // 0x200
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2
+ field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
+ field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
+ field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
@@ -7677,6 +7687,7 @@ package android.content.pm {
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
field public static final int FLAG_NO_HISTORY = 128; // 0x80
+ field public static final int FLAG_PERSISTABLE = 4096; // 0x1000
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
field public static final int LAUNCH_MULTIPLE = 0; // 0x0
@@ -7701,6 +7712,7 @@ package android.content.pm {
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
field public int configChanges;
+ field public int documentLaunchMode;
field public int flags;
field public int launchMode;
field public java.lang.String parentActivityName;
@@ -10734,6 +10746,7 @@ package android.graphics {
method public void releaseTexImage();
method public void setDefaultBufferSize(int, int);
method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
+ method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener, android.os.Handler);
method public void updateTexImage();
}
@@ -12171,17 +12184,29 @@ package android.hardware.camera2 {
method public int getSequenceId();
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
+ field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
@@ -12212,6 +12237,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
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_TEST_PATTERN_DATA;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE;
@@ -12220,6 +12246,7 @@ package android.hardware.camera2 {
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
@@ -20493,9 +20520,17 @@ package android.os {
method public void setUserRestriction(java.lang.String, boolean);
method public void setUserRestrictions(android.os.Bundle);
method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+ field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
+ field public static final java.lang.String DISALLOW_CONFIG_APPS = "no_config_apps";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+ field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
+ field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+ field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+ field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+ field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+ field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
@@ -20503,6 +20538,7 @@ package android.os {
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
}
public abstract class Vibrator {
@@ -25047,6 +25083,36 @@ package android.service.dreams {
}
+package android.service.fingerprint {
+
+ public class FingerprintManager {
+ ctor public FingerprintManager(android.content.Context);
+ method public void enroll(long);
+ method public void remove(int);
+ method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
+ method public void stopListening();
+ field protected static final boolean DEBUG = true;
+ field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
+ field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
+ field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+ field public static final int FINGERPRINT_SCANNED = 1; // 0x1
+ field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+ field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
+ }
+
+ public class FingerprintManagerReceiver {
+ ctor public FingerprintManagerReceiver();
+ method public void onEnrollResult(int, int);
+ method public void onError(int);
+ method public void onRemoved(int);
+ method public void onScanned(int, int);
+ }
+
+}
+
package android.service.notification {
public abstract class NotificationListenerService extends android.app.Service {
@@ -31584,26 +31650,17 @@ package android.view {
method public abstract void onFocusLost(android.view.WindowId);
}
- public class WindowInsets {
+ public final class WindowInsets {
ctor public WindowInsets(android.view.WindowInsets);
- method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
- method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
- method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
- method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
- method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
- method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public android.view.WindowInsets consumeSystemWindowInsets();
method public int getSystemWindowInsetBottom();
method public int getSystemWindowInsetLeft();
method public int getSystemWindowInsetRight();
method public int getSystemWindowInsetTop();
- method public int getWindowDecorInsetBottom();
- method public int getWindowDecorInsetLeft();
- method public int getWindowDecorInsetRight();
- method public int getWindowDecorInsetTop();
method public boolean hasInsets();
method public boolean hasSystemWindowInsets();
- method public boolean hasWindowDecorInsets();
method public boolean isRound();
+ method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
}
public abstract interface WindowManager implements android.view.ViewManager {
@@ -32930,6 +32987,16 @@ package android.webkit {
method public boolean hasMimeType(java.lang.String);
}
+ public abstract interface PermissionRequest {
+ method public abstract void deny();
+ method public abstract android.net.Uri getOrigin();
+ method public abstract long getResources();
+ method public abstract void grant(long);
+ field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
+ field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L
+ field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
+ }
+
public abstract interface PluginStub {
method public abstract android.view.View getEmbeddedView(int, android.content.Context);
method public abstract android.view.View getFullScreenView(int, android.content.Context);
@@ -32989,6 +33056,8 @@ package android.webkit {
method public boolean onJsConfirm(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
method public deprecated boolean onJsTimeout();
+ method public void onPermissionRequest(android.webkit.PermissionRequest);
+ method public void onPermissionRequestCanceled(android.webkit.PermissionRequest);
method public void onProgressChanged(android.webkit.WebView, int);
method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
@@ -33276,6 +33345,7 @@ package android.webkit {
method public boolean pageUp(boolean);
method public void pauseTimers();
method public void postUrl(java.lang.String, byte[]);
+ method public void preauthorizePermission(android.net.Uri, long);
method public void reload();
method public void removeJavascriptInterface(java.lang.String);
method public void requestFocusNodeHref(android.os.Message);
@@ -49559,6 +49629,7 @@ package javax.net.ssl {
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
+ method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
method public abstract boolean getNeedClientAuth();
method public java.lang.String getPeerHost();
@@ -49632,10 +49703,12 @@ package javax.net.ssl {
ctor public SSLParameters(java.lang.String[]);
ctor public SSLParameters(java.lang.String[], java.lang.String[]);
method public java.lang.String[] getCipherSuites();
+ method public java.lang.String getEndpointIdentificationAlgorithm();
method public boolean getNeedClientAuth();
method public java.lang.String[] getProtocols();
method public boolean getWantClientAuth();
method public void setCipherSuites(java.lang.String[]);
+ method public void setEndpointIdentificationAlgorithm(java.lang.String);
method public void setNeedClientAuth(boolean);
method public void setProtocols(java.lang.String[]);
method public void setWantClientAuth(boolean);
@@ -49736,6 +49809,7 @@ package javax.net.ssl {
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
+ method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract boolean getNeedClientAuth();
method public javax.net.ssl.SSLParameters getSSLParameters();
method public abstract javax.net.ssl.SSLSession getSession();
@@ -49791,6 +49865,14 @@ package javax.net.ssl {
method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine);
}
+ public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager {
+ ctor public X509ExtendedTrustManager();
+ method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ }
+
public abstract interface X509KeyManager implements javax.net.ssl.KeyManager {
method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket);
method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket);
diff --git a/core/java/android/animation/TypeEvaluator.java b/core/java/android/animation/TypeEvaluator.java
index 2640457..429c435 100644
--- a/core/java/android/animation/TypeEvaluator.java
+++ b/core/java/android/animation/TypeEvaluator.java
@@ -29,7 +29,7 @@ public interface TypeEvaluator<T> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
- * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+ * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fe532bf..c621696 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -106,6 +106,9 @@ import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintService;
import android.telephony.TelephonyManager;
import android.tv.ITvInputManager;
import android.tv.TvInputManager;
@@ -451,6 +454,11 @@ class ContextImpl extends Context {
return new KeyguardManager();
}});
+ registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new FingerprintManager(ctx);
+ }});
+
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 929bf65..b24b932 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -22,6 +22,7 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -2041,4 +2042,43 @@ public class DevicePolicyManager {
}
}
}
+
+ /**
+ * Called by profile or device owner to re-enable a system app that was disabled by default
+ * when the managed profile was created. This should only be called from a profile or device
+ * owner running within a managed profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The package to be re-enabled in the current profile.
+ */
+ public void enableSystemApp(ComponentName admin, String packageName) {
+ if (mService != null) {
+ try {
+ mService.enableSystemApp(admin, packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to install package: " + packageName);
+ }
+ }
+ }
+
+ /**
+ * Called by profile or device owner to re-enable system apps by intent that were disabled
+ * by default when the managed profile was created. This should only be called from a profile
+ * or device owner running within a managed profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param intent An intent matching the app(s) to be installed. All apps that resolve for this
+ * intent will be re-enabled in the current profile.
+ * @returns int The number of activities that matched the intent and were installed.
+ */
+ public int enableSystemApp(ComponentName admin, Intent intent) {
+ if (mService != null) {
+ try {
+ return mService.enableSystemAppWithIntent(admin, intent);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to install packages matching filter: " + intent);
+ }
+ }
+ return 0;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e3090b6..b30f1b9 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,7 @@
package android.app.admin;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteCallback;
@@ -122,4 +123,7 @@ interface IDevicePolicyManager {
void setUserRestriction(in ComponentName who, in String key, boolean enable);
void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearForwardingIntentFilters(in ComponentName admin);
+
+ void enableSystemApp(in ComponentName admin, in String packageName);
+ int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a396a05..7f8d0ab 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -512,6 +512,25 @@ public final class BluetoothDevice implements Parcelable {
*/
public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+ /**
+ * No preferrence of physical transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_AUTO = 0;
+
+ /**
+ * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_BREDR = 1;
+
+ /**
+ * Prefer LE transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_LE = 2;
+
+
/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
@@ -1216,6 +1235,27 @@ public final class BluetoothDevice implements Parcelable {
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
+ return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
+ }
+
+ /**
+ * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as any further GATT client operations.
+ * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+ * GATT client operations.
+ * @param callback GATT callback handler that will receive asynchronous callbacks.
+ * @param autoConnect Whether to directly connect to the remote device (false)
+ * or to automatically connect as soon as the remote
+ * device becomes available (true).
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @throws IllegalArgumentException if callback is null
+ * @hide
+ */
+ public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+ BluetoothGattCallback callback, int transport) {
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1226,10 +1266,11 @@ public final class BluetoothDevice implements Parcelable {
// BLE is not supported
return null;
}
- BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
+ BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
+
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ff3af7c..601d9ee 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -51,6 +51,7 @@ public final class BluetoothGatt implements BluetoothProfile {
private int mConnState;
private final Object mStateLock = new Object();
private Boolean mDeviceBusy = false;
+ private int mTransport;
private static final int CONN_STATE_IDLE = 0;
private static final int CONN_STATE_CONNECTING = 1;
@@ -135,7 +136,7 @@ public final class BluetoothGatt implements BluetoothProfile {
}
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
- !mAutoConnect); // autoConnect is inverse of "isDirect"
+ !mAutoConnect, mTransport); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
@@ -600,10 +601,12 @@ public final class BluetoothGatt implements BluetoothProfile {
}
};
- /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
+ /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
+ int transport) {
mContext = context;
mService = iGatt;
mDevice = device;
+ mTransport = transport;
mServices = new ArrayList<BluetoothGattService>();
mConnState = CONN_STATE_IDLE;
@@ -759,7 +762,7 @@ public final class BluetoothGatt implements BluetoothProfile {
public boolean connect() {
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
- false); // autoConnect is inverse of "isDirect"
+ false, mTransport); // autoConnect is inverse of "isDirect"
return true;
} catch (RemoteException e) {
Log.e(TAG,"",e);
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 0c00c06..34e8605 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -50,6 +50,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
private Object mServerIfLock = new Object();
private int mServerIf;
+ private int mTransport;
private List<BluetoothGattService> mServices;
private static final int CALLBACK_REG_TIMEOUT = 10000;
@@ -269,12 +270,13 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Create a BluetoothGattServer proxy object.
*/
- /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
+ /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
mContext = context;
mService = iGatt;
mAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = null;
mServerIf = 0;
+ mTransport = transport;
mServices = new ArrayList<BluetoothGattService>();
}
@@ -401,7 +403,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
try {
mService.serverConnect(mServerIf, device.getAddress(),
- autoConnect ? false : true); // autoConnect is inverse of "isDirect"
+ autoConnect ? false : true,mTransport); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 172f3bc..b1618cf3 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -194,6 +194,26 @@ public final class BluetoothManager {
*/
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
+
+ return (openGattServer (context, callback, BluetoothDevice.TRANSPORT_AUTO));
+ }
+
+ /**
+ * Open a GATT Server
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as the results of any other GATT server operations.
+ * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+ * to conduct GATT server operations.
+ * @param context App context
+ * @param callback GATT server callback handler that will receive asynchronous callbacks.
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @return BluetoothGattServer instance
+ * @hide
+ */
+ public BluetoothGattServer openGattServer(Context context,
+ BluetoothGattServerCallback callback,int transport) {
if (context == null || callback == null) {
throw new IllegalArgumentException("null parameter: " + context + " " + callback);
}
@@ -208,7 +228,7 @@ public final class BluetoothManager {
Log.e(TAG, "Fail to get GATT Server connection");
return null;
}
- BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
+ BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
Boolean regStatus = mGattServer.registerCallback(callback);
return regStatus? mGattServer : null;
} catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index f532f7c..00fd7ce 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -325,6 +325,7 @@ public final class BluetoothSocket implements Closeable {
}
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ throw new IOException("unable to send RPC: " + e.getMessage());
}
}
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 6dd551e..a0b603e 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -53,6 +53,9 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
private static final boolean DBG = true;
private static final boolean VDBG = true;
+ // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
+ private static final int EVENT_NETWORK_FAILED = 1;
+
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
@@ -315,6 +318,7 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
}
if (!success) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+ mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
return;
}
mLinkProperties = dhcpResults.linkProperties;
@@ -407,6 +411,10 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
mBtdt.stopReverseTether();
break;
+ case EVENT_NETWORK_FAILED:
+ if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
+ mBtdt.teardown();
+ break;
}
}
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 4b28516..ab53fb0 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -18,6 +18,8 @@ package android.bluetooth;
import android.os.ParcelUuid;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.UUID;
@@ -76,6 +78,12 @@ public final class BluetoothUuid {
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
+ /** Length of bytes for 16 bit UUID */
+ public static final int UUID_BYTES_16_BIT = 2;
+ /** Length of bytes for 32 bit UUID */
+ public static final int UUID_BYTES_32_BIT = 4;
+ /** Length of bytes for 128 bit UUID */
+ public static final int UUID_BYTES_128_BIT = 16;
public static final ParcelUuid[] RESERVED_UUIDS = {
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
@@ -216,15 +224,60 @@ public final class BluetoothUuid {
}
/**
+ * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
+ * but the returned UUID is always in 128-bit format.
+ * Note UUID is little endian in Bluetooth.
+ *
+ * @param uuidBytes Byte representation of uuid.
+ * @return {@link ParcelUuid} parsed from bytes.
+ * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+ */
+ public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+ if (uuidBytes == null) {
+ throw new IllegalArgumentException("uuidBytes cannot be null");
+ }
+ int length = uuidBytes.length;
+ if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
+ length != UUID_BYTES_128_BIT) {
+ throw new IllegalArgumentException("uuidBytes length invalid - " + length);
+ }
+
+ // Construct a 128 bit UUID.
+ if (length == UUID_BYTES_128_BIT) {
+ ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
+ long msb = buf.getLong(8);
+ long lsb = buf.getLong(0);
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
+ // 128_bit_value = uuid * 2^96 + BASE_UUID
+ long shortUuid;
+ if (length == UUID_BYTES_16_BIT) {
+ shortUuid = uuidBytes[0] & 0xFF;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ } else {
+ shortUuid = uuidBytes[0] & 0xFF ;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ shortUuid += (uuidBytes[2] & 0xFF) << 16;
+ shortUuid += (uuidBytes[3] & 0xFF) << 24;
+ }
+ long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
+ long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ /**
* Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
+ *
* @param parcelUuid
* @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
*/
public static boolean isShortUuid(ParcelUuid parcelUuid) {
- UUID uuid = parcelUuid.getUuid();
- if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
- return false;
- }
- return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
+ UUID uuid = parcelUuid.getUuid();
+ if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+ return false;
+ }
+ return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
}
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index c6b5c3d..49b156d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,7 +35,7 @@ interface IBluetoothGatt {
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
void unregisterClient(in int clientIf);
- void clientConnect(in int clientIf, in String address, in boolean isDirect);
+ void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
void clientDisconnect(in int clientIf, in String address);
void startAdvertising(in int appIf);
void stopAdvertising();
@@ -77,7 +77,7 @@ interface IBluetoothGatt {
void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
void unregisterServer(in int serverIf);
- void serverConnect(in int servertIf, in String address, in boolean isDirect);
+ void serverConnect(in int servertIf, in String address, in boolean isDirect, in int transport);
void serverDisconnect(in int serverIf, in String address);
void beginServiceDeclaration(in int serverIf, in int srvcType,
in int srvcInstanceId, in int minHandles,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index de223a3..7c625bd 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2377,6 +2377,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.service.fingerprint.FingerprintManager} for handling management
+ * of fingerprints.
+ *
+ * @see #getSystemService
+ * @see android.app.FingerprintManager
+ */
+ public static final String FINGERPRINT_SERVICE = "fingerprint";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.media.MediaRouter} for controlling and managing
* routing of media.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ae5437b..3cfc56c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3736,7 +3736,8 @@ public class Intent implements Parcelable, Cloneable {
*
* <p>When set, the activity specified by this Intent will launch into a
* separate task rooted at that activity. The activity launched must be
- * defined with {@link android.R.attr#launchMode} "standard" or "singleTop".
+ * defined with {@link android.R.attr#launchMode} <code>standard</code>
+ * or <code>singleTop</code>.
*
* <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
* {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
@@ -3751,6 +3752,8 @@ public class Intent implements Parcelable, Cloneable {
* always create a new task. Thus the same document may be made to appear
* more than one time in Recents.
*
+ * <p>This is equivalent to the attribute {@link android.R.attr#documentLaunchMode}.
+ *
* @see #FLAG_ACTIVITY_MULTIPLE_TASK
*/
public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
@@ -3815,6 +3818,15 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;
/**
+ * If set and the new activity is the root of a new task, then the task
+ * will remain in the list of recently launched tasks only until all of
+ * the activities in it are finished.
+ *
+ * <p>This is equivalent to the attribute
+ * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}.
+ */
+ public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 0x00002000;
+ /**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
*/
@@ -4019,7 +4031,7 @@ public class Intent implements Parcelable, Cloneable {
/**
* Create an intent for a specific component with a specified action and data.
- * This is equivalent using {@link #Intent(String, android.net.Uri)} to
+ * This is equivalent to using {@link #Intent(String, android.net.Uri)} to
* construct the Intent and then calling {@link #setClass} to set its
* class.
*
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c53e545..c2fe3a2 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -67,7 +67,37 @@ public class ActivityInfo extends ComponentInfo
* {@link #LAUNCH_SINGLE_INSTANCE}.
*/
public int launchMode;
-
+
+ /**
+ * Constant corresponding to <code>none</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_NONE = 0;
+ /**
+ * Constant corresponding to <code>intoExisting</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1;
+ /**
+ * Constant corresponding to <code>always</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_ALWAYS = 2;
+ /**
+ * The document launch mode style requested by the activity. From the
+ * {@link android.R.attr#documentLaunchMode} attribute, one of
+ * {@link #DOCUMENT_LAUNCH_NONE}, {@link #DOCUMENT_LAUNCH_INTO_EXISTING},
+ * {@link #DOCUMENT_LAUNCH_ALWAYS}.
+ *
+ * <p>Modes DOCUMENT_LAUNCH_ALWAYS
+ * and DOCUMENT_LAUNCH_INTO_EXISTING are equivalent to {@link
+ * android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ * Intent.FLAG_ACTIVITY_NEW_DOCUMENT} with and without {@link
+ * android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ * Intent.FLAG_ACTIVITY_MULTIPLE_TASK} respectively.
+ */
+ public int documentLaunchMode;
+
/**
* Optional name of a permission required to be able to access this
* Activity. From the "permission" attribute.
@@ -192,10 +222,15 @@ public class ActivityInfo extends ComponentInfo
* Bit in {@link #flags} indicating that this activity is to be persisted across
* reboots for display in the Recents list.
* {@link android.R.attr#persistable}
- * @hide
*/
public static final int FLAG_PERSISTABLE = 0x1000;
/**
+ * Bit in {@link #flags} indicating that tasks started with this activity are to be
+ * removed from the recent list of tasks when the last activity in the task is finished.
+ * {@link android.R.attr#autoRemoveFromRecents}
+ */
+ public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 0x2000;
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
* android.R.attr#primaryUserOnly attribute.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 080b37b..d80ab7b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2462,17 +2462,6 @@ public class PackageParser {
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
- a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
- }
-
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
- false)) {
- a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
- }
-
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
@@ -2483,6 +2472,9 @@ public class PackageParser {
a.info.launchMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
ActivityInfo.LAUNCH_MULTIPLE);
+ a.info.documentLaunchMode = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
+ ActivityInfo.DOCUMENT_LAUNCH_NONE);
a.info.screenOrientation = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -2492,6 +2484,23 @@ public class PackageParser {
a.info.softInputMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
0);
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
+ }
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+ }
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d8981c8..1d2d0e9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -124,6 +124,58 @@ public final class CaptureResult extends CameraMetadata {
/**
+ * <p>The mode control selects how the image data is converted from the
+ * sensor's native color into linear sRGB color.</p>
+ * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+ * control is overridden by the AWB routine. When AWB is disabled, the
+ * application controls how the color mapping is performed.</p>
+ * <p>We define the expected processing pipeline below. For consistency
+ * across devices, this is always the case with TRANSFORM_MATRIX.</p>
+ * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+ * do additional processing but {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} will still be provided by the
+ * camera device (in the results) and be roughly correct.</p>
+ * <p>Switching to TRANSFORM_MATRIX and using the data provided from
+ * FAST or HIGH_QUALITY will yield a picture with the same white point
+ * as what was produced by the camera device in the earlier frame.</p>
+ * <p>The expected processing pipeline is as follows:</p>
+ * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+ * <p>The white balance is encoded by two values, a 4-channel white-balance
+ * gain vector (applied in the Bayer domain), and a 3x3 color transform
+ * matrix (applied after demosaic).</p>
+ * <p>The 4-channel white-balance gains are defined as:</p>
+ * <pre><code>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} = [ R G_even G_odd B ]
+ * </code></pre>
+ * <p>where <code>G_even</code> is the gain for green pixels on even rows of the
+ * output, and <code>G_odd</code> is the gain for green pixels on the odd rows.
+ * These may be identical for a given camera device implementation; if
+ * the camera device does not support a separate gain for even/odd green
+ * channels, it will use the <code>G_even</code> value, and write <code>G_odd</code> equal to
+ * <code>G_even</code> in the output result metadata.</p>
+ * <p>The matrices for color transforms are defined as a 9-entry vector:</p>
+ * <pre><code>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
+ * </code></pre>
+ * <p>which define a transform from input sensor colors, <code>P_in = [ r g b ]</code>,
+ * to output linear sRGB, <code>P_out = [ r' g' b' ]</code>,</p>
+ * <p>with colors as follows:</p>
+ * <pre><code>r' = I0r + I1g + I2b
+ * g' = I3r + I4g + I5b
+ * b' = I6r + I7g + I8b
+ * </code></pre>
+ * <p>Both the input and output value ranges must match. Overflow/underflow
+ * values are clipped to fit within the range.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+ * @see CaptureRequest#CONTROL_AWB_MODE
+ * @see #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX
+ * @see #COLOR_CORRECTION_MODE_FAST
+ * @see #COLOR_CORRECTION_MODE_HIGH_QUALITY
+ */
+ public static final Key<Integer> COLOR_CORRECTION_MODE =
+ new Key<Integer>("android.colorCorrection.mode", int.class);
+
+ /**
* <p>A color transform matrix to use to transform
* from sensor RGB color space to output linear sRGB color space</p>
* <p>This matrix is either set by the camera device when the request
@@ -176,6 +228,82 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.aePrecaptureId", int.class);
/**
+ * <p>The desired setting for the camera device's auto-exposure
+ * algorithm's antibanding compensation.</p>
+ * <p>Some kinds of lighting fixtures, such as some fluorescent
+ * lights, flicker at the rate of the power supply frequency
+ * (60Hz or 50Hz, depending on country). While this is
+ * typically not noticeable to a person, it can be visible to
+ * a camera device. If a camera sets its exposure time to the
+ * wrong value, the flicker may become visible in the
+ * viewfinder as flicker or in a final captured image, as a
+ * set of variable-brightness bands across the image.</p>
+ * <p>Therefore, the auto-exposure routines of camera devices
+ * include antibanding routines that ensure that the chosen
+ * exposure value will not cause such banding. The choice of
+ * exposure time depends on the rate of flicker, which the
+ * camera device can detect automatically, or the expected
+ * rate can be selected by the application using this
+ * control.</p>
+ * <p>A given camera device may not support all of the possible
+ * options for the antibanding mode. The
+ * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES android.control.aeAvailableAntibandingModes} key contains
+ * the available modes for a given camera device.</p>
+ * <p>The default mode is AUTO, which must be supported by all
+ * camera devices.</p>
+ * <p>If manual exposure control is enabled (by setting
+ * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} to OFF),
+ * then this setting has no effect, and the application must
+ * ensure it selects exposure times that do not cause banding
+ * issues. The {@link CaptureResult#STATISTICS_SCENE_FLICKER android.statistics.sceneFlicker} key can assist
+ * the application in this.</p>
+ *
+ * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_MODE
+ * @see CaptureResult#STATISTICS_SCENE_FLICKER
+ * @see #CONTROL_AE_ANTIBANDING_MODE_OFF
+ * @see #CONTROL_AE_ANTIBANDING_MODE_50HZ
+ * @see #CONTROL_AE_ANTIBANDING_MODE_60HZ
+ * @see #CONTROL_AE_ANTIBANDING_MODE_AUTO
+ */
+ public static final Key<Integer> CONTROL_AE_ANTIBANDING_MODE =
+ new Key<Integer>("android.control.aeAntibandingMode", int.class);
+
+ /**
+ * <p>Adjustment to AE target image
+ * brightness</p>
+ * <p>For example, if EV step is 0.333, '6' will mean an
+ * exposure compensation of +2 EV; -3 will mean an exposure
+ * compensation of -1</p>
+ */
+ public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
+ new Key<Integer>("android.control.aeExposureCompensation", int.class);
+
+ /**
+ * <p>Whether AE is currently locked to its latest
+ * calculated values.</p>
+ * <p>Note that even when AE is locked, the flash may be
+ * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
+ * ON_AUTO_FLASH_REDEYE.</p>
+ * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
+ * when AE is already locked, the camera device will not change the exposure time
+ * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
+ * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
+ * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
+ * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+ * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+ * @see CaptureResult#CONTROL_AE_STATE
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+ * @see CaptureRequest#SENSOR_SENSITIVITY
+ */
+ public static final Key<Boolean> CONTROL_AE_LOCK =
+ new Key<Boolean>("android.control.aeLock", boolean.class);
+
+ /**
* <p>The desired mode for the camera device's
* auto-exposure routine.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is
@@ -237,6 +365,35 @@ public final class CaptureResult extends CameraMetadata {
new Key<int[]>("android.control.aeRegions", int[].class);
/**
+ * <p>Range over which fps can be adjusted to
+ * maintain exposure</p>
+ * <p>Only constrains AE algorithm, not manual control
+ * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+ *
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+ */
+ public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
+ new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
+
+ /**
+ * <p>Whether the camera device will trigger a precapture
+ * metering sequence when it processes this request.</p>
+ * <p>This entry is normally set to IDLE, or is not
+ * included at all in the request settings. When included and
+ * set to START, the camera device will trigger the autoexposure
+ * precapture metering sequence.</p>
+ * <p>The effect of AE precapture trigger depends on the current
+ * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
+ * state transition details.</p>
+ *
+ * @see CaptureResult#CONTROL_AE_STATE
+ * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
+ * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+ */
+ public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
+ new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
+
+ /**
* <p>Current state of AE algorithm</p>
* <p>Switching between or enabling AE modes ({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}) always
* resets the AE state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -481,6 +638,24 @@ public final class CaptureResult extends CameraMetadata {
new Key<int[]>("android.control.afRegions", int[].class);
/**
+ * <p>Whether the camera device will trigger autofocus for this request.</p>
+ * <p>This entry is normally set to IDLE, or is not
+ * included at all in the request settings.</p>
+ * <p>When included and set to START, the camera device will trigger the
+ * autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
+ * <p>When set to CANCEL, the camera device will cancel any active trigger,
+ * and return to its initial AF state.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+ *
+ * @see CaptureResult#CONTROL_AF_STATE
+ * @see #CONTROL_AF_TRIGGER_IDLE
+ * @see #CONTROL_AF_TRIGGER_START
+ * @see #CONTROL_AF_TRIGGER_CANCEL
+ */
+ public static final Key<Integer> CONTROL_AF_TRIGGER =
+ new Key<Integer>("android.control.afTrigger", int.class);
+
+ /**
* <p>Current state of AF algorithm.</p>
* <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always
* resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -889,6 +1064,16 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.afTriggerId", int.class);
/**
+ * <p>Whether AWB is currently locked to its
+ * latest calculated values.</p>
+ * <p>Note that AWB lock is only meaningful for AUTO
+ * mode; in other modes, AWB is already fixed to a specific
+ * setting.</p>
+ */
+ public static final Key<Boolean> CONTROL_AWB_LOCK =
+ new Key<Boolean>("android.control.awbLock", boolean.class);
+
+ /**
* <p>Whether AWB is currently setting the color
* transform fields, and what its illumination target
* is.</p>
@@ -948,6 +1133,30 @@ public final class CaptureResult extends CameraMetadata {
new Key<int[]>("android.control.awbRegions", int[].class);
/**
+ * <p>Information to the camera device 3A (auto-exposure,
+ * auto-focus, auto-white balance) routines about the purpose
+ * of this capture, to help the camera device to decide optimal 3A
+ * strategy.</p>
+ * <p>This control (except for MANUAL) is only effective if
+ * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
+ * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains MANUAL_SENSOR.</p>
+ *
+ * @see CaptureRequest#CONTROL_MODE
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see #CONTROL_CAPTURE_INTENT_CUSTOM
+ * @see #CONTROL_CAPTURE_INTENT_PREVIEW
+ * @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE
+ * @see #CONTROL_CAPTURE_INTENT_VIDEO_RECORD
+ * @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
+ * @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
+ * @see #CONTROL_CAPTURE_INTENT_MANUAL
+ */
+ public static final Key<Integer> CONTROL_CAPTURE_INTENT =
+ new Key<Integer>("android.control.captureIntent", int.class);
+
+ /**
* <p>Current state of AWB algorithm</p>
* <p>Switching between or enabling AWB modes ({@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}) always
* resets the AWB state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -1078,6 +1287,31 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.awbState", int.class);
/**
+ * <p>A special color effect to apply.</p>
+ * <p>When this mode is set, a color effect will be applied
+ * to images produced by the camera device. The interpretation
+ * and implementation of these color effects is left to the
+ * implementor of the camera device, and should not be
+ * depended on to be consistent (or present) across all
+ * devices.</p>
+ * <p>A color effect will only be applied if
+ * {@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF.</p>
+ *
+ * @see CaptureRequest#CONTROL_MODE
+ * @see #CONTROL_EFFECT_MODE_OFF
+ * @see #CONTROL_EFFECT_MODE_MONO
+ * @see #CONTROL_EFFECT_MODE_NEGATIVE
+ * @see #CONTROL_EFFECT_MODE_SOLARIZE
+ * @see #CONTROL_EFFECT_MODE_SEPIA
+ * @see #CONTROL_EFFECT_MODE_POSTERIZE
+ * @see #CONTROL_EFFECT_MODE_WHITEBOARD
+ * @see #CONTROL_EFFECT_MODE_BLACKBOARD
+ * @see #CONTROL_EFFECT_MODE_AQUA
+ */
+ public static final Key<Integer> CONTROL_EFFECT_MODE =
+ new Key<Integer>("android.control.effectMode", int.class);
+
+ /**
* <p>Overall mode of 3A control
* routines.</p>
* <p>High-level 3A control. When set to OFF, all 3A control
@@ -1106,6 +1340,57 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.mode", int.class);
/**
+ * <p>A camera mode optimized for conditions typical in a particular
+ * capture setting.</p>
+ * <p>This is the mode that that is active when
+ * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
+ * these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+ * <p>The interpretation and implementation of these scene modes is left
+ * to the implementor of the camera device. Their behavior will not be
+ * consistent across all devices, and any given device may only implement
+ * a subset of these modes.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AWB_MODE
+ * @see CaptureRequest#CONTROL_MODE
+ * @see #CONTROL_SCENE_MODE_DISABLED
+ * @see #CONTROL_SCENE_MODE_FACE_PRIORITY
+ * @see #CONTROL_SCENE_MODE_ACTION
+ * @see #CONTROL_SCENE_MODE_PORTRAIT
+ * @see #CONTROL_SCENE_MODE_LANDSCAPE
+ * @see #CONTROL_SCENE_MODE_NIGHT
+ * @see #CONTROL_SCENE_MODE_NIGHT_PORTRAIT
+ * @see #CONTROL_SCENE_MODE_THEATRE
+ * @see #CONTROL_SCENE_MODE_BEACH
+ * @see #CONTROL_SCENE_MODE_SNOW
+ * @see #CONTROL_SCENE_MODE_SUNSET
+ * @see #CONTROL_SCENE_MODE_STEADYPHOTO
+ * @see #CONTROL_SCENE_MODE_FIREWORKS
+ * @see #CONTROL_SCENE_MODE_SPORTS
+ * @see #CONTROL_SCENE_MODE_PARTY
+ * @see #CONTROL_SCENE_MODE_CANDLELIGHT
+ * @see #CONTROL_SCENE_MODE_BARCODE
+ */
+ public static final Key<Integer> CONTROL_SCENE_MODE =
+ new Key<Integer>("android.control.sceneMode", int.class);
+
+ /**
+ * <p>Whether video stabilization is
+ * active</p>
+ * <p>If enabled, video stabilization can modify the
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
+ * stabilized</p>
+ *
+ * @see CaptureRequest#SCALER_CROP_REGION
+ * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
+ * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
+ */
+ public static final Key<Integer> CONTROL_VIDEO_STABILIZATION_MODE =
+ new Key<Integer>("android.control.videoStabilizationMode", int.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge/sharpness/detail enhancement. OFF means no
@@ -1688,6 +1973,22 @@ public final class CaptureResult extends CameraMetadata {
new Key<Float>("android.sensor.greenSplit", float.class);
/**
+ * <p>A pixel <code>[R, G_even, G_odd, B]</code> that supplies the test pattern
+ * when {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode} is SOLID_COLOR.</p>
+ * <p>Each color channel is treated as an unsigned 32-bit integer.
+ * The camera device then uses the most significant X bits
+ * that correspond to how many bits are in its Bayer raw sensor
+ * output.</p>
+ * <p>For example, a sensor with RAW10 Bayer output would use the
+ * 10 most significant bits from each color channel.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
+ */
+ public static final Key<int[]> SENSOR_TEST_PATTERN_DATA =
+ new Key<int[]>("android.sensor.testPatternData", int[].class);
+
+ /**
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
@@ -1936,6 +2237,20 @@ public final class CaptureResult extends CameraMetadata {
new Key<int[]>("android.statistics.hotPixelMap", int[].class);
/**
+ * <p>Whether the camera device will output the lens
+ * shading map in output result metadata.</p>
+ * <p>When set to ON,
+ * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in
+ * the output result metadata.</p>
+ *
+ * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+ * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
+ * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
+ */
+ public static final Key<Integer> STATISTICS_LENS_SHADING_MAP_MODE =
+ new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
+
+ /**
* <p>Tonemapping / contrast / gamma curve for the blue
* channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
* CONTRAST_CURVE.</p>
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1b2b798..84639eb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -91,7 +91,6 @@ public class UserManager {
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
-
public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
/**
@@ -145,6 +144,96 @@ public class UserManager {
*/
public static final String DISALLOW_REMOVE_USER = "no_remove_user";
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from enabling or
+ * accessing debugging features. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring VPN.
+ * The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring Tethering
+ * & portable hotspots. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from factory resetting
+ * from Settings.
+ * The default value is <code>false</code>.
+ * <p>
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from adding new users and
+ * profiles. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_ADD_USER = "no_add_user";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from disabling application
+ * verification. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring cell
+ * broadcasts. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring mobile
+ * networks. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring
+ * applications in Settings. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_APPS = "no_config_apps";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0eb994d..d5a3bcb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3480,6 +3480,12 @@ public final class Settings {
"lock_screen_appwidget_ids";
/**
+ * List of enrolled fingerprint identifiers (comma-delimited).
+ * @hide
+ */
+ public static final String USER_FINGERPRINT_IDS = "user_fingerprint_ids";
+
+ /**
* Id of the appwidget shown on the lock screen when appwidgets are disabled.
* @hide
*/
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
new file mode 100644
index 0000000..0d14c59
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -0,0 +1,200 @@
+/**
+ * Copyright (C) 2014 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.service.fingerprint;
+
+import android.app.ActivityManagerNative;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * A class that coordinates access to the fingerprint hardware.
+ */
+
+public class FingerprintManager {
+ private static final String TAG = "FingerprintManager";
+ protected static final boolean DEBUG = true;
+ private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
+ private static final String FINGERPRINT_SERVICE_CLASS =
+ "com.android.service.fingerprint.FingerprintService";
+ private static final int MSG_ENROLL_RESULT = 100;
+ private static final int MSG_SCANNED = 101;
+ private static final int MSG_ERROR = 102;
+ private static final int MSG_REMOVED = 103;
+
+ public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
+ public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
+
+ // Progress messages.
+ public static final int FINGERPRINT_SCANNED = 1;
+ public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+ public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
+
+ // Error messages. Must agree with fingerprint HAL definitions.
+ public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
+ public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+ public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
+ public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+
+ private IFingerprintService mService;
+ private FingerprintManagerReceiver mClientReceiver;
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ if (mClientReceiver != null) {
+ switch(msg.what) {
+ case MSG_ENROLL_RESULT:
+ mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
+ break;
+ case MSG_SCANNED:
+ mClientReceiver.onScanned(msg.arg1, msg.arg2);
+ break;
+ case MSG_ERROR:
+ mClientReceiver.onError(msg.arg1);
+ break;
+ case MSG_REMOVED:
+ mClientReceiver.onRemoved(msg.arg1);
+ }
+ }
+ }
+ };
+
+ public FingerprintManager(Context context) {
+ // Connect to service...
+ Intent intent = new Intent();
+ intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
+ if (!context.bindServiceAsUser(intent, mFingerprintConnection,
+ Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
+ if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+ }
+ }
+
+ private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
+ mService = IFingerprintService.Stub.asInterface(service);
+ try {
+ mService.startListening(mServiceReceiver, getCurrentUserId());
+ } catch (RemoteException e) {
+ if (DEBUG) Log.v(TAG, "Failed to set callback", e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
+ mService = null;
+ }
+ };
+
+ private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+ public void onEnrollResult(int fingerprintId, int remaining) {
+ mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
+ }
+
+ public void onScanned(int fingerprintId, int confidence) {
+ mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
+ .sendToTarget();;
+ }
+
+ public void onError(int error) {
+ mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
+ }
+
+ public void onRemoved(int fingerprintId) {
+ mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
+ }
+ };
+
+ /**
+ * Start the enrollment process. Timeout dictates how long to wait for the user to
+ * enroll a fingerprint.
+ *
+ * @param timeout
+ */
+ public void enroll(long timeout) {
+ if (mServiceReceiver == null) {
+ throw new IllegalStateException("enroll: Call registerCallback() first");
+ }
+ if (mService != null) try {
+ mService.enroll(timeout, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception while enrolling: ", e);
+ }
+ }
+
+ /**
+ * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning
+ * which is to delete all fingerprint data for the current user. Use with caution.
+ * @param fingerprintId
+ */
+ public void remove(int fingerprintId) {
+ if (mService != null) try {
+ mService.remove(fingerprintId, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+ }
+ }
+
+ /**
+ * Starts listening for fingerprint events. When a finger is scanned or recognized, the
+ * client will be notified via the callback.
+ */
+ public void startListening(FingerprintManagerReceiver receiver) {
+ mClientReceiver = receiver;
+ if (mService != null) {
+ try {
+ mService.startListening(mServiceReceiver, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in startListening(): ", e);
+ }
+ }
+ }
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get current user id\n");
+ return UserHandle.USER_NULL;
+ }
+ }
+
+ /**
+ * Stops the client from listening to fingerprint events.
+ */
+ public void stopListening() {
+ mClientReceiver = null;
+ if (mService != null) {
+ try {
+ mService.stopListening(getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in stopListening(): ", e);
+ }
+ } else {
+ Log.w(TAG, "stopListening(): Service not connected!");
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
new file mode 100644
index 0000000..34f1655
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -0,0 +1,59 @@
+package android.service.fingerprint;
+/**
+ * Copyright (C) 2014 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.
+ */
+
+public class FingerprintManagerReceiver {
+ /**
+ * Fingerprint enrollment progress update. Enrollment is considered complete if
+ * remaining hits 0 without {@link #onError(int)} being called.
+ *
+ * @param fingerprintId the fingerprint we're currently enrolling
+ * @param remaining the number of samples required to complete enrollment. It's up to
+ * the hardware to define what each step in enrollment means. Some hardware
+ * requires multiple samples of the same part of the finger. Others require sampling of
+ * different parts of the finger. The enrollment flow can use remaining to
+ * mean "step x" of the process or "just need another sample."
+ */
+ public void onEnrollResult(int fingerprintId, int remaining) { }
+
+ /**
+ * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+ *
+ * @param fingerprintId is the finger the hardware has detected.
+ * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
+ * special meaning - the finger wasn't recognized.
+ */
+ public void onScanned(int fingerprintId, int confidence) { }
+
+ /**
+ * An error was detected during scan or enrollment. One of
+ * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
+ * {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
+ * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
+ * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
+ *
+ * @param error one of the above error codes
+ */
+ public void onError(int error) { }
+
+ /**
+ * The given fingerprint template was successfully removed by the driver.
+ * See {@link FingerprintManager#remove(int)}
+ *
+ * @param fingerprintId id of template to remove.
+ */
+ public void onRemoved(int fingerprintId) { }
+} \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..c7fa7cd
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintService.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright (C) 2014 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.service.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends Service {
+ private final String TAG = FingerprintService.class.getSimpleName() +
+ "[" + getClass().getSimpleName() + "]";
+ private static final boolean DEBUG = true;
+ HashMap<IFingerprintServiceReceiver, ClientData> mClients =
+ new HashMap<IFingerprintServiceReceiver, ClientData>();
+
+ private static final int MSG_NOTIFY = 10;
+
+ Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_NOTIFY:
+ handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown message:" + msg.what);
+ }
+ }
+ };
+
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_LISTENING = 1;
+ private static final int STATE_ENROLLING = 2;
+ private static final int STATE_DELETING = 3;
+ private static final long MS_PER_SEC = 1000;
+
+ private static final class ClientData {
+ public IFingerprintServiceReceiver receiver;
+ int state;
+ int userId;
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ return new FingerprintServiceWrapper();
+ }
+
+ // JNI methods to communicate from FingerprintManagerService to HAL
+ native int nativeEnroll(int timeout);
+ native int nativeRemove(int fingerprintId);
+
+ // JNI methods for communicating from HAL to clients
+ void notify(int msg, int arg1, int arg2) {
+ mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ }
+
+ void handleNotify(int msg, int arg1, int arg2) {
+ for (int i = 0; i < mClients.size(); i++) {
+ ClientData clientData = mClients.get(i);
+ switch (msg) {
+ case FingerprintManager.FINGERPRINT_ERROR: {
+ if (clientData.state != STATE_IDLE) {
+ // FINGERPRINT_ERROR_HW_UNAVAILABLE
+ // FINGERPRINT_ERROR_BAD_CAPTURE
+ // FINGERPRINT_ERROR_TIMEOUT
+ // FINGERPRINT_ERROR_NO_SPACE
+ final int error = arg1;
+ clientData.state = STATE_IDLE;
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onError(error);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ }
+ break;
+ case FingerprintManager.FINGERPRINT_SCANNED: {
+ final int fingerId = arg1;
+ final int confidence = arg2;
+ if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
+ try {
+ clientData.receiver.onScanned(fingerId, confidence);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+ if (clientData.state == STATE_ENROLLING) {
+ final int fingerId = arg1;
+ final int remaining = arg2;
+ if (remaining == 0) {
+ FingerprintUtils.addFingerprintIdForUser(fingerId,
+ getContentResolver(), clientData.userId);
+ clientData.state = STATE_IDLE; // Nothing left to do
+ }
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onEnrollResult(fingerId, remaining);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+ int fingerId = arg1;
+ if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+ if (clientData.state == STATE_DELETING) {
+ FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
+ clientData.userId);
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onRemoved(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_ENROLLING;
+ return nativeEnroll((int) (timeout / MS_PER_SEC));
+ }
+ return -1;
+ }
+
+ int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_DELETING;
+ // The fingerprint id will be removed when we get confirmation from the HAL
+ return nativeRemove(fingerId);
+ }
+ return -1;
+ }
+
+ void startListening(IFingerprintServiceReceiver receiver, int userId) {
+ ClientData clientData = new ClientData();
+ clientData.state = STATE_LISTENING;
+ clientData.receiver = receiver;
+ clientData.userId = userId;
+ mClients.put(receiver, clientData);
+ }
+
+ void stopListening(IFingerprintServiceReceiver receiver, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ clientData.state = STATE_IDLE;
+ clientData.userId = -1;
+ clientData.receiver = null;
+ }
+ mClients.remove(receiver);
+ }
+
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ IFingerprintServiceReceiver mReceiver;
+ public int enroll(long timeout, int userId) {
+ return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
+ : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
+ }
+
+ public int remove(int fingerprintId, int userId) {
+ return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
+ }
+
+ public void startListening(IFingerprintServiceReceiver receiver, int userId) {
+ mReceiver = receiver;
+ FingerprintService.this.startListening(receiver, userId);
+ }
+
+ public void stopListening(int userId) {
+ FingerprintService.this.stopListening(mReceiver, userId);
+ }
+ }
+}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
new file mode 100644
index 0000000..81a2aac
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2014 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.service.fingerprint;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.Arrays;
+
+class FingerprintUtils {
+ private static final boolean DEBUG = true;
+ private static final String TAG = "FingerprintUtils";
+
+ public static int[] getFingerprintIdsForUser(ContentResolver res, int userId) {
+ String fingerIdsRaw = Settings.Secure.getStringForUser(res,
+ Settings.Secure.USER_FINGERPRINT_IDS, userId);
+
+ String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+ int result[] = new int[fingerStringIds.length];
+ for (int i = 0; i < result.length; i++) {
+ try {
+ result[i] = Integer.decode(fingerStringIds[i]);
+ } catch (NumberFormatException e) {
+ if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ }
+ }
+ return result;
+ }
+
+ public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+ int[] fingerIds = getFingerprintIdsForUser(res, userId);
+
+ // FingerId 0 has special meaning.
+ if (fingerId == 0) return;
+
+ // Don't allow dups
+ for (int i = 0; i < fingerIds.length; i++) {
+ if (fingerIds[i] == fingerId) return;
+ }
+ int[] newList = Arrays.copyOf(fingerIds, fingerIds.length + 1);
+ newList[fingerIds.length] = fingerId;
+ Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+ Arrays.toString(newList), userId);
+ }
+
+ public static boolean removeFingerprintIdForUser(int fingerId, ContentResolver res, int userId)
+ {
+ // FingerId 0 has special meaning. The HAL layer is supposed to remove each finger one
+ // at a time and invoke notify() for each fingerId. If we get called with 0 here, it means
+ // something bad has happened.
+ if (fingerId == 0) throw new IllegalStateException("Bad fingerId");
+
+ int[] fingerIds = getFingerprintIdsForUser(res, userId);
+ int[] resultIds = Arrays.copyOf(fingerIds, fingerIds.length);
+ int resultCount = 0;
+ for (int i = 0; i < fingerIds.length; i++) {
+ if (fingerId != fingerIds[i]) {
+ resultIds[resultCount++] = fingerIds[i];
+ }
+ }
+ if (resultCount > 0) {
+ Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+ Arrays.toString(Arrays.copyOf(resultIds, resultCount)), userId);
+ return true;
+ }
+ return false;
+ }
+
+};
+
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
new file mode 100644
index 0000000..e92c20c
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 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.service.fingerprint;
+
+import android.os.Bundle;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+/**
+ * Communication channel from client to the fingerprint service.
+ * @hide
+ */
+interface IFingerprintService {
+ // Returns 0 if successfully started, -1 otherwise
+ int enroll(long timeout, int userId);
+
+ // Returns 0 if fingerprintId's template can be removed, -1 otherwise
+ int remove(int fingerprintId, int userId);
+
+ // Start listening for fingerprint events. This has the side effect of starting
+ // the hardware if not already started.
+ oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+
+ // Stops listening for fingerprints
+ oneway void stopListening(int userId);
+}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
new file mode 100644
index 0000000..4826b59
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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.service.fingerprint;
+
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the FingerprintService back to FingerprintManager.
+ * @hide
+ */
+oneway interface IFingerprintServiceReceiver {
+ void onEnrollResult(int fingerprintId, int remaining);
+ void onScanned(int fingerprintId, int confidence);
+ void onError(int error);
+ void onRemoved(int fingerprintId);
+}
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index 186cb49..92bb0ac 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -83,7 +83,7 @@ class BlockingAudioTrack {
mVolume = volume;
mPan = pan;
- mBytesPerFrame = getBytesPerFrame(mAudioFormat) * mChannelCount;
+ mBytesPerFrame = AudioFormat.getBytesPerSample(mAudioFormat) * mChannelCount;
mIsShortUtterance = false;
mAudioBufferSize = 0;
mBytesWritten = 0;
@@ -229,17 +229,6 @@ class BlockingAudioTrack {
return audioTrack;
}
- private static int getBytesPerFrame(int audioFormat) {
- if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) {
- return 1;
- } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
- return 2;
- }
-
- return -1;
- }
-
-
private void blockUntilDone(AudioTrack audioTrack) {
if (mBytesWritten <= 0) {
return;
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 717aeb6..d84f7f0 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -278,8 +278,7 @@ class FileSynthesisCallback extends AbstractSynthesisCallback {
private ByteBuffer makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
int dataLength) {
- // TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
- int sampleSizeInBytes = (audioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ int sampleSizeInBytes = AudioFormat.getBytesPerSample(audioFormat);
int byteRate = sampleRateInHz * sampleSizeInBytes * channelCount;
short blockAlign = (short) (sampleSizeInBytes * channelCount);
short bitsPerSample = (short) (sampleSizeInBytes * 8);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2d55a01..c15ce44 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -74,8 +74,10 @@ public class SurfaceControl {
IBinder displayToken, int orientation,
int l, int t, int r, int b,
int L, int T, int R, int B);
- private static native boolean nativeGetDisplayInfo(
- IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo);
+ private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs(
+ IBinder displayToken);
+ private static native int nativeGetActiveConfig(IBinder displayToken);
+ private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
private static native void nativeBlankDisplay(IBinder displayToken);
private static native void nativeUnblankDisplay(IBinder displayToken);
@@ -499,14 +501,25 @@ public class SurfaceControl {
nativeBlankDisplay(displayToken);
}
- public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
+ public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- if (outInfo == null) {
- throw new IllegalArgumentException("outInfo must not be null");
+ return nativeGetDisplayConfigs(displayToken);
+ }
+
+ public static int getActiveConfig(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ return nativeGetActiveConfig(displayToken);
+ }
+
+ public static boolean setActiveConfig(IBinder displayToken, int id) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDisplayInfo(displayToken, outInfo);
+ return nativeSetActiveConfig(displayToken, id);
}
public static void setDisplayProjection(IBinder displayToken,
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 3cfe5e9..1765c43 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -23,7 +23,6 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
-import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
@@ -119,8 +118,6 @@ public class TextureView extends View {
private boolean mUpdateLayer;
private boolean mUpdateSurface;
- private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
-
private Canvas mCanvas;
private int mSaveCount;
@@ -370,21 +367,7 @@ public class TextureView extends View {
mSurface.setDefaultBufferSize(getWidth(), getHeight());
nCreateNativeWindow(mSurface);
- mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- // Per SurfaceTexture's documentation, the callback may be invoked
- // from an arbitrary thread
- updateLayer();
-
- if (Looper.myLooper() == Looper.getMainLooper()) {
- invalidate();
- } else {
- postInvalidate();
- }
- }
- };
- mSurface.setOnFrameAvailableListener(mUpdateListener);
+ mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
if (mListener != null && !mUpdateSurface) {
mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
@@ -422,7 +405,7 @@ public class TextureView extends View {
// To cancel updates, the easiest thing to do is simply to remove the
// updates listener
if (visibility == VISIBLE) {
- mSurface.setOnFrameAvailableListener(mUpdateListener);
+ mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
updateLayerAndInvalidate();
} else {
mSurface.setOnFrameAvailableListener(null);
@@ -767,6 +750,15 @@ public class TextureView extends View {
mListener = listener;
}
+ private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
+ new SurfaceTexture.OnFrameAvailableListener() {
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ updateLayer();
+ invalidate();
+ }
+ };
+
/**
* This listener can be used to be notified when the surface texture
* associated with this texture view is available.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3998c04..d8fcfc5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6147,12 +6147,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// call into it as a fallback in case we're in a class that overrides it
// and has logic to perform.
if (fitSystemWindows(insets.getSystemWindowInsets())) {
- return insets.cloneWithSystemWindowInsetsConsumed();
+ return insets.consumeSystemWindowInsets();
}
} else {
// We were called from within a direct call to fitSystemWindows.
if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
- return insets.cloneWithSystemWindowInsetsConsumed();
+ return insets.consumeSystemWindowInsets();
}
}
return insets;
@@ -9766,6 +9766,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9809,6 +9810,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9852,6 +9854,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9887,6 +9890,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9922,6 +9926,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10083,6 +10088,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -10513,6 +10520,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10661,6 +10669,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
mRenderNode.setOutline(null);
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10815,6 +10824,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
invalidateParentIfNeeded();
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10861,6 +10871,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
invalidateParentIfNeeded();
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 43bc0b6..4309366 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4638,6 +4638,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (invalidate) {
invalidateViewProperty(false, false);
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
/**
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 2160efe..294f472 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -29,7 +29,7 @@ import android.graphics.Rect;
* @see View.OnApplyWindowInsetsListener
* @see View#onApplyWindowInsets(WindowInsets)
*/
-public class WindowInsets {
+public final class WindowInsets {
private Rect mSystemWindowInsets;
private Rect mWindowDecorInsets;
private Rect mTempRect;
@@ -151,6 +151,7 @@ public class WindowInsets {
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The left window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetLeft() {
return mWindowDecorInsets.left;
@@ -164,6 +165,7 @@ public class WindowInsets {
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The top window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetTop() {
return mWindowDecorInsets.top;
@@ -177,6 +179,7 @@ public class WindowInsets {
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The right window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetRight() {
return mWindowDecorInsets.right;
@@ -190,6 +193,7 @@ public class WindowInsets {
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The bottom window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetBottom() {
return mWindowDecorInsets.bottom;
@@ -217,6 +221,7 @@ public class WindowInsets {
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return true if any of the window decor inset values are nonzero
+ * @hide pending API
*/
public boolean hasWindowDecorInsets() {
return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
@@ -246,13 +251,28 @@ public class WindowInsets {
return mIsRound;
}
- public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+ /**
+ * Returns a copy of this WindowInsets with the system window insets fully consumed.
+ *
+ * @return A modified copy of this WindowInsets
+ */
+ public WindowInsets consumeSystemWindowInsets() {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
return result;
}
- public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+ /**
+ * Returns a copy of this WindowInsets with selected system window insets fully consumed.
+ *
+ * @param left true to consume the left system window inset
+ * @param top true to consume the top system window inset
+ * @param right true to consume the right system window inset
+ * @param bottom true to consume the bottom system window inset
+ * @return A modified copy of this WindowInsets
+ * @hide pending API
+ */
+ public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
@@ -265,19 +285,36 @@ public class WindowInsets {
return this;
}
- public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+ /**
+ * Returns a copy of this WindowInsets with selected system window insets replaced
+ * with new values.
+ *
+ * @param left New left inset in pixels
+ * @param top New top inset in pixels
+ * @param right New right inset in pixels
+ * @param bottom New bottom inset in pixels
+ * @return A modified copy of this WindowInsets
+ */
+ public WindowInsets replaceSystemWindowInsets(int left, int top,
+ int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(left, top, right, bottom);
return result;
}
- public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+ /**
+ * @hide
+ */
+ public WindowInsets consumeWindowDecorInsets() {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets.set(0, 0, 0, 0);
return result;
}
- public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+ /**
+ * @hide
+ */
+ public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
@@ -290,7 +327,10 @@ public class WindowInsets {
return this;
}
- public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+ /**
+ * @hide
+ */
+ public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets = new Rect(left, top, right, bottom);
return result;
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 2f8850b..3e33498 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -19,14 +19,11 @@ package android.webkit;
import android.net.Uri;
/**
- * This class wraps a permission request, and is used to request permission for
- * the web content to access the resources.
+ * This interface defines a permission request and is used when web content
+ * requests access to protected resources.
*
- * Either {@link #grant(long) grant()} or {@link #deny()} must be called to response the
- * request, otherwise, {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will
- * not be invoked again if there is other permission request in this WebView.
- *
- * @hide
+ * Either {@link #grant(long) grant()} or {@link #deny()} must be called in UI
+ * thread to respond to the request.
*/
public interface PermissionRequest {
/**
@@ -62,8 +59,6 @@ public interface PermissionRequest {
* must be equals or a subset of granted resources.
* This parameter is designed to avoid granting permission by accident
* especially when new resources are requested by web content.
- * Calling grant(getResources()) has security issue, the new permission
- * will be granted without being noticed.
*/
public void grant(long resources);
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 60cba86..d630a9a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -304,7 +304,6 @@ public class WebChromeClient {
* If this method isn't overridden, the permission is denied.
*
* @param request the PermissionRequest from current web content.
- * @hide
*/
public void onPermissionRequest(PermissionRequest request) {
request.deny();
@@ -314,8 +313,7 @@ public class WebChromeClient {
* Notify the host application that the given permission request
* has been canceled. Any related UI should therefore be hidden.
*
- * @param request the PermissionRequest need be canceled.
- * @hide
+ * @param request the PermissionRequest that needs be canceled.
*/
public void onPermissionRequestCanceled(PermissionRequest request) {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4b2b52c..91ca7b4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1682,13 +1682,15 @@ public class WebView extends AbsoluteLayout
/**
* Preauthorize the given origin to access resources.
- * This authorization only valid for this WebView instance life cycle and
+ * The authorization only valid for this WebView instance's life cycle and
* will not retained.
*
+ * In the case that an origin has had resources preauthorized, calls to
+ * {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will not be
+ * made for those resources from that origin.
+ *
* @param origin the origin authorized to access resources
* @param resources the resource authorized to be accessed by origin.
- *
- * @hide
*/
public void preauthorizePermission(Uri origin, long resources) {
checkThread();
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d1d1a52..75feb5d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -33,7 +33,8 @@ oneway interface IStatusBar
void animateCollapsePanels();
void setSystemUiVisibility(int vis, int mask);
void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
void setHardKeyboardStatus(boolean available, boolean enabled);
void toggleRecentApps();
void preloadRecentApps();
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index caa6b98..cf334c3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -31,7 +31,8 @@ interface IStatusBarService
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
void expandSettingsPanel();
void setCurrentUser(int newUserId);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 667bf6c..8bd2e4f 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -141,6 +141,7 @@ LOCAL_SRC_FILES:= \
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
+ android_server_FingerprintManager.cpp \
android_server_NetworkManagementSocketTagger.cpp \
android_server_Watchdog.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index b78b131..621534e 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -221,7 +221,7 @@ static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
}
fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;)V");
+ "(Ljava/lang/ref/WeakReference;)V");
if (fields.postEvent == NULL) {
ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
}
@@ -338,7 +338,7 @@ static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
static JNINativeMethod gSurfaceTextureMethods[] = {
{"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
- {"nativeInit", "(IZLjava/lang/Object;)V", (void*)SurfaceTexture_init },
+ {"nativeInit", "(IZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
{"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
{"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
{"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index f4bab26..fedb1b2 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -22,6 +22,7 @@
// keep these values in sync with AudioFormat.java
#define ENCODING_PCM_16BIT 2
#define ENCODING_PCM_8BIT 3
+#define ENCODING_PCM_FLOAT 4
static inline audio_format_t audioFormatToNative(int audioFormat)
{
@@ -30,6 +31,8 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_PCM_16_BIT;
case ENCODING_PCM_8BIT:
return AUDIO_FORMAT_PCM_8_BIT;
+ case ENCODING_PCM_FLOAT:
+ return AUDIO_FORMAT_PCM_FLOAT;
default:
return AUDIO_FORMAT_INVALID;
}
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
new file mode 100644
index 0000000..f8a1fd9
--- /dev/null
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 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_TAG "Fingerprint-JNI"
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static struct {
+ jclass clazz;
+ jmethodID notify;
+} gFingerprintManagerClassInfo;
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+ return -1; // TODO
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+ return -1; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod g_methods[] = {
+ { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeRemove", "(I)I", (void*)nativeRemove },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className); \
+ var = jclass(env->NewGlobalRef(var));
+
+#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method" methodName);
+
+#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method" methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_FingerprintManager(JNIEnv* env) {
+ FIND_CLASS(gFingerprintManagerClassInfo.clazz,
+ "android/service/fingerprint/FingerprintManager");
+ GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
+ "notify", "(III)V");
+ return AndroidRuntime::registerNativeMethods(
+ env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c293c7a..5a935a9 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -50,6 +50,8 @@ static const char* const OutOfResourcesException =
"android/view/Surface$OutOfResourcesException";
static struct {
+ jclass clazz;
+ jmethodID ctor;
jfieldID width;
jfieldID height;
jfieldID refreshRate;
@@ -346,24 +348,49 @@ static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
}
-static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
- jobject tokenObj, jobject infoObj) {
+static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
+ jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return JNI_FALSE;
+ if (token == NULL) return NULL;
- DisplayInfo info;
- if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
- return JNI_FALSE;
+ Vector<DisplayInfo> configs;
+ if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
+ configs.size() == 0) {
+ return NULL;
}
- env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
- env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
- env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
- return JNI_TRUE;
+ jobjectArray configArray = env->NewObjectArray(configs.size(),
+ gPhysicalDisplayInfoClassInfo.clazz, NULL);
+
+ for (size_t c = 0; c < configs.size(); ++c) {
+ const DisplayInfo& info = configs[c];
+ jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
+ gPhysicalDisplayInfoClassInfo.ctor);
+ env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
+ env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
+ env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
+ env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
+ env->DeleteLocalRef(infoObj);
+ }
+
+ return configArray;
+}
+
+static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return -1;
+ return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
+}
+
+static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return JNI_FALSE;
+ status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
+ return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -576,8 +603,12 @@ static JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDisplayLayerStack },
{"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
(void*)nativeSetDisplayProjection },
- {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
- (void*)nativeGetDisplayInfo },
+ {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
+ (void*)nativeGetDisplayConfigs },
+ {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
+ (void*)nativeGetActiveConfig },
+ {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
+ (void*)nativeSetActiveConfig },
{"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
(void*)nativeBlankDisplay },
{"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
@@ -598,6 +629,9 @@ int register_android_view_SurfaceControl(JNIEnv* env)
sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
+ gPhysicalDisplayInfoClassInfo.clazz = static_cast<jclass>(env->NewGlobalRef(clazz));
+ gPhysicalDisplayInfoClassInfo.ctor = env->GetMethodID(gPhysicalDisplayInfoClassInfo.clazz,
+ "<init>", "()V");
gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cce4dbd..b1f256e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,6 +885,47 @@
be passed a persistable Bundle in their Intent.extras. -->
<attr name="persistable" format="boolean" />
+ <!-- Specify whether this activity should always be launched in doc-centric mode. For
+ values other than <code>none</code> the activity must be defined with
+ {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+ This attribute can be overridden by {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+
+ <p>If this attribute is not specified, <code>none</code> will be used.
+ Note that this launch behavior can be changed in some ways at runtime
+ through the {@link android.content.Intent} flags
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. -->
+ <attr name="documentLaunchMode">
+ <!-- The default mode, which will create a new task only when
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
+ Intent.FLAG_ACTIVITY_NEW_TASK} is set. -->
+ <enum name="none" value="0" />
+ <!-- All tasks will be searched for a matching Intent. If one is found
+ That task will cleared and restarted with the root activity receiving a call
+ to {@link android.app.Activity#onNewIntent Activity.onNewIntent}. If no
+ such task is found a new task will be created.
+ This is the equivalent of with {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+ without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ <enum name="intoExisting" value="1" />
+ <!-- A new task rooted at this activity will be created.
+ This is the equivalent of with {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+ paired with {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ <enum name="always" value="2" />
+ </attr>
+
+ <!-- Tasks launched by activities with this attribute will remain in the recent task
+ list until the last activity in the task is completed. When that happens the task
+ will be automatically removed from the recent task list.
+
+ This attribute is the equivalent of {@link
+ android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
+ <attr name="autoRemoveFromRecents" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1549,6 +1590,8 @@
<attr name="primaryUserOnly" format="boolean" />
<attr name="persistable" />
<attr name="allowEmbedded" />
+ <attr name="documentLaunchMode" />
+ <attr name="autoRemoveFromRecents" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e88a6ee..8874c30 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2169,6 +2169,8 @@
<public type="attr" name="excludeClass" />
<public type="attr" name="hideOnContentScroll" />
<public type="attr" name="actionOverflowMenuStyle" />
+ <public type="attr" name="documentLaunchMode" />
+ <public type="attr" name="autoRemoveFromRecents" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
new file mode 100644
index 0000000..0f3ea0e
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 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.bluetooth;
+
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for {@link BluetoothUuid}.
+ * <p>
+ * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothUuidTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothUuidTest extends TestCase {
+
+ @SmallTest
+ public void testUuidParser() {
+ byte[] uuid16 = new byte[] {
+ 0x0B, 0x11 };
+ assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"),
+ BluetoothUuid.parseUuidFrom(uuid16));
+
+ byte[] uuid32 = new byte[] {
+ 0x0B, 0x11, 0x33, (byte) 0xFE };
+ assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"),
+ BluetoothUuid.parseUuidFrom(uuid32));
+
+ byte[] uuid128 = new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF };
+ assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"),
+ BluetoothUuid.parseUuidFrom(uuid128));
+ }
+}
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index a0f7ce1..b4813a5 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -737,7 +737,7 @@ so you can populate fields of the contact details.
<pre>
public void editContact(Uri contactUri, String email) {
Intent intent = new Intent(Intent.ACTION_EDIT);
- intent.setDataAndType(contactUri, Contacts.CONTENT_TYPE);
+ intent.setData(contactUri);
intent.putExtra(Intents.Insert.EMAIL, email);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index d877502..3f8c45c 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -62,9 +62,8 @@ import android.view.Surface;
* #updateTexImage} should not be called directly from the callback.
*/
public class SurfaceTexture {
-
- private EventHandler mEventHandler;
- private OnFrameAvailableListener mOnFrameAvailableListener;
+ private final Looper mCreatorLooper;
+ private Handler mOnFrameAvailableHandler;
/**
* These fields are used by native code, do not access or modify.
@@ -83,7 +82,8 @@ public class SurfaceTexture {
/**
* Exception thrown when a SurfaceTexture couldn't be created or resized.
*
- * @deprecated No longer thrown. {@link Surface.OutOfResourcesException} is used instead.
+ * @deprecated No longer thrown. {@link android.view.Surface.OutOfResourcesException}
+ * is used instead.
*/
@SuppressWarnings("serial")
@Deprecated
@@ -100,10 +100,10 @@ public class SurfaceTexture {
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*
- * @throws OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName) {
- init(texName, false);
+ this(texName, false);
}
/**
@@ -121,20 +121,58 @@ public class SurfaceTexture {
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
* @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
*
- * @throws throws OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName, boolean singleBufferMode) {
- init(texName, singleBufferMode);
+ mCreatorLooper = Looper.myLooper();
+ nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
}
/**
* Register a callback to be invoked when a new image frame becomes available to the
- * SurfaceTexture. Note that this callback may be called on an arbitrary thread, so it is not
+ * SurfaceTexture.
+ * <p>
+ * This callback may be called on an arbitrary thread, so it is not
* safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
* thread invoking the callback.
+ * </p>
+ *
+ * @param listener The listener to set.
*/
- public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
- mOnFrameAvailableListener = l;
+ public void setOnFrameAvailableListener(OnFrameAvailableListener listener) {
+ setOnFrameAvailableListener(listener, null);
+ }
+
+ /**
+ * Register a callback to be invoked when a new image frame becomes available to the
+ * SurfaceTexture.
+ * <p>
+ * If no handler is specified, then this callback may be called on an arbitrary thread,
+ * so it is not safe to call {@link #updateTexImage} without first binding the OpenGL ES
+ * context to the thread invoking the callback.
+ * </p>
+ *
+ * @param listener The listener to set.
+ * @param handler The handler on which the listener should be invoked, or null
+ * to use an arbitrary thread.
+ */
+ public void setOnFrameAvailableListener(final OnFrameAvailableListener listener,
+ Handler handler) {
+ if (listener != null) {
+ // Although we claim the thread is arbitrary, earlier implementation would
+ // prefer to send the callback on the creating looper or the main looper
+ // so we preserve this behavior here.
+ Looper looper = handler != null ? handler.getLooper() :
+ mCreatorLooper != null ? mCreatorLooper : Looper.getMainLooper();
+ mOnFrameAvailableHandler = new Handler(looper, null, true /*async*/) {
+ @Override
+ public void handleMessage(Message msg) {
+ listener.onFrameAvailable(SurfaceTexture.this);
+ }
+ };
+ } else {
+ mOnFrameAvailableHandler = null;
+ }
}
/**
@@ -285,49 +323,22 @@ public class SurfaceTexture {
}
}
- private class EventHandler extends Handler {
- public EventHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mOnFrameAvailableListener != null) {
- mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
- }
- }
- }
-
/**
* This method is invoked from native code only.
*/
@SuppressWarnings({"UnusedDeclaration"})
- private static void postEventFromNative(Object selfRef) {
- WeakReference weakSelf = (WeakReference)selfRef;
- SurfaceTexture st = (SurfaceTexture)weakSelf.get();
- if (st == null) {
- return;
- }
-
- if (st.mEventHandler != null) {
- Message m = st.mEventHandler.obtainMessage();
- st.mEventHandler.sendMessage(m);
- }
- }
-
- private void init(int texName, boolean singleBufferMode) throws Surface.OutOfResourcesException {
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mEventHandler = new EventHandler(looper);
- } else {
- mEventHandler = null;
+ private static void postEventFromNative(WeakReference<SurfaceTexture> weakSelf) {
+ SurfaceTexture st = weakSelf.get();
+ if (st != null) {
+ Handler handler = st.mOnFrameAvailableHandler;
+ if (handler != null) {
+ handler.sendEmptyMessage(0);
+ }
}
- nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
}
- private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf)
+ private native void nativeInit(int texName, boolean singleBufferMode,
+ WeakReference<SurfaceTexture> weakSelf)
throws Surface.OutOfResourcesException;
private native void nativeFinalize();
private native void nativeGetTransformMatrix(float[] mtx);
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ad0d459..6b2a247 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -32,11 +32,13 @@ public class AudioFormat {
/** Default audio data format */
public static final int ENCODING_DEFAULT = 1;
- // These two values must be kept in sync with core/jni/android_media_AudioFormat.h
+ // These values must be kept in sync with core/jni/android_media_AudioFormat.h
/** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */
public static final int ENCODING_PCM_16BIT = 2;
/** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
public static final int ENCODING_PCM_8BIT = 3;
+ /** @hide Candidate for public API */
+ public static final int ENCODING_PCM_FLOAT = 4;
/** Invalid audio channel configuration */
/** @deprecated use CHANNEL_INVALID instead */
@@ -139,4 +141,19 @@ public class AudioFormat {
public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK;
// CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL
+ /** @hide */
+ public static int getBytesPerSample(int audioFormat)
+ {
+ switch (audioFormat) {
+ case ENCODING_PCM_8BIT:
+ return 1;
+ case ENCODING_PCM_16BIT:
+ case ENCODING_DEFAULT:
+ return 2;
+ case ENCODING_INVALID:
+ default:
+ throw new IllegalArgumentException("Bad audio format " + audioFormat);
+ }
+ }
+
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a4891f8..384e120 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -319,7 +319,7 @@ public class AudioRecord
// NB: this section is only valid with PCM data.
// To update when supporting compressed formats
int frameSizeInBytes = mChannelCount
- * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ * (AudioFormat.getBytesPerSample(mAudioFormat));
if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
throw new IllegalArgumentException("Invalid audio buffer size.");
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 17840f2..1899685 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -518,7 +518,7 @@ public class AudioTrack
// NB: this section is only valid with PCM data.
// To update when supporting compressed formats
int frameSizeInBytes = mChannelCount
- * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ * (AudioFormat.getBytesPerSample(mAudioFormat));
if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
throw new IllegalArgumentException("Invalid audio buffer size.");
}
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index bd91fc5..7735e78 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -169,9 +169,11 @@ public class JetPlayer
native_setup(new WeakReference<JetPlayer>(this),
JetPlayer.getMaxTracks(),
- // bytes to frame conversion: sample format is ENCODING_PCM_16BIT, 2 channels
+ // bytes to frame conversion:
// 1200 == minimum buffer size in frames on generation 1 hardware
- Math.max(1200, buffSizeInBytes / 4));
+ Math.max(1200, buffSizeInBytes /
+ (AudioFormat.getBytesPerSample(AudioFormat.ENCODING_PCM_16BIT) *
+ 2 /*channels*/)));
}
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 28de6ac..d763bd6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -227,6 +227,12 @@
<!-- The radius of the rounded corners on a task view. -->
<dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
+ <!-- The min translation in the Z index for the last task. -->
+ <dimen name="recents_task_view_z_min">3dp</dimen>
+
+ <!-- The translation in the Z index for each task above the last task. -->
+ <dimen name="recents_task_view_z_increment">5dp</dimen>
+
<!-- The amount of space a user has to scroll to dismiss any info panes. -->
<dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
new file mode 100644
index 0000000..e5168c4
--- /dev/null
+++ b/packages/SystemUI/res/values/ids.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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="id" name="translation_y_animator_tag"/>
+ <item type="id" name="translation_z_animator_tag"/>
+ <item type="id" name="alpha_animator_tag"/>
+ <item type="id" name="top_inset_animator_tag"/>
+ <item type="id" name="height_animator_tag"/>
+ <item type="id" name="translation_y_animator_end_value_tag"/>
+ <item type="id" name="translation_z_animator_end_value_tag"/>
+ <item type="id" name="alpha_animator_end_value_tag"/>
+ <item type="id" name="top_inset_animator_end_value_tag"/>
+ <item type="id" name="height_animator_end_value_tag"/>
+</resources>
+
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d38d828..6387a92 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -322,6 +322,7 @@ public class SwipeHelper implements Gefingerpoken {
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
updateAlphaFromOffset(animView, canAnimViewBeDismissed);
+ mCallback.onChildSnappedBack(animView);
}
});
anim.start();
@@ -407,5 +408,7 @@ public class SwipeHelper implements Gefingerpoken {
void onChildDismissed(View v);
void onDragCancelled(View v);
+
+ void onChildSnappedBack(View animView);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 35c824b..0759b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -217,6 +217,10 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
public void onDragCancelled(View v) {
}
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
final float x = ev.getX() + getScrollX();
final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 297fe0d..c2dde6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -225,6 +225,10 @@ public class RecentsVerticalScrollView extends ScrollView
public void onDragCancelled(View v) {
}
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
final float x = ev.getX() + getScrollX();
final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index f2e322d..396cb14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,6 +64,17 @@ public class AlternateRecentsComponent {
mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
+ Console.log(Constants.DebugFlags.App.RecentsComponent,
+ "[RecentsComponent|RecentsMessageHandler|handleMessage]",
+ "singleTaskRect: " + mSingleCountFirstTaskRect +
+ " multipleTaskRect: " + mMultipleCountFirstTaskRect);
+
+ // If we had the update the animation rects as a result of onServiceConnected, then
+ // we check for whether we need to toggle the recents here.
+ if (mToggleRecentsUponServiceBound) {
+ startAlternateRecentsActivity();
+ mToggleRecentsUponServiceBound = false;
+ }
}
}
}
@@ -78,11 +89,16 @@ public class AlternateRecentsComponent {
mService = new Messenger(service);
mServiceIsBound = true;
- // Toggle recents if this service connection was triggered by hitting the recents button
- if (mToggleRecentsUponServiceBound) {
- startAlternateRecentsActivity();
+ if (hasValidTaskRects()) {
+ // Toggle recents if this new service connection was triggered by hitting recents
+ if (mToggleRecentsUponServiceBound) {
+ startAlternateRecentsActivity();
+ mToggleRecentsUponServiceBound = false;
+ }
+ } else {
+ // Otherwise, update the animation rects before starting the recents if requested
+ updateAnimationRects();
}
- mToggleRecentsUponServiceBound = false;
}
@Override
@@ -191,6 +207,26 @@ public class AlternateRecentsComponent {
}
public void onConfigurationChanged(Configuration newConfig) {
+ updateAnimationRects();
+ }
+
+ /** Binds to the recents implementation */
+ private void bindToRecentsService(boolean toggleRecentsUponConnection) {
+ mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
+ Intent intent = new Intent();
+ intent.setClassName(sRecentsPackage, sRecentsService);
+ mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ /** Returns whether we have valid task rects to animate to. */
+ boolean hasValidTaskRects() {
+ return mSingleCountFirstTaskRect != null && mSingleCountFirstTaskRect.width() > 0 &&
+ mSingleCountFirstTaskRect.height() > 0 && mMultipleCountFirstTaskRect != null &&
+ mMultipleCountFirstTaskRect.width() > 0 && mMultipleCountFirstTaskRect.height() > 0;
+ }
+
+ /** Updates each of the task animation rects. */
+ void updateAnimationRects() {
if (mServiceIsBound) {
Resources res = mContext.getResources();
int statusBarHeight = res.getDimensionPixelSize(
@@ -216,14 +252,6 @@ public class AlternateRecentsComponent {
}
}
- /** Binds to the recents implementation */
- private void bindToRecentsService(boolean toggleRecentsUponConnection) {
- mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
- Intent intent = new Intent();
- intent.setClassName(sRecentsPackage, sRecentsService);
- mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- }
-
/** Loads the first task thumbnail */
Bitmap loadFirstTaskThumbnail() {
SystemServicesProxy ssp = mSystemServicesProxy;
@@ -300,6 +328,49 @@ public class AlternateRecentsComponent {
return SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
}
+ /** Creates the activity options for a thumbnail transition. */
+ ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
+ // Loading from thumbnail
+ Bitmap thumbnail;
+ Bitmap firstThumbnail = loadFirstTaskThumbnail();
+ if (firstThumbnail != null) {
+ // Create the thumbnail
+ thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+ Bitmap.Config.ARGB_8888);
+ int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
+ Canvas c = new Canvas(thumbnail);
+ c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
+ new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+ c.setBitmap(null);
+ // Recycle the old thumbnail
+ firstThumbnail.recycle();
+ } else {
+ // Load the thumbnail from the screenshot if can't get one from the system
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ Bitmap screenshot = takeScreenshot(display);
+ if (screenshot != null) {
+ Resources res = mContext.getResources();
+ int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
+ int statusBarHeight = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+ Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(thumbnail);
+ c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight +
+ size), new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+ c.setBitmap(null);
+ // Recycle the temporary screenshot
+ screenshot.recycle();
+ } else {
+ return null;
+ }
+ }
+
+ return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, thumbnail,
+ taskRect.left, taskRect.top, null);
+ }
+
/** Starts the recents activity */
void startAlternateRecentsActivity() {
// If the user has toggled it too quickly, then just eat up the event here (it's better than
@@ -351,47 +422,28 @@ public class AlternateRecentsComponent {
// number of items in the list.
List<ActivityManager.RecentTaskInfo> recentTasks =
ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
- boolean hasMultipleTasks = hasMultipleRecentsTask(recentTasks);
+ Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
+ mSingleCountFirstTaskRect;
boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
- Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect;
- if (!isTopTaskHome && !isTaskExcludedFromRecents &&
- (taskRect != null) && (taskRect.width() > 0) && (taskRect.height() > 0)) {
- // Loading from thumbnail
- Bitmap thumbnail;
- Bitmap firstThumbnail = loadFirstTaskThumbnail();
- if (firstThumbnail != null) {// Create the thumbnail
- thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
- Bitmap.Config.ARGB_8888);
- int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
- Canvas c = new Canvas(thumbnail);
- c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
- new Rect(0, 0, taskRect.width(), taskRect.height()), null);
- c.setBitmap(null);
- // Recycle the old thumbnail
- firstThumbnail.recycle();
+ boolean useThumbnailTransition = !isTopTaskHome && !isTaskExcludedFromRecents &&
+ hasValidTaskRects();
+
+ if (useThumbnailTransition) {
+ // Try starting with a thumbnail transition
+ ActivityOptions opts = getThumbnailTransitionActivityOptions(taskRect);
+ if (opts != null) {
+ startAlternateRecentsActivity(opts, true);
} else {
- // Load the thumbnail from the screenshot if can't get one from the system
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- Bitmap screenshot = takeScreenshot(display);
- Resources res = mContext.getResources();
- int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
- int statusBarHeight = res.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(thumbnail);
- c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size),
- new Rect(0, 0, taskRect.width(), taskRect.height()), null);
- c.setBitmap(null);
- // Recycle the temporary screenshot
- screenshot.recycle();
+ // Fall through below to the non-thumbnail transition
+ useThumbnailTransition = false;
}
+ }
- ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
- thumbnail, taskRect.left, taskRect.top, null);
- startAlternateRecentsActivity(opts, true);
- } else {
+ // If there is no thumbnail transition, then just use a generic transition
+ // XXX: This should be different between home and from a recents-excluded app, perhaps the
+ // recents-excluded app should still show up in recents, when the app is in the
+ // foreground
+ if (!useThumbnailTransition) {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter,
R.anim.recents_from_launcher_exit);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index bc8ab45..90ea873 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -91,11 +91,8 @@ public class Constants {
public static final int TaskStackOverscrollRange = 150;
public static final int FilterStartDelay = 25;
- // The amount to inverse scale the movement if we are overscrolling
- public static final float TouchOverscrollScaleFactor = 3f;
-
// The padding will be applied to the smallest dimension, and then applied to all sides
- public static final float StackPaddingPct = 0.15f;
+ public static final float StackPaddingPct = 0.1f;
// The overlap height relative to the task height
public static final float StackOverlapPct = 0.65f;
// The height of the peek space relative to the stack height
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 23a0179..d1a3954 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -49,6 +49,8 @@ public class RecentsConfiguration {
public int taskStackScrollDismissInfoPaneDistance;
public int taskStackMaxDim;
public int taskViewInfoPaneAnimDuration;
+ public int taskViewTranslationZMinPx;
+ public int taskViewTranslationZIncrementPx;
public int taskViewRoundedCornerRadiusPx;
public int searchBarSpaceHeightPx;
@@ -108,6 +110,9 @@ public class RecentsConfiguration {
res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
taskViewRoundedCornerRadiusPx =
res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+ taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+ taskViewTranslationZIncrementPx =
+ res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
index 983ad49..c6c29a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -20,10 +20,12 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.TouchFeedbackDrawable;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.FrameLayout;
@@ -151,6 +153,15 @@ class TaskInfoView extends FrameLayout {
RecentsConfiguration configuration = RecentsConfiguration.getInstance();
if (Constants.DebugFlags.App.EnableTaskBarThemeColors && t.colorPrimary != 0) {
setBackgroundColor(t.colorPrimary);
+ // Workaround: The button currently doesn't support setting a custom background tint
+ // not defined in the theme. Just lower the alpha on the button to make it blend more
+ // into the background.
+ if (mAppInfoButton.getBackground() instanceof TouchFeedbackDrawable) {
+ TouchFeedbackDrawable d = (TouchFeedbackDrawable) mAppInfoButton.getBackground();
+ if (d != null) {
+ d.setAlpha(96);
+ }
+ }
} else {
setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e273ecf..ce43b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -395,12 +395,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return false;
}
- /** Returns whether the specified scroll is out of bounds */
- boolean isScrollOutOfBounds(int scroll) {
- return (scroll < mMinScroll) || (scroll > mMaxScroll);
+
+ /** Returns the amount that the scroll is out of bounds */
+ int getScrollAmountOutOfBounds(int scroll) {
+ if (scroll < mMinScroll) {
+ return mMinScroll - scroll;
+ } else if (scroll > mMaxScroll) {
+ return scroll - mMaxScroll;
+ }
+ return 0;
}
+
+ /** Returns whether the specified scroll is out of bounds */
boolean isScrollOutOfBounds() {
- return isScrollOutOfBounds(getStackScroll());
+ return getScrollAmountOutOfBounds(getStackScroll()) != 0;
}
/** Updates the min and max virtual scroll bounds */
@@ -561,7 +569,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int smallestDimension = Math.min(width, height);
int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
if (Constants.DebugFlags.App.EnableSearchButton) {
- // Don't need to pad the top since we have some padding on the search bar already
+ mStackRect.top += padding;
mStackRect.left += padding;
mStackRect.right -= padding;
mStackRect.bottom -= padding;
@@ -1297,9 +1305,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
}
if (mIsScrolling) {
int curStackScroll = mSv.getStackScroll();
- if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) {
- // Scale the touch if we are overscrolling
- deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor;
+ int overScrollAmount = mSv.getScrollAmountOutOfBounds(curStackScroll + deltaY);
+ if (overScrollAmount != 0) {
+ // Bound the overscroll to a fixed amount, and inversely scale the y-movement
+ // relative to how close we are to the max overscroll
+ float maxOverScroll = mSv.mTaskRect.height() / 3f;
+ deltaY = Math.round(deltaY * (1f - (Math.min(maxOverScroll, overScrollAmount)
+ / maxOverScroll)));
}
mSv.setStackScroll(curStackScroll + deltaY);
if (mSv.isScrollOutOfBounds()) {
@@ -1319,6 +1331,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
// Enable HW layers on the stack
mSv.addHwLayersRefCount("flingScroll");
+ // XXX: Make this animation a function of the velocity AND distance
int overscrollRange = (int) (Math.min(1f,
Math.abs((float) velocity / mMaximumVelocity)) *
Constants.Values.TaskStackView.TaskStackOverscrollRange);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index ecd0c45..801de24 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,6 +20,7 @@ import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
@@ -33,7 +34,6 @@ import com.android.systemui.R;
import com.android.systemui.recents.BakedBezierInterpolator;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
@@ -108,6 +108,11 @@ public class TaskView extends FrameLayout implements View.OnClickListener,
mRoundedRectClipPath.reset();
mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
radius, radius, Path.Direction.CW);
+
+ // Update the outline
+ Outline o = new Outline();
+ o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), radius);
+ setOutline(o);
}
@Override
@@ -134,14 +139,20 @@ public class TaskView extends FrameLayout implements View.OnClickListener,
/** Synchronizes this view's properties with the task's transform */
void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
TaskViewTransform toTransform, int duration) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ int minZ = config.taskViewTranslationZMinPx;
+ int incZ = config.taskViewTranslationZIncrementPx;
+
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
+ setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
setScaleX(animateFromTransform.scale);
setScaleY(animateFromTransform.scale);
setAlpha(animateFromTransform.alpha);
}
animate().translationY(toTransform.translationY)
+ .translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)))
.scaleX(toTransform.scale)
.scaleY(toTransform.scale)
.alpha(toTransform.alpha)
@@ -157,6 +168,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener,
.start();
} else {
setTranslationY(toTransform.translationY);
+ setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
setScaleX(toTransform.scale);
setScaleY(toTransform.scale);
setAlpha(toTransform.alpha);
@@ -169,6 +181,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener,
void resetViewProperties() {
setTranslationX(0f);
setTranslationY(0f);
+ setTranslationZ(0f);
setScaleX(1f);
setScaleY(1f);
setAlpha(1f);
@@ -363,7 +376,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener,
@Override
public void onClick(View v) {
if (v == mInfoView) {
- // Do nothing
+ hideInfoPane();
} else if (v == mBarView.mApplicationIcon) {
mCb.onTaskIconClicked(this);
} else if (v == mInfoView.mAppInfoButton) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2c7464a..d224975 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -302,7 +302,7 @@ public abstract class BaseStatusBar extends SystemUI implements
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
- int[] switches = new int[7];
+ int[] switches = new int[8];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
@@ -317,7 +317,7 @@ public abstract class BaseStatusBar extends SystemUI implements
setSystemUiVisibility(switches[1], 0xffffffff);
topAppWindowChanged(switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(binders.get(0), switches[3], switches[4]);
+ setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[7] != 0);
setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
// Set up the initial icon state
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bbbe8fa..5362af5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -65,6 +65,8 @@ public class CommandQueue extends IStatusBar.Stub {
public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
+ private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
+
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
@@ -91,7 +93,8 @@ public class CommandQueue extends IStatusBar.Stub {
public void animateExpandSettingsPanel();
public void setSystemUiVisibility(int vis, int mask);
public void topAppWindowChanged(boolean visible);
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
public void setHardKeyboardStatus(boolean available, boolean enabled);
public void toggleRecentApps();
public void preloadRecentApps();
@@ -190,11 +193,13 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
synchronized (mList) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
- mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token)
- .sendToTarget();
+ Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
+ m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
+ m.sendToTarget();
}
}
@@ -298,7 +303,8 @@ public class CommandQueue extends IStatusBar.Stub {
mCallbacks.topAppWindowChanged(msg.arg1 != 0);
break;
case MSG_SHOW_IME_BUTTON:
- mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2);
+ mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+ msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
break;
case MSG_SET_HARD_KEYBOARD_STATUS:
mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 33e9051..169521d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -17,11 +17,6 @@
package com.android.systemui.statusbar;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -112,6 +107,10 @@ public abstract class ExpandableView extends FrameLayout {
mClipTopAmount = clipTopAmount;
}
+ public int getClipTopAmount() {
+ return mClipTopAmount;
+ }
+
public void setOnHeightChangedListener(OnHeightChangedListener listener) {
mOnHeightChangedListener = listener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 1f15eaf..379bd05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -94,10 +94,6 @@ public class NotificationContentView extends ExpandableView {
updateClipping();
}
- public int getClipTopAmount() {
- return mClipTopAmount;
- }
-
private void updateClipping() {
mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight);
setClipBounds(mClipBounds);
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 f945c79..3856ba1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2235,7 +2235,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
int flags = mNavigationIconHints;
if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
@@ -2243,7 +2244,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
flags &= ~NAVIGATION_HINT_BACK_ALT;
}
- if (imeShown) {
+ if (showImeSwitcher) {
flags |= NAVIGATION_HINT_IME_SHOWN;
} else {
flags &= ~NAVIGATION_HINT_IME_SHOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 72e22e9..81e2cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -237,6 +237,10 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
}
@Override
+ public void onChildSnappedBack(View animView) {
+ }
+
+ @Override
public View getChildAtPosition(MotionEvent ev) {
return mContentHolder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e4e5fb1..f8aab80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -97,6 +97,8 @@ public class NotificationStackScrollLayout extends ViewGroup
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
+ private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
+ private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>();
private ArrayList<AnimationEvent> mAnimationEvents
= new ArrayList<AnimationEvent>();
private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
@@ -377,11 +379,34 @@ public class NotificationStackScrollLayout extends ViewGroup
veto.performClick();
}
setSwipingInProgress(false);
+ if (mDragAnimPendingChildren.contains(v)) {
+ // We start the swipe and finish it in the same frame, we don't want any animation
+ // for the drag
+ mDragAnimPendingChildren.remove(v);
+ }
mSwipedOutViews.add(v);
+ mStackScrollAlgorithm.onDragFinished(v);
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView) {
+ mStackScrollAlgorithm.onDragFinished(animView);
+ if (!mDragAnimPendingChildren.contains(animView)) {
+ mSnappedBackChildren.add(animView);
+ requestChildrenUpdate();
+ mNeedsAnimation = true;
+ } else {
+ // We start the swipe and snap back in the same frame, we don't want any animation
+ mDragAnimPendingChildren.remove(animView);
+ }
}
public void onBeginDrag(View v) {
setSwipingInProgress(true);
+ mDragAnimPendingChildren.add(v);
+ mStackScrollAlgorithm.onBeginDrag(v);
+ requestChildrenUpdate();
+ mNeedsAnimation = true;
}
public void onDragCancelled(View v) {
@@ -934,12 +959,30 @@ public class NotificationStackScrollLayout extends ViewGroup
private void generateChildHierarchyEvents() {
generateChildAdditionEvents();
generateChildRemovalEvents();
+ generateSnapBackEvents();
+ generateDragEvents();
generateTopPaddingEvent();
mNeedsAnimation = false;
}
+ private void generateSnapBackEvents() {
+ for (View child : mSnappedBackChildren) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_SNAP_BACK));
+ }
+ mSnappedBackChildren.clear();
+ }
+
+ private void generateDragEvents() {
+ for (View child : mDragAnimPendingChildren) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_START_DRAG));
+ }
+ mDragAnimPendingChildren.clear();
+ }
+
private void generateChildRemovalEvents() {
- for (View child : mChildrenToRemoveAnimated) {
+ for (View child : mChildrenToRemoveAnimated) {
boolean childWasSwipedOut = mSwipedOutViews.contains(child);
int animationType = childWasSwipedOut
? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
@@ -951,7 +994,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void generateChildAdditionEvents() {
- for (View child : mChildrenToAddAnimated) {
+ for (View child : mChildrenToAddAnimated) {
mAnimationEvents.add(new AnimationEvent(child,
AnimationEvent.ANIMATION_TYPE_ADD));
}
@@ -1173,6 +1216,8 @@ public class NotificationStackScrollLayout extends ViewGroup
static int ANIMATION_TYPE_REMOVE = 2;
static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3;
static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 4;
+ static int ANIMATION_TYPE_START_DRAG = 5;
+ static int ANIMATION_TYPE_SNAP_BACK = 6;
final long eventStartTime;
final View changingView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 09d8d50..f7818c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -61,6 +61,7 @@ public class StackScrollAlgorithm {
private ExpandableView mFirstChildWhileExpanding;
private boolean mExpandedOnStart;
private int mTopStackTotalSize;
+ private ArrayList<View> mDraggedViews = new ArrayList<View>();
public StackScrollAlgorithm(Context context) {
initConstants(context);
@@ -118,6 +119,34 @@ public class StackScrollAlgorithm {
// Phase 3:
updateZValuesForState(resultState, algorithmState);
+
+ handleDraggedViews(resultState, algorithmState);
+ }
+
+ /**
+ * Handle the special state when views are being dragged
+ */
+ private void handleDraggedViews(StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+ for (View draggedView : mDraggedViews) {
+ int childIndex = algorithmState.visibleChildren.indexOf(draggedView);
+ if (childIndex >= 0 && childIndex < algorithmState.visibleChildren.size() - 1) {
+ View nextChild = algorithmState.visibleChildren.get(childIndex + 1);
+ if (!mDraggedViews.contains(nextChild)) {
+ // only if the view is not dragged itself we modify its state to be fully
+ // visible
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(
+ nextChild);
+ // The child below the dragged one must be fully visible
+ viewState.alpha = 1;
+ }
+
+ // Lets set the alpha to the one it currently has, as its currently being dragged
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(draggedView);
+ // The dragged child should keep the set alpha
+ viewState.alpha = draggedView.getAlpha();
+ }
+ }
}
/**
@@ -566,6 +595,14 @@ public class StackScrollAlgorithm {
}
}
+ public void onBeginDrag(View view) {
+ mDraggedViews.add(view);
+ }
+
+ public void onDragFinished(View view) {
+ mDraggedViews.remove(view);
+ }
+
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 26cef36..70126f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -93,6 +93,7 @@ public class StackScrollState {
int numChildren = mHostView.getChildCount();
float previousNotificationEnd = 0;
float previousNotificationStart = 0;
+ boolean previousNotificationIsSwiped = false;
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
ViewState state = mStateMap.get(child);
@@ -153,12 +154,20 @@ public class StackScrollState {
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
+
+ // When the previous notification is swiped, we don't clip the content to the
+ // bottom of it.
+ float clipHeight = previousNotificationIsSwiped
+ ? newHeight
+ : newNotificationEnd - (previousNotificationEnd);
+
updateChildClippingAndBackground(child, newHeight,
- newNotificationEnd - (previousNotificationEnd),
+ clipHeight,
(int) (newHeight - (previousNotificationStart - newYTranslation)));
- previousNotificationStart = newYTranslation;
+ previousNotificationStart = newYTranslation + child.getClipTopAmount();
previousNotificationEnd = newNotificationEnd;
+ previousNotificationIsSwiped = child.getTranslationX() != 0;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 4dce288..2e700aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -16,13 +16,21 @@
package com.android.systemui.statusbar.stack;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
/**
* An stack state animator which handles animations to new StackScrollStates
@@ -30,130 +38,372 @@ import java.util.ArrayList;
public class StackStateAnimator {
private static final int ANIMATION_DURATION = 360;
+ private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+ private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+ private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+ private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+ private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+ private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+ private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+ private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+ private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+ private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
private final Interpolator mFastOutSlowInInterpolator;
public NotificationStackScrollLayout mHostLayout;
- private boolean mAnimationIsRunning;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents =
new ArrayList<>();
+ private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
+ new ArrayList<>();
+ private Set<Animator> mAnimatorSet = new HashSet<Animator>();
+ private Stack<AnimatorListenerAdapter> mAnimationListenerPool
+ = new Stack<AnimatorListenerAdapter>();
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
+ android.R.interpolator.fast_out_slow_in);
}
public boolean isRunning() {
- return mAnimationIsRunning;
+ return !mAnimatorSet.isEmpty();
}
public void startAnimationForEvents(
ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents,
StackScrollState finalState) {
- int numEvents = mAnimationEvents.size();
- if (numEvents == 0) {
- // No events, so we don't perform any animation
- return;
- }
- long lastEventStartTime = mAnimationEvents.get(numEvents - 1).eventStartTime;
- long eventEnd = lastEventStartTime + ANIMATION_DURATION;
- long currentTime = AnimationUtils.currentAnimationTimeMillis();
- long newDuration = eventEnd - currentTime;
- if (newDuration <= 0) {
- // last event is long before this, so we don't do anything
- return;
- }
- initializeAddedViewStates(mAnimationEvents, finalState);
+
+ processAnimationEvents(mAnimationEvents, finalState);
+
+ boolean hasNewEvents = !mNewEvents.isEmpty();
int childCount = mHostLayout.getChildCount();
- boolean isFirstAnimatingView = true;
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
if (viewState == null) {
continue;
}
- int childVisibility = child.getVisibility();
- boolean wasVisible = childVisibility == View.VISIBLE;
- final float alpha = viewState.alpha;
- if (!wasVisible && alpha != 0 && !viewState.gone) {
- child.setVisibility(View.VISIBLE);
- }
- startPropertyAnimation(newDuration, isFirstAnimatingView, child, viewState, alpha);
+ startAnimations(child, viewState, hasNewEvents);
- // TODO: animate clipBounds
child.setClipBounds(null);
- int currentHeigth = child.getActualHeight();
- if (viewState.height != currentHeigth) {
- startHeightAnimation(newDuration, child, viewState, currentHeigth);
- }
- isFirstAnimatingView = false;
}
- mAnimationIsRunning = true;
+ if (!isRunning()) {
+ // no child has preformed any animation, lets finish
+ onAnimationFinished();
+ }
}
- private void startPropertyAnimation(long newDuration, final boolean hasFinishAction,
- final ExpandableView child, StackScrollState.ViewState viewState, final float alpha) {
- child.animate().setInterpolator(mFastOutSlowInInterpolator)
- .translationY(viewState.yTranslation)
- .translationZ(viewState.zTranslation)
- .setDuration(newDuration)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mAnimationIsRunning = false;
- if (hasFinishAction) {
- mHandledEvents.clear();
- mHostLayout.onChildAnimationFinished();
- }
- if (alpha == 0) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- });
+ /**
+ * Start an animation to the given viewState
+ */
+ private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
+ boolean hasNewEvents) {
+ int childVisibility = child.getVisibility();
+ boolean wasVisible = childVisibility == View.VISIBLE;
+ final float alpha = viewState.alpha;
+ if (!wasVisible && alpha != 0 && !viewState.gone) {
+ child.setVisibility(View.VISIBLE);
+ }
+ // start translationY animation
+ if (child.getTranslationY() != viewState.yTranslation) {
+ startYTranslationAnimation(child, viewState, hasNewEvents);
+ }
+ // start translationZ animation
+ if (child.getTranslationZ() != viewState.zTranslation) {
+ startZTranslationAnimation(child, viewState, hasNewEvents);
+ }
+ // start alpha animation
if (alpha != child.getAlpha()) {
- child.animate().withLayer().alpha(alpha);
+ startAlphaAnimation(child, viewState, hasNewEvents);
+ }
+ // start height animation
+ if (viewState.height != child.getActualHeight()) {
+ startHeightAnimation(child, viewState, hasNewEvents);
}
}
- private void startHeightAnimation(long newDuration, final ExpandableView child,
- StackScrollState.ViewState viewState, int currentHeigth) {
- ValueAnimator heightAnimator = ValueAnimator.ofInt(currentHeigth, viewState.height);
- heightAnimator.setInterpolator(mFastOutSlowInInterpolator);
- heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ private void startHeightAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ Integer previousEndValue = getChildTag(child,TAG_END_HEIGHT);
+ if (previousEndValue != null && previousEndValue == viewState.height) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ if (newDuration <= 0) {
+ // no new animation needed, let's just apply the value
+ child.setActualHeight(viewState.height);
+ if (previousAnimator != null && !isRunning()) {
+ onAnimationFinished();
+ }
+ return;
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), viewState.height);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
child.setActualHeight((int) animation.getAnimatedValue());
}
});
- heightAnimator.setDuration(newDuration);
- heightAnimator.start();
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_HEIGHT, null);
+ child.setTag(TAG_END_HEIGHT, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+ child.setTag(TAG_END_HEIGHT, viewState.height);
+ }
+
+ private void startAlphaAnimation(final ExpandableView child,
+ final StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ final float endAlpha = viewState.alpha;
+ Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+ if (previousEndValue != null && previousEndValue == endAlpha) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ if (newDuration <= 0) {
+ // no new animation needed, let's just apply the value
+ child.setAlpha(endAlpha);
+ if (endAlpha == 0) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ if (previousAnimator != null && !isRunning()) {
+ onAnimationFinished();
+ }
+ return;
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+ child.getAlpha(), endAlpha);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ // Handle layer type
+ final int currentLayerType = child.getLayerType();
+ child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setLayerType(currentLayerType, null);
+ if (endAlpha == 0 && !mWasCancelled) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ child.setTag(TAG_ANIMATOR_ALPHA, null);
+ child.setTag(TAG_END_ALPHA, null);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+ });
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_ALPHA, animator);
+ child.setTag(TAG_END_ALPHA, endAlpha);
+ }
+
+ private void startZTranslationAnimation(final ExpandableView child,
+ final StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+ if (previousEndValue != null && previousEndValue == viewState.zTranslation) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ if (newDuration <= 0) {
+ // no new animation needed, let's just apply the value
+ child.setTranslationZ(viewState.zTranslation);
+
+ if (previousAnimator != null && !isRunning()) {
+ onAnimationFinished();
+ }
+ return;
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+ child.getTranslationZ(), viewState.zTranslation);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+ child.setTag(TAG_END_TRANSLATION_Z, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+ child.setTag(TAG_END_TRANSLATION_Z, viewState.zTranslation);
+ }
+
+ private void startYTranslationAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState, boolean hasNewEvents) {
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+ if (previousEndValue != null && previousEndValue == viewState.yTranslation) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
+ if (newDuration <= 0) {
+ // no new animation needed, let's just apply the value
+ child.setTranslationY(viewState.yTranslation);
+ if (previousAnimator != null && !isRunning()) {
+ onAnimationFinished();
+ }
+ return;
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+ child.getTranslationY(), viewState.yTranslation);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+ child.setTag(TAG_END_TRANSLATION_Y, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+ child.setTag(TAG_END_TRANSLATION_Y, viewState.yTranslation);
+ }
+
+ /**
+ * Start an animator instantly instead of waiting on the next synchronization frame
+ */
+ private void startInstantly(ValueAnimator animator) {
+ animator.start();
+ animator.setCurrentPlayTime(0);
+ }
+
+ /**
+ * @return an adapter which ensures that onAnimationFinished is called once no animation is
+ * running anymore
+ */
+ private AnimatorListenerAdapter getGlobalAnimationFinishedListener() {
+ if (!mAnimationListenerPool.empty()) {
+ return mAnimationListenerPool.pop();
+ }
+
+ // We need to create a new one, no reusable ones found
+ return new AnimatorListenerAdapter() {
+ private boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimatorSet.remove(animation);
+ if (mAnimatorSet.isEmpty() && !mWasCancelled) {
+ onAnimationFinished();
+ }
+ mAnimationListenerPool.push(this);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimatorSet.add(animation);
+ mWasCancelled = false;
+ }
+ };
+ }
+
+ private <T> T getChildTag(View child, int tag) {
+ return (T) child.getTag(tag);
+ }
+
+ /**
+ * Cancel the previous animator and get the duration of the new animation.
+ *
+ * @param previousAnimator the animator which was running before
+ * @param hasNewEvents indicating whether new events came in in this animation
+ * @return the new duration
+ */
+ private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator,
+ boolean hasNewEvents) {
+ long newDuration = ANIMATION_DURATION;
+ if (previousAnimator != null) {
+ if (!hasNewEvents) {
+ // This is only an update, no new event came in. lets just take the remaining
+ // duration as the new duration
+ newDuration = previousAnimator.getDuration()
+ - previousAnimator.getCurrentPlayTime();
+ }
+ previousAnimator.cancel();
+ } else if (!hasNewEvents){
+ newDuration = 0;
+ }
+ return newDuration;
+ }
+
+ private void onAnimationFinished() {
+ mHandledEvents.clear();
+ mNewEvents.clear();
+ mHostLayout.onChildAnimationFinished();
}
/**
- * Initialize the viewStates for the added children
+ * Process the animationEvents for a new animation
*
- * @param animationEvents the animation events who contain the added children
+ * @param animationEvents the animation events for the animation to perform
* @param finalState the final state to animate to
*/
- private void initializeAddedViewStates(
+ private void processAnimationEvents(
ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents,
StackScrollState finalState) {
+ mNewEvents.clear();
for (NotificationStackScrollLayout.AnimationEvent event: animationEvents) {
View changingView = event.changingView;
- if (event.animationType == NotificationStackScrollLayout.AnimationEvent
- .ANIMATION_TYPE_ADD && !mHandledEvents.contains(event)) {
-
- // This item is added, initialize it's properties.
- StackScrollState.ViewState viewState = finalState.getViewStateForView(changingView);
- if (viewState == null) {
- // The position for this child was never generated, let's continue.
- continue;
+ if (!mHandledEvents.contains(event)) {
+ if (event.animationType == NotificationStackScrollLayout.AnimationEvent
+ .ANIMATION_TYPE_ADD) {
+
+ // This item is added, initialize it's properties.
+ StackScrollState.ViewState viewState = finalState
+ .getViewStateForView(changingView);
+ if (viewState == null) {
+ // The position for this child was never generated, let's continue.
+ continue;
+ }
+ changingView.setAlpha(0);
+ changingView.setTranslationY(viewState.yTranslation);
+ changingView.setTranslationZ(viewState.zTranslation);
}
- changingView.setAlpha(0);
- changingView.setTranslationY(viewState.yTranslation);
- changingView.setTranslationZ(viewState.zTranslation);
mHandledEvents.add(event);
+ mNewEvents.add(event);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index d615542..4b3d3b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -78,7 +78,8 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
}
@Override
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 7ed1cc7..10315a7 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1532,14 +1532,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
mImeWindowVis = vis;
mBackDisposition = backDisposition;
- if (mStatusBar != null) {
- mStatusBar.setImeWindowStatus(token, vis, backDisposition);
- }
final boolean iconVisibility = ((vis & (InputMethodService.IME_ACTIVE)) != 0)
&& (mWindowManagerService.isHardKeyboardAvailable()
|| (vis & (InputMethodService.IME_VISIBLE)) != 0);
+ final boolean needsToShowImeSwitcher = iconVisibility
+ && needsToShowImeSwitchOngoingNotification();
+ if (mStatusBar != null) {
+ mStatusBar.setImeWindowStatus(token, vis, backDisposition,
+ needsToShowImeSwitcher);
+ }
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
- if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
+ if (imi != null && needsToShowImeSwitcher) {
// Used to load label
final CharSequence title = mRes.getText(
com.android.internal.R.string.select_input_method);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f908de2..cbb8377 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7070,7 +7070,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<ActivityRecord> activities = tr.mActivities;
int activityNdx;
final int numActivities = activities.size();
- for (activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+ for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+ ++activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.intent != null &&
(r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 91afec7..7f43e43 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -21,6 +21,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemProperties;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayEventReceiver;
@@ -47,8 +48,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
new SparseArray<LocalDisplayDevice>();
private HotplugDisplayEventReceiver mHotplugReceiver;
- private final SurfaceControl.PhysicalDisplayInfo mTempPhys = new SurfaceControl.PhysicalDisplayInfo();
-
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -68,14 +67,31 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private void tryConnectDisplayLocked(int builtInDisplayId) {
IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
- if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
+ if (displayToken != null) {
+ SurfaceControl.PhysicalDisplayInfo[] configs =
+ SurfaceControl.getDisplayConfigs(displayToken);
+ if (configs == null) {
+ // There are no valid configs for this device, so we can't use it
+ Slog.w(TAG, "No valid configs found for display device " +
+ builtInDisplayId);
+ return;
+ }
+ int activeConfig = SurfaceControl.getActiveConfig(displayToken);
+ if (activeConfig < 0) {
+ // There is no active config, and for now we don't have the
+ // policy to set one.
+ Slog.w(TAG, "No active config found for display device " +
+ builtInDisplayId);
+ return;
+ }
LocalDisplayDevice device = mDevices.get(builtInDisplayId);
if (device == null) {
// Display was added.
- device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
+ device = new LocalDisplayDevice(displayToken, builtInDisplayId,
+ configs[activeConfig]);
mDevices.put(builtInDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
- } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
+ } else if (device.updatePhysicalDisplayInfoLocked(configs[activeConfig])) {
// Display properties changed.
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
@@ -228,4 +244,4 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index fd2f8a1..8968da3 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -642,8 +642,9 @@ public final class DreamManagerService extends SystemService {
try {
synchronized (mMcuHal) {
if (mReleased) {
- throw new IllegalStateException("This operation cannot be performed "
- + "because the dream has ended.");
+ Slog.w(TAG, "Ignoring message to MCU HAL because the dream "
+ + "has already ended: " + msg);
+ return null;
}
return mMcuHal.sendMessage(msg, arg);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index c87fc99..b103a4d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -40,7 +40,7 @@ import java.util.List;
*
* <p>Declared as package-private, accessed by {@link HdmiControlService} only.
*/
-class HdmiCecController {
+final class HdmiCecController {
private static final String TAG = "HdmiCecController";
private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
@@ -313,6 +313,63 @@ class HdmiCecController {
return mDeviceInfos.get(logicalAddress);
}
+ /**
+ * Add a new logical address to the device. Device's HW should be notified
+ * when a new logical address is assigned to a device, so that it can accept
+ * a command having available destinations.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param newLogicalAddress a logical address to be added
+ * @return 0 on success. Otherwise, returns negative value
+ */
+ int addLogicalAddress(int newLogicalAddress) {
+ if (HdmiCec.isValidAddress(newLogicalAddress)) {
+ return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Clear all logical addresses registered in the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ void clearLogicalAddress() {
+ nativeClearLogicalAddress(mNativePtr);
+ }
+
+ /**
+ * Return the physical address of the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @return CEC physical address of the device. The range of success address
+ * is between 0x0000 and 0xFFFF. If failed it returns -1
+ */
+ int getPhysicalAddress() {
+ return nativeGetPhysicalAddress(mNativePtr);
+ }
+
+ /**
+ * Return CEC version of the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ int getVersion() {
+ return nativeGetVersion(mNativePtr);
+ }
+
+ /**
+ * Return vendor id of the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ int getVendorId() {
+ return nativeGetVendorId(mNativePtr);
+ }
+
private void init(HdmiControlService service, long nativePtr) {
mIoHandler = new IoHandler(service.getServiceLooper());
mControlHandler = new ControlHandler(service.getServiceLooper());
@@ -364,6 +421,11 @@ class HdmiCecController {
}
private static native long nativeInit(HdmiCecController handler);
- private static native int nativeSendCecCommand(long contollerPtr, int srcAddress,
+ private static native int nativeSendCecCommand(long controllerPtr, int srcAddress,
int dstAddress, byte[] body);
+ private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress);
+ private static native void nativeClearLogicalAddress(long controllerPtr);
+ private static native int nativeGetPhysicalAddress(long controllerPtr);
+ private static native int nativeGetVersion(long controllerPtr);
+ private static native int nativeGetVendorId(long controllerPtr);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6a843a8..72fc295 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7479,11 +7479,7 @@ public class PackageManagerService extends IPackageManager.Stub {
null);
PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "installExistingPackage for user " + userId);
- }
+ enforceCrossUserPermission(uid, userId, true, "installExistingPackage for user " + userId);
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3239b46..4f5326f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -734,6 +734,15 @@ public class UserManagerService extends IUserManager.Stub {
writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADD_USER);
+ writeBoolean(serializer, restrictions, UserManager.ENSURE_VERIFY_APPS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_APPS);
serializer.endTag(null, TAG_RESTRICTIONS);
}
serializer.endTag(null, TAG_USER);
@@ -873,6 +882,15 @@ public class UserManagerService extends IUserManager.Stub {
readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_ADD_USER);
+ readBoolean(parser, restrictions, UserManager.ENSURE_VERIFY_APPS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_APPS);
}
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 022bdae..738ad32 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -74,6 +74,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
private boolean mMenuVisible = false;
private int mImeWindowVis = 0;
private int mImeBackDisposition;
+ private boolean mShowImeSwitcher;
private IBinder mImeToken = null;
private int mCurrentUserId;
@@ -346,7 +347,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
@Override
- public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
+ public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
+ final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
@@ -360,11 +362,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
mImeToken = token;
+ mShowImeSwitcher = showImeSwitcher;
mHandler.post(new Runnable() {
public void run() {
if (mBar != null) {
try {
- mBar.setImeWindowStatus(token, vis, backDisposition);
+ mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
} catch (RemoteException ex) {
}
}
@@ -512,6 +515,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
switches[2] = mMenuVisible ? 1 : 0;
switches[3] = mImeWindowVis;
switches[4] = mImeBackDisposition;
+ switches[7] = mShowImeSwitcher ? 1 : 0;
binders.add(mImeToken);
}
switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index 527216d..27c8876 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -43,6 +43,16 @@ public:
// Send message to other device. Note that it runs in IO thread.
int sendMessage(const cec_message_t& message);
+ // Add a logical address to device.
+ int addLogicalAddress(cec_logical_address_t address);
+ // Clear all logical address registered to the device.
+ void clearLogicaladdress();
+ // Get physical address of device.
+ int getPhysicalAddress();
+ // Get CEC version from driver.
+ int getVersion();
+ // Get vendor id used for vendor command.
+ uint32_t getVendorId();
private:
// Propagate the message up to Java layer.
@@ -94,6 +104,34 @@ int HdmiCecController::sendMessage(const cec_message_t& message) {
return mDevice->send_message(mDevice, &message);
}
+int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
+ return mDevice->add_logical_address(mDevice, address);
+}
+
+void HdmiCecController::clearLogicaladdress() {
+ mDevice->clear_logical_address(mDevice);
+}
+
+int HdmiCecController::getPhysicalAddress() {
+ uint16_t physicalAddress = 0xFFFF;
+ if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) {
+ return physicalAddress;
+ }
+ return -1;
+}
+
+int HdmiCecController::getVersion() {
+ int version = 0;
+ mDevice->get_version(mDevice, &version);
+ return version;
+}
+
+uint32_t HdmiCecController::getVendorId() {
+ uint32_t vendorId = 0;
+ mDevice->get_vendor_id(mDevice, &vendorId);
+ return vendorId;
+}
+
// static
void HdmiCecController::checkAndClearExceptionFromCallback(JNIEnv* env,
const char* methodName) {
@@ -180,12 +218,51 @@ static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
return controller->sendMessage(message);
}
+static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz,
+ jlong controllerPtr, jint logicalAddress) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->addLogicalAddress(
+ static_cast<cec_logical_address_t>(logicalAddress));
+}
+
+static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz,
+ jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ controller->clearLogicaladdress();
+}
+
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz,
+ jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getPhysicalAddress();
+}
+
+static jint nativeGetVersion(JNIEnv* env, jclass clazz,
+ jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getVersion();
+}
+
+static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getVendorId();
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J",
(void *) nativeInit },
- { "nativeSendCecCommand", "(JII[B)I",
- (void *) nativeSendCecCommand },
+ { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand },
+ { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress },
+ { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress },
+ { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
+ { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
+ { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
};
#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7a0d1c7..23b912f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -44,6 +44,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -3023,6 +3024,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
ComponentName activity) {
synchronized (this) {
@@ -3043,6 +3045,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
synchronized (this) {
if (who == null) {
@@ -3168,4 +3171,110 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
}
+
+ @Override
+ public void enableSystemApp(ComponentName who, String packageName) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ UserManager um = UserManager.get(mContext);
+ if (!um.getUserInfo(userId).isManagedProfile()) {
+ throw new IllegalStateException(
+ "Only call this method from a managed profile.");
+ }
+
+ // TODO: Use UserManager::getProfileParent when available.
+ UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+ if (DBG) {
+ Slog.v(LOG_TAG, "installing " + packageName + " for "
+ + userId);
+ }
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ if (!isSystemApp(pm, packageName, primaryUser.id)) {
+ throw new IllegalArgumentException("Only system apps can be enabled this way.");
+ }
+
+ // Install the app.
+ pm.installExistingPackageAsUser(packageName, userId);
+
+ } catch (RemoteException re) {
+ // shouldn't happen
+ Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ @Override
+ public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ UserManager um = UserManager.get(mContext);
+ if (!um.getUserInfo(userId).isManagedProfile()) {
+ throw new IllegalStateException(
+ "Only call this method from a managed profile.");
+ }
+
+ // TODO: Use UserManager::getProfileParent when available.
+ UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ 0, // no flags
+ primaryUser.id);
+
+ if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+ int numberOfAppsInstalled = 0;
+ if (activitiesToEnable != null) {
+ for (ResolveInfo info : activitiesToEnable) {
+ if (info.activityInfo != null) {
+
+ if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) {
+ throw new IllegalArgumentException(
+ "Only system apps can be enabled this way.");
+ }
+
+
+ numberOfAppsInstalled++;
+ pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
+ }
+ }
+ }
+ return numberOfAppsInstalled;
+ } catch (RemoteException e) {
+ // shouldn't happen
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
+ return 0;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ private boolean isSystemApp(IPackageManager pm, String packageName, int userId)
+ throws RemoteException {
+ ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0, userId);
+ return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;
+ }
}