summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt31
-rw-r--r--cmds/settings/src/com/android/commands/settings/SettingsCmd.java34
-rw-r--r--core/java/android/app/ActivityView.java17
-rw-r--r--core/java/android/app/VoiceInteractor.java2
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java58
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java514
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java88
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java148
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfiguration.java3
-rw-r--r--core/java/android/net/RouteInfo.java2
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java220
-rw-r--r--core/java/android/service/voice/DspInfo.java56
-rw-r--r--core/java/android/service/voice/KeyphraseEnrollmentInfo.java246
-rw-r--r--core/java/android/service/voice/KeyphraseInfo.java27
-rw-r--r--core/java/android/service/voice/SoundTriggerManager.java73
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java59
-rw-r--r--core/java/android/speech/tts/RequestConfig.java15
-rw-r--r--core/java/android/speech/tts/RequestConfigHelper.java15
-rw-r--r--core/java/android/speech/tts/SynthesisRequestV2.java15
-rw-r--r--core/java/android/speech/tts/VoiceInfo.java15
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp8
-rw-r--r--core/jni/android/graphics/AndroidPicture.cpp112
-rw-r--r--core/jni/android/graphics/AndroidPicture.h63
-rw-r--r--core/jni/android/graphics/Bitmap.cpp40
-rw-r--r--core/jni/android/graphics/Canvas.cpp209
-rw-r--r--core/jni/android/graphics/Graphics.cpp5
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h4
-rw-r--r--core/jni/android/graphics/Picture.cpp38
-rw-r--r--core/jni/android/graphics/pdf/PdfDocument.cpp29
-rw-r--r--core/jni/android_media_AudioSystem.cpp7
-rw-r--r--core/jni/android_view_Surface.cpp1
-rw-r--r--core/res/AndroidManifest.xml11
-rw-r--r--core/res/res/layout/notification_template_material_big_base.xml2
-rw-r--r--core/res/res/layout/notification_template_material_big_media.xml3
-rw-r--r--core/res/res/layout/notification_template_material_big_text.xml2
-rw-r--r--core/res/res/values-watch/config.xml4
-rw-r--r--core/res/res/values/attrs.xml10
-rw-r--r--core/res/res/values/colors.xml1
-rw-r--r--core/res/res/values/config.xml10
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/styles_material.xml3
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--data/fonts/Android.mk2
-rw-r--r--data/fonts/Roboto-BlackItalic.ttfbin0 -> 134716 bytes
-rw-r--r--data/fonts/fonts.mk1
-rw-r--r--data/fonts/system_fonts.xml1
-rw-r--r--docs/html/distribute/engage/analytics.jd50
-rw-r--r--docs/html/distribute/engage/deep-linking.jd35
-rw-r--r--docs/html/distribute/engage/engage_toc.cs6
-rw-r--r--docs/html/distribute/engage/index.jd4
-rw-r--r--docs/html/distribute/engage/widgets.jd2
-rw-r--r--docs/html/distribute/monetize/ads.jd101
-rw-r--r--docs/html/distribute/users/index.jd4
-rw-r--r--docs/html/distribute/users/promote-with-ads.jd45
-rw-r--r--docs/html/distribute/users/users_toc.cs7
-rw-r--r--docs/html/images/gp-ads-console.jpgbin0 -> 34526 bytes
-rw-r--r--docs/html/images/gp-ads-linking2.jpgbin0 -> 30046 bytes
-rw-r--r--docs/html/images/gp-analytics.jpgbin0 -> 36914 bytes
-rw-r--r--docs/html/jd_collections.js19
-rw-r--r--docs/html/jd_extras.js28
-rw-r--r--graphics/java/android/graphics/Bitmap.java11
-rw-r--r--graphics/java/android/graphics/Picture.java25
-rw-r--r--libs/hwui/TessellationCache.cpp29
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp2
-rw-r--r--media/java/android/media/AudioManager.java22
-rw-r--r--media/java/android/media/AudioSystem.java5
-rw-r--r--media/java/android/media/tv/TvContract.java9
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp13
-rw-r--r--media/jni/android_media_MediaScanner.cpp11
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.pngbin756 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.pngbin569 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.pngbin932 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.pngbin1683 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/ic_notify_zen.xml (renamed from packages/SystemUI/res/drawable/ic_qs_location_01.xml)10
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_color_inversion.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_inversion_off.xml (renamed from packages/SystemUI/res/drawable/ic_qs_location_02.xml)8
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_inversion_on.xml (renamed from packages/SystemUI/res/drawable/ic_qs_location_04.xml)6
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_03.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_05.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_06.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_07.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_08.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_09.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_10.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_off.xml32
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_location_on.xml29
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_no_sim.xml (renamed from packages/SystemUI/res/drawable/ic_qs_location_11.xml)8
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml49
-rw-r--r--packages/SystemUI/res/values/colors.xml12
-rw-r--r--packages/SystemUI/res/values/dimens.xml10
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java136
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java128
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java204
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java153
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java26
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java22
-rw-r--r--services/core/java/com/android/server/BatteryService.java72
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java3
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityStack.java15
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java89
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java12
-rw-r--r--services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java39
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java80
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java43
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiConstants.java26
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java132
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java20
-rw-r--r--services/core/java/com/android/server/hdmi/NewDeviceAction.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java22
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java1
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java21
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java8
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp43
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java10
-rw-r--r--tests/Camera2Tests/CameraToo/Android.mk23
-rw-r--r--tests/Camera2Tests/CameraToo/AndroidManifest.xml33
-rw-r--r--tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml23
-rw-r--r--tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java437
-rw-r--r--tests/Camera2Tests/CameraToo/tests/Android.mk25
-rw-r--r--tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml29
-rw-r--r--tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java189
-rw-r--r--tests/VoiceEnrollment/Android.mk12
-rw-r--r--tests/VoiceEnrollment/AndroidManifest.xml16
-rw-r--r--tests/VoiceEnrollment/res/xml/enrollment_application.xml23
-rw-r--r--tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java23
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java5
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java15
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java39
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java76
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java108
158 files changed, 4073 insertions, 1889 deletions
diff --git a/api/current.txt b/api/current.txt
index 80f83cd..991186f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1000,6 +1000,9 @@ package android {
field public static final int scrollbars = 16842974; // 0x10100de
field public static final int scrollingCache = 16843006; // 0x10100fe
field public static final deprecated int searchButtonText = 16843269; // 0x1010205
+ field public static final int searchKeyphrase = 16843873; // 0x1010461
+ field public static final int searchKeyphraseId = 16843872; // 0x1010460
+ field public static final int searchKeyphraseSupportedLocales = 16843874; // 0x1010462
field public static final int searchMode = 16843221; // 0x10101d5
field public static final int searchSettingsDescription = 16843402; // 0x101028a
field public static final int searchSuggestAuthority = 16843222; // 0x10101d6
@@ -13681,6 +13684,7 @@ package android.media {
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
+ method public int allocateAudioSessionId();
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -13741,6 +13745,7 @@ package android.media {
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
+ field public static final int ERROR = -1; // 0xffffffff
field public static final java.lang.String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
field public static final java.lang.String EXTRA_SCO_AUDIO_PREVIOUS_STATE = "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
field public static final java.lang.String EXTRA_SCO_AUDIO_STATE = "android.media.extra.SCO_AUDIO_STATE";
@@ -15820,8 +15825,11 @@ package android.media.tv {
field public static final int TYPE_ISDB_S = 262656; // 0x40200
field public static final int TYPE_ISDB_T = 262144; // 0x40000
field public static final int TYPE_ISDB_TB = 262400; // 0x40100
+ field public static final int TYPE_NTSC = 1; // 0x1
field public static final int TYPE_OTHER = 0; // 0x0
+ field public static final int TYPE_PAL = 2; // 0x2
field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
+ field public static final int TYPE_SECAM = 3; // 0x3
field public static final int TYPE_S_DMB = 393472; // 0x60100
field public static final int TYPE_T_DMB = 393216; // 0x60000
}
@@ -26010,21 +26018,28 @@ package android.service.notification {
method public final void cancelNotification(java.lang.String);
method public final void cancelNotifications(java.lang.String[]);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
- method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking();
+ method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
method public android.os.IBinder onBind(android.content.Intent);
method public void onListenerConnected();
- method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
- method public void onNotificationRankingUpdate();
- method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
+ method public void onNotificationPosted(android.service.notification.StatusBarNotification);
+ method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
}
- public static class NotificationListenerService.Ranking implements android.os.Parcelable {
+ public static class NotificationListenerService.Ranking {
+ method public java.lang.String getKey();
+ method public int getRank();
+ method public boolean isAmbient();
+ method public boolean isInterceptedByDoNotDisturb();
+ }
+
+ public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
method public int describeContents();
method public java.lang.String[] getOrderedKeys();
- method public int getRank(java.lang.String);
- method public boolean isAmbient(java.lang.String);
- method public boolean isInterceptedByDoNotDisturb(java.lang.String);
+ method public android.service.notification.NotificationListenerService.Ranking getRanking(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index dce0a75..e6847a9 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,6 +20,7 @@ import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IActivityManager.ContentProviderHolder;
import android.content.IContentProvider;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -33,7 +34,8 @@ public final class SettingsCmd {
enum CommandVerb {
UNSPECIFIED,
GET,
- PUT
+ PUT,
+ DELETE
}
static String[] mArgs;
@@ -74,6 +76,8 @@ public final class SettingsCmd {
mVerb = CommandVerb.GET;
} else if ("put".equalsIgnoreCase(arg)) {
mVerb = CommandVerb.PUT;
+ } else if ("delete".equalsIgnoreCase(arg)) {
+ mVerb = CommandVerb.DELETE;
} else {
// invalid
System.err.println("Invalid command: " + arg);
@@ -87,7 +91,7 @@ public final class SettingsCmd {
break; // invalid
}
mTable = arg.toLowerCase();
- } else if (mVerb == CommandVerb.GET) {
+ } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
mKey = arg;
if (mNextArg >= mArgs.length) {
valid = true;
@@ -136,6 +140,10 @@ public final class SettingsCmd {
case PUT:
putForUser(provider, mUser, mTable, mKey, mValue);
break;
+ case DELETE:
+ System.out.println("Deleted "
+ + deleteForUser(provider, mUser, mTable, mKey) + " rows");
+ break;
default:
System.err.println("Unspecified command");
break;
@@ -211,9 +219,31 @@ public final class SettingsCmd {
}
}
+ int deleteForUser(IContentProvider provider, int userHandle,
+ final String table, final String key) {
+ Uri targetUri;
+ if ("system".equals(table)) targetUri = Settings.System.getUriFor(key);
+ else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key);
+ else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key);
+ else {
+ System.err.println("Invalid table; no delete performed");
+ throw new IllegalArgumentException("Invalid table " + table);
+ }
+
+ int num = 0;
+ try {
+ num = provider.delete(null, targetUri, null, null);
+ } catch (RemoteException e) {
+ System.err.println("Can't clear key " + key + " in " + table + " for user "
+ + userHandle);
+ }
+ return num;
+ }
+
private static void printUsage() {
System.err.println("usage: settings [--user NUM] get namespace key");
System.err.println(" settings [--user NUM] put namespace key value");
+ System.err.println(" settings [--user NUM] delete namespace key");
System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index c29d75e..94ea2c5 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -354,9 +354,11 @@ public class ActivityView extends ViewGroup {
private static class ActivityContainerWrapper {
private final IActivityContainer mIActivityContainer;
private final CloseGuard mGuard = CloseGuard.get();
+ boolean mOpened; // Protected by mGuard.
ActivityContainerWrapper(IActivityContainer container) {
mIActivityContainer = container;
+ mOpened = true;
mGuard.open("release");
}
@@ -424,11 +426,16 @@ public class ActivityView extends ViewGroup {
}
void release() {
- if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
- try {
- mIActivityContainer.release();
- mGuard.close();
- } catch (RemoteException e) {
+ synchronized (mGuard) {
+ if (mOpened) {
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+ try {
+ mIActivityContainer.release();
+ mGuard.close();
+ } catch (RemoteException e) {
+ }
+ mOpened = false;
+ }
}
}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 85e970c..0d94721 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -293,7 +293,7 @@ public class VoiceInteractor {
IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
IVoiceInteractorCallback callback) throws RemoteException {
- return interactor.startConfirmation(packageName, callback, mCommand, mArgs);
+ return interactor.startCommand(packageName, callback, mCommand, mArgs);
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index ff56720..9eea545 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -30,7 +30,7 @@ import java.util.List;
*
* <p>These properties are fixed for a given CameraDevice, and can be queried
* through the {@link CameraManager CameraManager}
- * interface in addition to through the CameraDevice interface.</p>
+ * interface with {@link CameraManager#getCameraCharacteristics}.</p>
*
* <p>{@link CameraCharacteristics} objects are immutable.</p>
*
@@ -555,7 +555,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>List containing a subset of the optical image
* stabilization (OIS) modes specified in
* {@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}.</p>
- * <p>If OIS is not implemented for a given camera device, this should
+ * <p>If OIS is not implemented for a given camera device, this will
* contain only OFF.</p>
*
* @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
@@ -612,7 +612,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
/**
* <p>Direction the camera faces relative to
- * device screen</p>
+ * device screen.</p>
* @see #LENS_FACING_FRONT
* @see #LENS_FACING_BACK
*/
@@ -622,7 +622,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
/**
* <p>The set of noise reduction modes supported by this camera device.</p>
* <p>This tag lists the valid modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}.</p>
- * <p>Full-capability camera devices must laways support OFF and FAST.</p>
+ * <p>Full-capability camera devices must always support OFF and FAST.</p>
*
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
@@ -778,18 +778,20 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<Byte>("android.request.pipelineMaxDepth", byte.class);
/**
- * <p>Optional. Defaults to 1. Defines how many sub-components
+ * <p>Defines how many sub-components
* a result will be composed of.</p>
* <p>In order to combat the pipeline latency, partial results
* may be delivered to the application layer from the camera device as
* soon as they are available.</p>
- * <p>A value of 1 means that partial results are not supported.</p>
+ * <p>Optional; defaults to 1. A value of 1 means that partial
+ * results are not supported, and only the final TotalCaptureResult will
+ * be produced by the camera device.</p>
* <p>A typical use case for this might be: after requesting an
* auto-focus (AF) lock the new AF state might be available 50%
* of the way through the pipeline. The camera device could
* then immediately dispatch this state via a partial result to
- * the framework/application layer, and the rest of the
- * metadata via later partial results.</p>
+ * the application, and the rest of the metadata via later
+ * partial results.</p>
*/
public static final Key<Integer> REQUEST_PARTIAL_RESULT_COUNT =
new Key<Integer>("android.request.partialResultCount", int.class);
@@ -806,8 +808,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* to do this query each of android.request.availableRequestKeys,
* android.request.availableResultKeys,
* android.request.availableCharacteristicsKeys.</p>
- * <p>XX: Maybe these should go into {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}
- * as a table instead?</p>
* <p>The following capabilities are guaranteed to be available on
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
* <ul>
@@ -815,14 +815,11 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>MANUAL_POST_PROCESSING</li>
* </ul>
* <p>Other capabilities may be available on either FULL or LIMITED
- * devices, but the app. should query this field to be sure.</p>
+ * devices, but the application should query this field to be sure.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
- * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
- * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
* @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
* @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
- * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
* @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
*/
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -838,7 +835,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* at a more granular level than capabilities. This is especially
* important for optional keys that are not listed under any capability
* in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
- * <p>TODO: This should be used by #getAvailableCaptureRequestKeys.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @hide
@@ -863,7 +859,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* at a more granular level than capabilities. This is especially
* important for optional keys that are not listed under any capability
* in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
- * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
@@ -879,7 +874,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* android.request.availableResultKeys (except that it applies for
* CameraCharacteristics instead of CaptureResult). See above for more
* details.</p>
- * <p>TODO: This should be used by CameraCharacteristics#getKeys.</p>
* @hide
*/
public static final Key<int[]> REQUEST_AVAILABLE_CHARACTERISTICS_KEYS =
@@ -927,10 +921,15 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
/**
- * <p>The maximum ratio between active area width
- * and crop region width, or between active area height and
- * crop region height, if the crop region height is larger
- * than width</p>
+ * <p>The maximum ratio between both active area width
+ * and crop region width, and active area height and
+ * crop region height.</p>
+ * <p>This represents the maximum amount of zooming possible by
+ * the camera device, or equivalently, the minimum cropping
+ * window size.</p>
+ * <p>Crop regions that have a width or height that is smaller
+ * than this ratio allows will be rounded up to the minimum
+ * allowed size by the camera device.</p>
*/
public static final Key<Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM =
new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
@@ -1339,9 +1338,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<android.util.Range<Integer>>("android.sensor.info.sensitivityRange", new TypeReference<android.util.Range<Integer>>() {{ }});
/**
- * <p>Arrangement of color filters on sensor;
+ * <p>The arrangement of color filters on sensor;
* represents the colors in the top-left 2x2 section of
- * the sensor, in reading order</p>
+ * the sensor, in reading order.</p>
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG
@@ -1666,10 +1665,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
/**
- * <p>Which face detection modes are available,
- * if any.</p>
- * <p>OFF means face detection is disabled, it must
- * be included in the list.</p>
+ * <p>The face detection modes that are available
+ * for this camera device.</p>
+ * <p>OFF is always supported.</p>
* <p>SIMPLE means the device supports the
* android.statistics.faceRectangles and
* android.statistics.faceScores outputs.</p>
@@ -1681,8 +1679,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.statistics.info.availableFaceDetectModes", int[].class);
/**
- * <p>Maximum number of simultaneously detectable
- * faces</p>
+ * <p>The maximum number of simultaneously detectable
+ * faces.</p>
*/
public static final Key<Integer> STATISTICS_INFO_MAX_FACE_COUNT =
new Key<Integer>("android.statistics.info.maxFaceCount", int.class);
@@ -1691,7 +1689,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>The set of hot pixel map output modes supported by this camera device.</p>
* <p>This tag lists valid output modes for {@link CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE android.statistics.hotPixelMapMode}.</p>
* <p>If no hotpixel map is available for this camera device, this will contain
- * only OFF. If the hotpixel map is available, this should include both
+ * only OFF. If the hotpixel map is available, this will include both
* the ON and OFF options.</p>
*
* @see CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 90e5e4e..33e1915 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -157,8 +157,8 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>The lens focus distance is not accurate, and the units used for
- * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.
- * Setting the lens to the same focus distance on separate occasions may
+ * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.</p>
+ * <p>Setting the lens to the same focus distance on separate occasions may
* result in a different real focus distance, depending on factors such
* as the orientation of the device, the age of the focusing mechanism,
* and the device temperature. The focus distance value will still be
@@ -172,20 +172,24 @@ public abstract class CameraMetadata<TKey> {
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0;
/**
- * <p>The lens focus distance is measured in diopters. However, setting the lens
- * to the same focus distance on separate occasions may result in a
- * different real focus distance, depending on factors such as the
- * orientation of the device, the age of the focusing mechanism, and
- * the device temperature.</p>
+ * <p>The lens focus distance is measured in diopters.</p>
+ * <p>However, setting the lens to the same focus distance
+ * on separate occasions may result in a different real
+ * focus distance, depending on factors such as the
+ * orientation of the device, the age of the focusing
+ * mechanism, and the device temperature.</p>
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1;
/**
- * <p>The lens focus distance is measured in diopters. The lens mechanism is
- * calibrated so that setting the same focus distance is repeatable on
- * multiple occasions with good accuracy, and the focus distance corresponds
- * to the real physical distance to the plane of best focus.</p>
+ * <p>The lens focus distance is measured in diopters, and
+ * is calibrated.</p>
+ * <p>The lens mechanism is calibrated so that setting the
+ * same focus distance is repeatable on multiple
+ * occasions with good accuracy, and the focus distance
+ * corresponds to the real physical distance to the plane
+ * of best focus.</p>
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2;
@@ -195,11 +199,13 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>The camera device faces the same direction as the device's screen.</p>
* @see CameraCharacteristics#LENS_FACING
*/
public static final int LENS_FACING_FRONT = 0;
/**
+ * <p>The camera device faces the opposite direction as the device's screen.</p>
* @see CameraCharacteristics#LENS_FACING
*/
public static final int LENS_FACING_BACK = 1;
@@ -215,11 +221,10 @@ public abstract class CameraMetadata<TKey> {
* <p>The full set of features supported by this capability makes
* the camera2 api backwards compatible with the camera1
* (android.hardware.Camera) API.</p>
- * <p>TODO: @hide this. Doesn't really mean anything except
- * act as a catch-all for all the 'base' functionality.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0;
@@ -228,15 +233,14 @@ public abstract class CameraMetadata<TKey> {
* tags or functionality not encapsulated by one of the other
* capabilities.</p>
* <p>A typical example is all tags marked 'optional'.</p>
- * <p>TODO: @hide. We may not need this if we @hide all the optional
- * tags not belonging to a capability.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL = 1;
/**
* <p>The camera device can be manually controlled (3A algorithms such
- * as auto exposure, and auto focus can be bypassed).
+ * as auto-exposure, and auto-focus can be bypassed).
* The camera device supports basic manual control of the sensor image
* acquisition related stages. This means the following controls are
* guaranteed to be supported:</p>
@@ -257,11 +261,11 @@ public abstract class CameraMetadata<TKey> {
* <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
* </ul>
* </li>
- * <li>Manual lens control<ul>
+ * <li>Manual lens control (if the lens is adjustable)<ul>
* <li>android.lens.*</li>
* </ul>
* </li>
- * <li>Manual flash control<ul>
+ * <li>Manual flash control (if a flash unit is present)<ul>
* <li>android.flash.*</li>
* </ul>
* </li>
@@ -312,8 +316,6 @@ public abstract class CameraMetadata<TKey> {
* </ul>
* <p>If auto white balance is enabled, then the camera device
* will accurately report the values applied by AWB in the result.</p>
- * <p>The camera device will also support everything in MANUAL_SENSOR
- * except manual lens control and manual flash control.</p>
* <p>A given camera device may also support additional post-processing
* controls, but this capability only covers the above list of controls.</p>
*
@@ -340,8 +342,8 @@ public abstract class CameraMetadata<TKey> {
* (both input/output) will match the maximum available
* resolution of JPEG streams.</li>
* </ul>
- * <p>@hide this, TODO: remove it when input related APIs are ready.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
@@ -355,7 +357,7 @@ public abstract class CameraMetadata<TKey> {
* <li>RAW16 is reprocessable into both YUV_420_888 and JPEG
* formats.</li>
* <li>The maximum available resolution for RAW16 streams (both
- * input/output) will match the either value in
+ * input/output) will match either the value in
* {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li>
* <li>All DNG-related optional metadata entries are provided
@@ -373,13 +375,13 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>The camera device will only support centered crop regions.</p>
+ * <p>The camera device only supports centered crop regions.</p>
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
*/
public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0;
/**
- * <p>The camera device will support arbitrarily chosen crop regions.</p>
+ * <p>The camera device supports arbitrarily chosen crop regions.</p>
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
*/
public static final int SCALER_CROPPING_TYPE_FREEFORM = 1;
@@ -525,7 +527,7 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>android.led.transmit control is used</p>
+ * <p>android.led.transmit control is used.</p>
* @see CameraCharacteristics#LED_AVAILABLE_LEDS
* @hide
*/
@@ -536,11 +538,14 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>This camera device has only limited capabilities.</p>
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
/**
+ * <p>This camera device is capable of supporting advanced imaging
+ * applications.</p>
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
@@ -550,9 +555,9 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>Every frame has the requests immediately applied.
- * (and furthermore for all results,
- * <code>android.sync.frameNumber == android.request.frameCount</code>)</p>
+ * <p>Every frame has the requests immediately applied.</p>
+ * <p>Furthermore for all results,
+ * <code>android.sync.frameNumber == android.request.frameCount</code></p>
* <p>Changing controls over multiple requests one after another will
* produce results that have those controls applied atomically
* each frame.</p>
@@ -592,8 +597,8 @@ public abstract class CameraMetadata<TKey> {
public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0;
/**
- * <p>Must not slow down capture rate relative to sensor raw
- * output.</p>
+ * <p>Color correction processing must not slow down
+ * capture rate relative to sensor raw output.</p>
* <p>Advanced white balance adjustments above and beyond
* the specified white balance pipeline may be applied.</p>
* <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -606,8 +611,9 @@ public abstract class CameraMetadata<TKey> {
public static final int COLOR_CORRECTION_MODE_FAST = 1;
/**
- * <p>Capture rate (relative to sensor raw output)
- * may be reduced by high quality.</p>
+ * <p>Color correction processing operates at improved
+ * quality but reduced capture rate (relative to sensor raw
+ * output).</p>
* <p>Advanced white balance adjustments above and beyond
* the specified white balance pipeline may be applied.</p>
* <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -658,8 +664,8 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>The camera device's autoexposure routine is disabled;
- * the application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
+ * <p>The camera device's autoexposure routine is disabled.</p>
+ * <p>The application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
* {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} and
* {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are used by the camera
* device, along with android.flash.* fields, if there's
@@ -674,7 +680,8 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>The camera device's autoexposure routine is active,
- * with no flash control. The application's values for
+ * with no flash control.</p>
+ * <p>The application's values for
* {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
* {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and
* {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are ignored. The
@@ -691,10 +698,10 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Like ON, except that the camera device also controls
* the camera's flash unit, firing it in low-light
- * conditions. The flash may be fired during a
- * precapture sequence (triggered by
- * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and may be fired
- * for captures for which the
+ * conditions.</p>
+ * <p>The flash may be fired during a precapture sequence
+ * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+ * may be fired for captures for which the
* {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
* STILL_CAPTURE</p>
*
@@ -707,10 +714,10 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Like ON, except that the camera device also controls
* the camera's flash unit, always firing it for still
- * captures. The flash may be fired during a precapture
- * sequence (triggered by
- * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and will always
- * be fired for captures for which the
+ * captures.</p>
+ * <p>The flash may be fired during a precapture sequence
+ * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+ * will always be fired for captures for which the
* {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
* STILL_CAPTURE</p>
*
@@ -722,9 +729,10 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Like ON_AUTO_FLASH, but with automatic red eye
- * reduction. If deemed necessary by the camera device,
- * a red eye reduction flash will fire during the
- * precapture sequence.</p>
+ * reduction.</p>
+ * <p>If deemed necessary by the camera device, a red eye
+ * reduction flash will fire during the precapture
+ * sequence.</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
@@ -741,8 +749,9 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>The precapture metering sequence will be started
- * by the camera device. The exact effect of the precapture
- * trigger depends on the current AE mode and state.</p>
+ * by the camera device.</p>
+ * <p>The exact effect of the precapture trigger depends on
+ * the current AE mode and state.</p>
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
*/
public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
@@ -754,7 +763,7 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>The auto-focus routine does not control the lens;
* {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} is controlled by the
- * application</p>
+ * application.</p>
*
* @see CaptureRequest#LENS_FOCUS_DISTANCE
* @see CaptureRequest#CONTROL_AF_MODE
@@ -839,8 +848,11 @@ public abstract class CameraMetadata<TKey> {
public static final int CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4;
/**
- * <p>Extended depth of field (digital focus). AF
- * trigger is ignored, AF state should always be
+ * <p>Extended depth of field (digital focus) mode.</p>
+ * <p>The camera device will produce images with an extended
+ * depth of field automatically; no special focusing
+ * operations need to be done before taking a picture.</p>
+ * <p>AF triggers are ignored, and the AF state will always be
* INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
@@ -874,8 +886,8 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>The camera device's auto white balance routine is disabled;
- * the application-selected color transform matrix
+ * <p>The camera device's auto-white balance routine is disabled.</p>
+ * <p>The application-selected color transform matrix
* ({@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}) and gains
* ({@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}) are used by the camera
* device for manual white balance control.</p>
@@ -887,9 +899,12 @@ public abstract class CameraMetadata<TKey> {
public static final int CONTROL_AWB_MODE_OFF = 0;
/**
- * <p>The camera device's auto white balance routine is active;
- * the application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
- * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.</p>
+ * <p>The camera device's auto-white balance routine is active.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
@@ -898,65 +913,125 @@ public abstract class CameraMetadata<TKey> {
public static final int CONTROL_AWB_MODE_AUTO = 1;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses incandescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant A.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant A.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_INCANDESCENT = 2;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses fluorescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant F2.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant F2.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_FLUORESCENT = 3;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses warm fluorescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant F4.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant F4.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_WARM_FLUORESCENT = 4;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses daylight light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant D65.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant D65.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_DAYLIGHT = 5;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses cloudy daylight light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses twilight light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_TWILIGHT = 7;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses shade light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_SHADE = 8;
@@ -966,38 +1041,43 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>This request doesn't fall into the other
- * categories. Default to preview-like
+ * <p>The goal of this request doesn't fall into the other
+ * categories. The camera device will default to preview-like
* behavior.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0;
/**
- * <p>This request is for a preview-like usecase. The
- * precapture trigger may be used to start off a metering
- * w/flash sequence</p>
+ * <p>This request is for a preview-like use case.</p>
+ * <p>The precapture trigger may be used to start off a metering
+ * w/flash sequence.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1;
/**
* <p>This request is for a still capture-type
- * usecase.</p>
+ * use case.</p>
+ * <p>If the flash unit is under automatic control, it may fire as needed.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2;
/**
* <p>This request is for a video recording
- * usecase.</p>
+ * use case.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3;
/**
* <p>This request is for a video snapshot (still
- * image while recording video) usecase</p>
+ * image while recording video) use case.</p>
+ * <p>The camera device should take the highest-quality image
+ * possible (given the other settings) without disrupting the
+ * frame rate of video recording.<br />
+ * </p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
@@ -1006,15 +1086,16 @@ public abstract class CameraMetadata<TKey> {
* <p>This request is for a ZSL usecase; the
* application will stream full-resolution images and
* reprocess one or several later for a final
- * capture</p>
+ * capture.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5;
/**
* <p>This request is for manual capture use case where
- * the applications want to directly control the capture parameters
- * (e.g. {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} etc.).</p>
+ * the applications want to directly control the capture parameters.</p>
+ * <p>For example, the application may wish to manually control
+ * {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, etc.</p>
*
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
* @see CaptureRequest#SENSOR_SENSITIVITY
@@ -1034,7 +1115,8 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>A "monocolor" effect where the image is mapped into
- * a single color. This will typically be grayscale.</p>
+ * a single color.</p>
+ * <p>This will typically be grayscale.</p>
* @see CaptureRequest#CONTROL_EFFECT_MODE
*/
public static final int CONTROL_EFFECT_MODE_MONO = 1;
@@ -1094,31 +1176,42 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>Full application control of pipeline. All 3A
- * routines are disabled, no other settings in
- * android.control.* have any effect</p>
+ * <p>Full application control of pipeline.</p>
+ * <p>All control by the device's metering and focusing (3A)
+ * routines is disabled, and no other settings in
+ * android.control.* have any effect, except that
+ * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} may be used by the camera
+ * device to select post-processing values for processing
+ * blocks that do not allow for manual control, or are not
+ * exposed by the camera API.</p>
+ * <p>However, the camera device's 3A routines may continue to
+ * collect statistics and update their internal state so that
+ * when control is switched to AUTO mode, good control values
+ * can be immediately applied.</p>
+ *
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF = 0;
/**
- * <p>Use settings for each individual 3A routine.
- * Manual control of capture parameters is disabled. All
+ * <p>Use settings for each individual 3A routine.</p>
+ * <p>Manual control of capture parameters is disabled. All
* controls in android.control.* besides sceneMode take
- * effect</p>
+ * effect.</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_AUTO = 1;
/**
- * <p>Use specific scene mode. Enabling this disables
- * control.aeMode, control.awbMode and control.afMode
- * controls; the camera device will ignore those settings while
- * USE_SCENE_MODE is active (except for FACE_PRIORITY
- * scene mode). Other control entries are still active.
- * This setting can only be used if scene mode is supported
- * (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes} contain some modes
- * other than DISABLED).</p>
+ * <p>Use a specific scene mode.</p>
+ * <p>Enabling this disables control.aeMode, control.awbMode and
+ * control.afMode controls; the camera device will ignore
+ * those settings while USE_SCENE_MODE is active (except for
+ * FACE_PRIORITY scene mode). Other control entries are still
+ * active. This setting can only be used if scene mode is
+ * supported (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}
+ * contain some modes other than DISABLED).</p>
*
* @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_MODE
@@ -1128,7 +1221,12 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Same as OFF mode, except that this capture will not be
* used by camera device background auto-exposure, auto-white balance and
- * auto-focus algorithms to update their statistics.</p>
+ * auto-focus algorithms (3A) to update their statistics.</p>
+ * <p>Specifically, the 3A routines are locked to the last
+ * values set from a request with AUTO, OFF, or
+ * USE_SCENE_MODE, and any statistics or state updates
+ * collected from manual captures with OFF_KEEP_STATE will be
+ * discarded by the camera device.</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF_KEEP_STATE = 3;
@@ -1146,8 +1244,9 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>If face detection support exists, use face
* detection data for auto-focus, auto-white balance, and
- * auto-exposure routines. If face detection statistics are
- * disabled (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
+ * auto-exposure routines.</p>
+ * <p>If face detection statistics are disabled
+ * (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
* this should still operate correctly (but will not return
* face detection statistics to the framework).</p>
* <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
@@ -1163,8 +1262,8 @@ public abstract class CameraMetadata<TKey> {
public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1;
/**
- * <p>Optimized for photos of quickly moving objects.
- * Similar to SPORTS.</p>
+ * <p>Optimized for photos of quickly moving objects.</p>
+ * <p>Similar to SPORTS.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_ACTION = 2;
@@ -1233,8 +1332,8 @@ public abstract class CameraMetadata<TKey> {
public static final int CONTROL_SCENE_MODE_FIREWORKS = 12;
/**
- * <p>Optimized for photos of quickly moving people.
- * Similar to ACTION.</p>
+ * <p>Optimized for photos of quickly moving people.</p>
+ * <p>Similar to ACTION.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_SPORTS = 13;
@@ -1266,11 +1365,13 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>Video stabilization is disabled.</p>
* @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
*/
public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0;
/**
+ * <p>Video stabilization is enabled.</p>
* @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
*/
public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
@@ -1280,21 +1381,20 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>No edge enhancement is applied</p>
+ * <p>No edge enhancement is applied.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor
+ * <p>Apply edge enhancement at a quality level that does not slow down frame rate relative to sensor
* output</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_FAST = 1;
/**
- * <p>Frame rate may be reduced by high
- * quality</p>
+ * <p>Apply high-quality edge enhancement, at a cost of reducing output frame rate.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_HIGH_QUALITY = 2;
@@ -1327,10 +1427,10 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>No hot pixel correction is applied.</p>
* <p>The frame rate must not be reduced relative to sensor raw output
* for this option.</p>
- * <p>No hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1338,10 +1438,9 @@ public abstract class CameraMetadata<TKey> {
public static final int HOT_PIXEL_MODE_OFF = 0;
/**
- * <p>The frame rate must not be reduced relative to sensor raw output
- * for this option.</p>
- * <p>Hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>Hot pixel correction is applied, without reducing frame
+ * rate relative to sensor raw output.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1349,10 +1448,9 @@ public abstract class CameraMetadata<TKey> {
public static final int HOT_PIXEL_MODE_FAST = 1;
/**
- * <p>The frame rate may be reduced relative to sensor raw output
- * for this option.</p>
- * <p>A high-quality hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>High-quality hot pixel correction is applied, at a cost
+ * of reducing frame rate relative to sensor raw output.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1380,21 +1478,21 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>No noise reduction is applied</p>
+ * <p>No noise reduction is applied.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor
- * output</p>
+ * <p>Noise reduction is applied without reducing frame rate relative to sensor
+ * output.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_FAST = 1;
/**
- * <p>May slow down frame rate to provide highest
- * quality</p>
+ * <p>High-quality noise reduction is applied, at the cost of reducing frame rate
+ * relative to sensor output.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
@@ -1404,8 +1502,9 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>Default. No test pattern mode is used, and the camera
+ * <p>No test pattern mode is used, and the camera
* device returns captures from the image sensor.</p>
+ * <p>This is the default if the key is not set.</p>
* @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
*/
public static final int SENSOR_TEST_PATTERN_MODE_OFF = 0;
@@ -1509,19 +1608,21 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>No lens shading correction is applied</p>
+ * <p>No lens shading correction is applied.</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor raw output</p>
+ * <p>Apply lens shading corrections, without slowing
+ * frame rate relative to sensor raw output</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_FAST = 1;
/**
- * <p>Frame rate may be reduced by high quality</p>
+ * <p>Apply high-quality lens shading correction, at the
+ * cost of reduced frame rate.</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_HIGH_QUALITY = 2;
@@ -1531,20 +1632,28 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>Do not include face detection statistics in capture
+ * results.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0;
/**
- * <p>Optional Return rectangle and confidence
- * only</p>
+ * <p>Return face rectangle and confidence values only.</p>
+ * <p>In this mode, only android.statistics.faceRectangles and
+ * android.statistics.faceScores outputs are valid.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1;
/**
- * <p>Optional Return all face
- * metadata</p>
+ * <p>Return all face
+ * metadata.</p>
+ * <p>In this mode,
+ * android.statistics.faceRectangles,
+ * android.statistics.faceScores,
+ * android.statistics.faceIds, and
+ * android.statistics.faceLandmarks outputs are valid.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
@@ -1554,11 +1663,13 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>Do not include a lens shading map in the capture result.</p>
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
*/
public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0;
/**
+ * <p>Include a lens shading map in the capture result.</p>
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
*/
public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
@@ -1582,15 +1693,15 @@ public abstract class CameraMetadata<TKey> {
public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
/**
- * <p>Advanced gamma mapping and color enhancement may be applied.</p>
- * <p>Should not slow down frame rate relative to raw sensor output.</p>
+ * <p>Advanced gamma mapping and color enhancement may be applied, without
+ * reducing frame rate compared to raw sensor output.</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_FAST = 1;
/**
- * <p>Advanced gamma mapping and color enhancement may be applied.</p>
- * <p>May slow down frame rate relative to raw sensor output.</p>
+ * <p>High-quality gamma mapping and color enhancement will be applied, at
+ * the cost of reduced frame rate compared to raw sensor output.</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
@@ -1600,7 +1711,8 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>AE is off or recently reset. When a camera device is opened, it starts in
+ * <p>AE is off or recently reset.</p>
+ * <p>When a camera device is opened, it starts in
* this state. This is a transient state, the camera device may skip reporting
* this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
@@ -1609,7 +1721,8 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>AE doesn't yet have a good set of control values
- * for the current scene. This is a transient state, the camera device may skip
+ * for the current scene.</p>
+ * <p>This is a transient state, the camera device may skip
* reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
@@ -1638,11 +1751,13 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>AE has been asked to do a precapture sequence
- * (through the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} START),
- * and is currently executing it. Once PRECAPTURE
- * completes, AE will transition to CONVERGED or
- * FLASH_REQUIRED as appropriate. This is a transient state, the
- * camera device may skip reporting this state in capture result.</p>
+ * and is currently executing it.</p>
+ * <p>Precapture can be triggered through setting
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START.</p>
+ * <p>Once PRECAPTURE completes, AE will transition to CONVERGED
+ * or FLASH_REQUIRED as appropriate. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
*
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CaptureResult#CONTROL_AE_STATE
@@ -1654,61 +1769,78 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>AF off or has not yet tried to scan/been asked
- * to scan. When a camera device is opened, it starts in
- * this state. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AF is off or has not yet tried to scan/been asked
+ * to scan.</p>
+ * <p>When a camera device is opened, it starts in this
+ * state. This is a transient state, the camera device may
+ * skip reporting this state in capture
+ * result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_INACTIVE = 0;
/**
- * <p>if CONTINUOUS_* modes are supported. AF is
- * currently doing an AF scan initiated by a continuous
- * autofocus mode. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AF is currently performing an AF scan initiated the
+ * camera device in a continuous autofocus mode.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1;
/**
- * <p>if CONTINUOUS_* modes are supported. AF currently
- * believes it is in focus, but may restart scanning at
- * any time. This is a transient state, the camera device may skip
- * reporting this state in capture result.</p>
+ * <p>AF currently believes it is in focus, but may
+ * restart scanning at any time.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2;
/**
- * <p>if AUTO or MACRO modes are supported. AF is doing
- * an AF scan because it was triggered by AF trigger. This is a
- * transient state, the camera device may skip reporting
- * this state in capture result.</p>
+ * <p>AF is performing an AF scan because it was
+ * triggered by AF trigger.</p>
+ * <p>Only used by AUTO or MACRO AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3;
/**
- * <p>if any AF mode besides OFF is supported. AF
- * believes it is focused correctly and is
- * locked.</p>
+ * <p>AF believes it is focused correctly and has locked
+ * focus.</p>
+ * <p>This state is reached only after an explicit START AF trigger has been
+ * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus has been obtained.</p>
+ * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+ * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AF_TRIGGER
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4;
/**
- * <p>if any AF mode besides OFF is supported. AF has
- * failed to focus successfully and is
- * locked.</p>
+ * <p>AF has failed to focus successfully and has locked
+ * focus.</p>
+ * <p>This state is reached only after an explicit START AF trigger has been
+ * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus cannot be obtained.</p>
+ * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+ * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AF_TRIGGER
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5;
/**
- * <p>if CONTINUOUS_* modes are supported. AF finished a
- * passive scan without finding focus, and may restart
- * scanning at any time. This is a transient state, the camera
+ * <p>AF finished a passive scan without finding focus,
+ * and may restart scanning at any time.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient state, the camera
* device may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
@@ -1719,16 +1851,19 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>AWB is not in auto mode. When a camera device is opened, it
- * starts in this state. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AWB is not in auto mode, or has not yet started metering.</p>
+ * <p>When a camera device is opened, it starts in this
+ * state. This is a transient state, the camera device may
+ * skip reporting this state in capture
+ * result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_INACTIVE = 0;
/**
* <p>AWB doesn't yet have a good set of control
- * values for the current scene. This is a transient state, the camera device
+ * values for the current scene.</p>
+ * <p>This is a transient state, the camera device
* may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
@@ -1776,8 +1911,9 @@ public abstract class CameraMetadata<TKey> {
public static final int FLASH_STATE_FIRED = 3;
/**
- * <p>Flash partially illuminated this frame. This is usually due to the next
- * or previous frame having the flash fire, and the flash spilling into this capture
+ * <p>Flash partially illuminated this frame.</p>
+ * <p>This is usually due to the next or previous frame having
+ * the flash fire, and the flash spilling into this capture
* due to hardware limitations.</p>
* @see CaptureResult#FLASH_STATE
*/
@@ -1800,8 +1936,10 @@ public abstract class CameraMetadata<TKey> {
public static final int LENS_STATE_STATIONARY = 0;
/**
- * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
- * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+ * <p>One or several of the lens parameters
+ * ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+ * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is
+ * currently changing.</p>
*
* @see CaptureRequest#LENS_APERTURE
* @see CaptureRequest#LENS_FILTER_DENSITY
@@ -1816,16 +1954,22 @@ public abstract class CameraMetadata<TKey> {
//
/**
+ * <p>The camera device does not detect any flickering illumination
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_NONE = 0;
/**
+ * <p>The camera device detects illumination flickering at 50Hz
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_50HZ = 1;
/**
+ * <p>The camera device detects illumination flickering at 60Hz
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_60HZ = 2;
@@ -1835,8 +1979,8 @@ public abstract class CameraMetadata<TKey> {
//
/**
- * <p>The current result is not yet fully synchronized to any request.
- * Synchronization is in progress, and reading metadata from this
+ * <p>The current result is not yet fully synchronized to any request.</p>
+ * <p>Synchronization is in progress, and reading metadata from this
* result may include a mix of data that have taken effect since the
* last synchronization time.</p>
* <p>In some future result, within {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} frames,
@@ -1851,10 +1995,10 @@ public abstract class CameraMetadata<TKey> {
public static final int SYNC_FRAME_NUMBER_CONVERGING = -1;
/**
- * <p>The current result's synchronization status is unknown. The
- * result may have already converged, or it may be in progress.
- * Reading from this result may include some mix of settings from
- * past requests.</p>
+ * <p>The current result's synchronization status is unknown.</p>
+ * <p>The result may have already converged, or it may be in
+ * progress. Reading from this result may include some mix
+ * of settings from past requests.</p>
* <p>After a settings change, the new settings will eventually all
* take effect for the output buffers and results. However, this
* value will not change when that happens. Altering settings
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 0ff8cce..bf7bd37 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -733,8 +733,16 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* 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 auto-exposure (AE) precapture trigger depends
- * on the current AE mode and state; see
+ * <p>The precapture sequence should triggered before starting a
+ * high-quality still capture for final metering decisions to
+ * be made, and for firing pre-capture flash pulses to estimate
+ * scene brightness and required final capture flash power, when
+ * the flash is enabled.</p>
+ * <p>Normally, this entry should be set to START for only a
+ * single request, and the application should wait until the
+ * sequence completes before starting a new one.</p>
+ * <p>The exact effect of auto-exposure (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>
*
@@ -800,7 +808,11 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* 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>
+ * <p>Generally, applications should set this entry to START or CANCEL for only a
+ * single capture, and then return it to IDLE (or not set at all). Specifying
+ * START for multiple captures in a row means restarting the AF operation over
+ * and over again.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see #CONTROL_AF_TRIGGER_IDLE
@@ -813,9 +825,11 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Whether auto-white balance (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>
+ * <p>Note that AWB lock is only meaningful when
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+ * AWB is already fixed to a specific setting.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
@@ -825,17 +839,21 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* transform fields, and what its illumination target
* is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
- * <p>When set to the ON mode, the camera device's auto white balance
+ * <p>When set to the ON mode, the camera device's auto-white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to the OFF mode, the camera device's auto white balance
+ * <p>When set to the OFF mode, the camera device's auto-white balance
* routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to any other modes, the camera device's auto white balance
- * routine is disabled. The camera device uses each particular illumination
- * target for white balance adjustment.</p>
+ * <p>When set to any other modes, the camera device's auto-white
+ * balance routine is disabled. The camera device uses each
+ * particular illumination target for white balance
+ * adjustment. The application's values for
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+ * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -886,8 +904,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* 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}
+ * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* contains MANUAL_SENSOR.</p>
*
* @see CaptureRequest#CONTROL_MODE
@@ -962,7 +980,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <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>
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+ * The scene modes available for a given camera device are listed in
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</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
@@ -970,6 +990,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AF_MODE
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CaptureRequest#CONTROL_MODE
* @see #CONTROL_SCENE_MODE_DISABLED
@@ -996,6 +1017,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Whether video stabilization is
* active.</p>
+ * <p>Video stabilization automatically translates and scales images from the camera
+ * in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
* stabilized</p>
@@ -1110,14 +1133,14 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Compression quality of the final JPEG
* image.</p>
- * <p>85-95 is typical usage range</p>
+ * <p>85-95 is typical usage range.</p>
*/
public static final Key<Byte> JPEG_QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
/**
* <p>Compression quality of JPEG
- * thumbnail</p>
+ * thumbnail.</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
@@ -1229,12 +1252,18 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Sets whether the camera device uses optical image stabilization (OIS)
* when capturing images.</p>
- * <p>OIS is used to compensate for motion blur due to small movements of
- * the camera during capture. Unlike digital image stabilization, OIS makes
- * use of mechanical elements to stabilize the camera sensor, and thus
- * allows for longer exposure times before camera shake becomes
- * apparent.</p>
- * <p>This is not expected to be supported on most devices.</p>
+ * <p>OIS is used to compensate for motion blur due to small
+ * movements of the camera during capture. Unlike digital image
+ * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+ * makes use of mechanical elements to stabilize the camera
+ * sensor, and thus allows for longer exposure times before
+ * camera shake becomes apparent.</p>
+ * <p>Not all devices will support OIS; see
+ * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+ * available controls.</p>
+ *
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -1242,16 +1271,15 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
/**
- * <p>Mode of operation for the noise reduction.
- * algorithm</p>
+ * <p>Mode of operation for the noise reduction algorithm.</p>
* <p>Noise filtering control. OFF means no noise reduction
* will be applied by the camera device.</p>
- * <p>This must be set to a valid mode in
+ * <p>This must be set to a valid mode from
* {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
- * even if it slows down capture rate. FAST means the camera device should not
+ * even if it slows down capture rate. FAST means the camera device will not
* slow down capture rate when applying noise filtering.</p>
*
* @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -1435,7 +1463,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <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
- * by android.sensor.* should be ignored. All other controls should
+ * by android.sensor.* will be ignored. All other controls should
* work as normal.</p>
* <p>For example, if manual flash is enabled, flash firing should still
* occur (and that the test pattern remain unmodified, since the flash
@@ -1490,7 +1518,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
new Key<Integer>("android.shading.mode", int.class);
/**
- * <p>State of the face detector
+ * <p>Control for the face detector
* unit.</p>
* <p>Whether face detection is enabled, and whether it
* should output just the basic fields or the full set of
@@ -1508,7 +1536,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Operating mode for hotpixel map generation.</p>
* <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
- * If set to OFF, no hotpixel map should be returned.</p>
+ * If set to OFF, no hotpixel map will be returned.</p>
* <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -1521,7 +1549,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>Whether the camera device will output the lens
* shading map in output result metadata.</p>
* <p>When set to ON,
- * android.statistics.lensShadingMap must be provided in
+ * android.statistics.lensShadingMap will be provided in
* the output result metadata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ce3de1d..3d17ed3 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -579,8 +579,16 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* 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 auto-exposure (AE) precapture trigger depends
- * on the current AE mode and state; see
+ * <p>The precapture sequence should triggered before starting a
+ * high-quality still capture for final metering decisions to
+ * be made, and for firing pre-capture flash pulses to estimate
+ * scene brightness and required final capture flash power, when
+ * the flash is enabled.</p>
+ * <p>Normally, this entry should be set to START for only a
+ * single request, and the application should wait until the
+ * sequence completes before starting a new one.</p>
+ * <p>The exact effect of auto-exposure (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>
*
@@ -592,7 +600,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
/**
- * <p>Current state of auto-exposure (AE) algorithm.</p>
+ * <p>Current state of the auto-exposure (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},
* or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -844,7 +852,11 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* 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>
+ * <p>Generally, applications should set this entry to START or CANCEL for only a
+ * single capture, and then return it to IDLE (or not set at all). Specifying
+ * START for multiple captures in a row means restarting the AF operation over
+ * and over again.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see #CONTROL_AF_TRIGGER_IDLE
@@ -1034,13 +1046,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. If focus is good, Lens now locked</td>
+ * <td align="center">Immediate transition, if focus is good. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. if focus is bad, Lens now locked</td>
+ * <td align="center">Immediate transition, if focus is bad. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
@@ -1064,13 +1076,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <td align="center">PASSIVE_FOCUSED</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td align="center">Immediate transition, lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_UNFOCUSED</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td align="center">Immediate transition, lens now locked</td>
* </tr>
* <tr>
* <td align="center">FOCUSED_LOCKED</td>
@@ -1137,13 +1149,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Eventual trans. once focus good, Lens now locked</td>
+ * <td align="center">Eventual transition once the focus is good. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Eventual trans. if cannot focus, Lens now locked</td>
+ * <td align="center">Eventual transition if cannot find focus. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
@@ -1254,9 +1266,11 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Whether auto-white balance (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>
+ * <p>Note that AWB lock is only meaningful when
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+ * AWB is already fixed to a specific setting.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
@@ -1266,17 +1280,21 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* transform fields, and what its illumination target
* is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
- * <p>When set to the ON mode, the camera device's auto white balance
+ * <p>When set to the ON mode, the camera device's auto-white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to the OFF mode, the camera device's auto white balance
+ * <p>When set to the OFF mode, the camera device's auto-white balance
* routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to any other modes, the camera device's auto white balance
- * routine is disabled. The camera device uses each particular illumination
- * target for white balance adjustment.</p>
+ * <p>When set to any other modes, the camera device's auto-white
+ * balance routine is disabled. The camera device uses each
+ * particular illumination target for white balance
+ * adjustment. The application's values for
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+ * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -1327,8 +1345,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* 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}
+ * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* contains MANUAL_SENSOR.</p>
*
* @see CaptureRequest#CONTROL_MODE
@@ -1533,7 +1551,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <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>
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+ * The scene modes available for a given camera device are listed in
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</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
@@ -1541,6 +1561,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AF_MODE
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CaptureRequest#CONTROL_MODE
* @see #CONTROL_SCENE_MODE_DISABLED
@@ -1567,6 +1588,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Whether video stabilization is
* active.</p>
+ * <p>Video stabilization automatically translates and scales images from the camera
+ * in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
* stabilized</p>
@@ -1698,14 +1721,14 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Compression quality of the final JPEG
* image.</p>
- * <p>85-95 is typical usage range</p>
+ * <p>85-95 is typical usage range.</p>
*/
public static final Key<Byte> JPEG_QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
/**
* <p>Compression quality of JPEG
- * thumbnail</p>
+ * thumbnail.</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
@@ -1817,12 +1840,18 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Sets whether the camera device uses optical image stabilization (OIS)
* when capturing images.</p>
- * <p>OIS is used to compensate for motion blur due to small movements of
- * the camera during capture. Unlike digital image stabilization, OIS makes
- * use of mechanical elements to stabilize the camera sensor, and thus
- * allows for longer exposure times before camera shake becomes
- * apparent.</p>
- * <p>This is not expected to be supported on most devices.</p>
+ * <p>OIS is used to compensate for motion blur due to small
+ * movements of the camera during capture. Unlike digital image
+ * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+ * makes use of mechanical elements to stabilize the camera
+ * sensor, and thus allows for longer exposure times before
+ * camera shake becomes apparent.</p>
+ * <p>Not all devices will support OIS; see
+ * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+ * available controls.</p>
+ *
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -1866,16 +1895,15 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
new Key<Integer>("android.lens.state", int.class);
/**
- * <p>Mode of operation for the noise reduction.
- * algorithm</p>
+ * <p>Mode of operation for the noise reduction algorithm.</p>
* <p>Noise filtering control. OFF means no noise reduction
* will be applied by the camera device.</p>
- * <p>This must be set to a valid mode in
+ * <p>This must be set to a valid mode from
* {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
- * even if it slows down capture rate. FAST means the camera device should not
+ * even if it slows down capture rate. FAST means the camera device will not
* slow down capture rate when applying noise filtering.</p>
*
* @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -2170,7 +2198,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <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
- * by android.sensor.* should be ignored. All other controls should
+ * by android.sensor.* will be ignored. All other controls should
* work as normal.</p>
* <p>For example, if manual flash is enabled, flash firing should still
* occur (and that the test pattern remain unmodified, since the flash
@@ -2225,7 +2253,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
new Key<Integer>("android.shading.mode", int.class);
/**
- * <p>State of the face detector
+ * <p>Control for the face detector
* unit.</p>
* <p>Whether face detection is enabled, and whether it
* should output just the basic fields or the full set of
@@ -2241,9 +2269,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
new Key<Integer>("android.statistics.faceDetectMode", int.class);
/**
- * <p>List of unique IDs for detected
- * faces</p>
- * <p>Only available if faceDetectMode == FULL</p>
+ * <p>List of unique IDs for detected faces.</p>
+ * <p>Each detected face is given a unique ID that is valid for as long as the face is visible
+ * to the camera device. A face that leaves the field of view and later returns may be
+ * assigned a new ID.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<int[]> STATISTICS_FACE_IDS =
@@ -2251,8 +2283,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>List of landmarks for detected
- * faces</p>
- * <p>Only available if faceDetectMode == FULL</p>
+ * faces.</p>
+ * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<int[]> STATISTICS_FACE_LANDMARKS =
@@ -2260,8 +2297,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>List of the bounding rectangles for detected
- * faces</p>
- * <p>Only available if faceDetectMode != OFF</p>
+ * faces.</p>
+ * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<android.graphics.Rect[]> STATISTICS_FACE_RECTANGLES =
@@ -2270,8 +2312,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>List of the face confidence scores for
* detected faces</p>
- * <p>Only available if faceDetectMode != OFF. The value should be
- * meaningful (for example, setting 100 at all times is illegal).</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF.</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<byte[]> STATISTICS_FACE_SCORES =
@@ -2435,12 +2478,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* The camera device uses this entry to tell the application what the scene
* illuminant frequency is.</p>
* <p>When manual exposure control is enabled
- * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
- * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
- * application can ensure it selects exposure times that do not cause banding
- * issues by looking into this metadata field. See {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode}
- * for more details.</p>
- * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
+ * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} ==
+ * OFF</code>), the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't perform
+ * antibanding, and the application can ensure it selects
+ * exposure times that do not cause banding issues by looking
+ * into this metadata field. See
+ * {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} for more details.</p>
+ * <p>Reports NONE if there doesn't appear to be flickering illumination.</p>
*
* @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
* @see CaptureRequest#CONTROL_AE_MODE
@@ -2455,7 +2499,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>Operating mode for hotpixel map generation.</p>
* <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
- * If set to OFF, no hotpixel map should be returned.</p>
+ * If set to OFF, no hotpixel map will be returned.</p>
* <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -2483,7 +2527,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>Whether the camera device will output the lens
* shading map in output result metadata.</p>
* <p>When set to ON,
- * android.statistics.lensShadingMap must be provided in
+ * android.statistics.lensShadingMap will be provided in
* the output result metadata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index dd862b5..a6fc10f 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -30,7 +30,8 @@ import android.util.Size;
* Immutable class to store the available stream
* {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to set up
* {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
- * with {@link CameraDevice#createCaptureSession}. <!-- TODO: link to input stream configuration -->
+ * with {@link CameraDevice#createCaptureSession}.
+ * <!-- TODO: link to input stream configuration -->
*
* <p>This is the authoritative list for all input/output formats (and sizes respectively
* for that format) that are supported by a camera device.</p>
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index af27e1d..8b42bcd 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -361,7 +361,7 @@ public class RouteInfo implements Parcelable {
RouteInfo target = (RouteInfo) obj;
- return Objects.equals(mDestination, target.getDestination()) &&
+ return Objects.equals(mDestination, target.getDestinationLinkAddress()) &&
Objects.equals(mGateway, target.getGateway()) &&
Objects.equals(mInterface, target.getInterface());
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ae536c1..1001677 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6035,6 +6035,7 @@ public final class Settings {
/**
* Battery level [1-99] at which low power mode automatically turns on.
+ * If 0, it will not automatically turn on.
* @hide
*/
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index fd475cd..8bd0f4d 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -29,6 +29,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.ArrayMap;
import android.util.Log;
import java.util.List;
@@ -54,7 +55,7 @@ public abstract class NotificationListenerService extends Service {
+ "[" + getClass().getSimpleName() + "]";
private INotificationListenerWrapper mWrapper = null;
- private Ranking mRanking;
+ private RankingMap mRankingMap;
private INotificationManager mNoMan;
@@ -75,7 +76,43 @@ public abstract class NotificationListenerService extends Service {
* object as well as its identifying information (tag and id) and source
* (package name).
*/
- public abstract void onNotificationPosted(StatusBarNotification sbn);
+ public void onNotificationPosted(StatusBarNotification sbn) {
+ // optional
+ }
+
+ /**
+ * Implement this method to learn about new notifications as they are posted by apps.
+ *
+ * @param sbn A data structure encapsulating the original {@link android.app.Notification}
+ * object as well as its identifying information (tag and id) and source
+ * (package name).
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications, including the newly posted one.
+ */
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+ onNotificationPosted(sbn);
+ }
+
+ /**
+ * Implement this method to learn when notifications are removed.
+ * <P>
+ * This might occur because the user has dismissed the notification using system UI (or another
+ * notification listener) or because the app has withdrawn the notification.
+ * <P>
+ * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
+ * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
+ * fields such as {@link android.app.Notification#contentView} and
+ * {@link android.app.Notification#largeIcon}. However, all other fields on
+ * {@link StatusBarNotification}, sufficient to match this call with a prior call to
+ * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
+ *
+ * @param sbn A data structure encapsulating at least the original information (tag and id)
+ * and source (package name) used to post the {@link android.app.Notification} that
+ * was just removed.
+ */
+ public void onNotificationRemoved(StatusBarNotification sbn) {
+ // optional
+ }
/**
* Implement this method to learn when notifications are removed.
@@ -93,8 +130,13 @@ public abstract class NotificationListenerService extends Service {
* @param sbn A data structure encapsulating at least the original information (tag and id)
* and source (package name) used to post the {@link android.app.Notification} that
* was just removed.
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications.
+ *
*/
- public abstract void onNotificationRemoved(StatusBarNotification sbn);
+ public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+ onNotificationRemoved(sbn);
+ }
/**
* Implement this method to learn about when the listener is enabled and connected to
@@ -107,10 +149,11 @@ public abstract class NotificationListenerService extends Service {
/**
* Implement this method to be notified when the notification ranking changes.
- * <P>
- * Call {@link #getCurrentRanking()} to retrieve the new ranking.
+ *
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications.
*/
- public void onNotificationRankingUpdate() {
+ public void onNotificationRankingUpdate(RankingMap rankingMap) {
// optional
}
@@ -241,16 +284,19 @@ public abstract class NotificationListenerService extends Service {
*
* <p>
* The returned object represents the current ranking snapshot and only
- * applies for currently active notifications. Hence you must retrieve a
- * new Ranking after each notification event such as
- * {@link #onNotificationPosted(StatusBarNotification)},
- * {@link #onNotificationRemoved(StatusBarNotification)}, etc.
+ * applies for currently active notifications.
+ * <p>
+ * Generally you should use the RankingMap that is passed with events such
+ * as {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
+ * {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and
+ * so on. This method should only be used when needing access outside of
+ * such events, for example to retrieve the RankingMap right after
+ * initialization.
*
- * @return A {@link NotificationListenerService.Ranking} object providing
- * access to ranking information
+ * @return A {@link RankingMap} object providing access to ranking information
*/
- public Ranking getCurrentRanking() {
- return mRanking;
+ public RankingMap getCurrentRanking() {
+ return mRankingMap;
}
@Override
@@ -313,7 +359,7 @@ public abstract class NotificationListenerService extends Service {
synchronized (mWrapper) {
applyUpdate(update);
try {
- NotificationListenerService.this.onNotificationPosted(sbn);
+ NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationPosted", t);
}
@@ -326,7 +372,7 @@ public abstract class NotificationListenerService extends Service {
synchronized (mWrapper) {
applyUpdate(update);
try {
- NotificationListenerService.this.onNotificationRemoved(sbn);
+ NotificationListenerService.this.onNotificationRemoved(sbn, mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRemoved", t);
}
@@ -351,7 +397,7 @@ public abstract class NotificationListenerService extends Service {
synchronized (mWrapper) {
applyUpdate(update);
try {
- NotificationListenerService.this.onNotificationRankingUpdate();
+ NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRankingUpdate", t);
}
@@ -360,7 +406,65 @@ public abstract class NotificationListenerService extends Service {
}
private void applyUpdate(NotificationRankingUpdate update) {
- mRanking = new Ranking(update);
+ mRankingMap = new RankingMap(update);
+ }
+
+ /**
+ * Provides access to ranking information on a currently active
+ * notification.
+ *
+ * <p>
+ * Note that this object is not updated on notification events (such as
+ * {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
+ * {@link #onNotificationRemoved(StatusBarNotification)}, etc.). Make sure
+ * to retrieve a new Ranking from the current {@link RankingMap} whenever
+ * a notification event occurs.
+ */
+ public static class Ranking {
+ private final String mKey;
+ private final int mRank;
+ private final boolean mIsAmbient;
+ private final boolean mIsInterceptedByDnd;
+
+ private Ranking(String key, int rank, boolean isAmbient, boolean isInterceptedByDnd) {
+ mKey = key;
+ mRank = rank;
+ mIsAmbient = isAmbient;
+ mIsInterceptedByDnd = isInterceptedByDnd;
+ }
+
+ /**
+ * Returns the key of the notification this Ranking applies to.
+ */
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * Returns the rank of the notification.
+ *
+ * @return the rank of the notification, that is the 0-based index in
+ * the list of active notifications.
+ */
+ public int getRank() {
+ return mRank;
+ }
+
+ /**
+ * Returns whether the notification is an ambient notification, that is
+ * a notification that doesn't require the user's immediate attention.
+ */
+ public boolean isAmbient() {
+ return mIsAmbient;
+ }
+
+ /**
+ * Returns whether the notification was intercepted by
+ * &quot;Do not disturb&quot;.
+ */
+ public boolean isInterceptedByDoNotDisturb() {
+ return mIsInterceptedByDnd;
+ }
}
/**
@@ -371,11 +475,14 @@ public abstract class NotificationListenerService extends Service {
* Note that this object represents a ranking snapshot that only applies to
* notifications active at the time of retrieval.
*/
- public static class Ranking implements Parcelable {
+ public static class RankingMap implements Parcelable {
private final NotificationRankingUpdate mRankingUpdate;
+ private final ArrayMap<String, Ranking> mRankingCache;
+ private boolean mRankingCacheInitialized;
- private Ranking(NotificationRankingUpdate rankingUpdate) {
+ private RankingMap(NotificationRankingUpdate rankingUpdate) {
mRankingUpdate = rankingUpdate;
+ mRankingCache = new ArrayMap<>(rankingUpdate.getOrderedKeys().length);
}
/**
@@ -389,56 +496,37 @@ public abstract class NotificationListenerService extends Service {
}
/**
- * Returns the rank of the notification with the given key, that is the
- * index of <code>key</code> in the array of keys returned by
- * {@link #getOrderedKeys()}.
+ * Returns the Ranking for the notification with the given key.
*
- * @return The rank of the notification with the given key; -1 when the
- * given key is unknown.
+ * @return the Ranking of the notification with the given key;
+ * <code>null</code> when the key is unknown.
*/
- public int getRank(String key) {
- // TODO: Optimize.
- String[] orderedKeys = mRankingUpdate.getOrderedKeys();
- for (int i = 0; i < orderedKeys.length; i++) {
- if (orderedKeys[i].equals(key)) {
- return i;
+ public Ranking getRanking(String key) {
+ synchronized (mRankingCache) {
+ if (!mRankingCacheInitialized) {
+ initializeRankingCache();
+ mRankingCacheInitialized = true;
}
}
- return -1;
+ return mRankingCache.get(key);
}
- /**
- * Returns whether the notification with the given key was intercepted
- * by &quot;Do not disturb&quot;.
- */
- public boolean isInterceptedByDoNotDisturb(String key) {
- // TODO: Optimize.
- for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) {
- if (interceptedKey.equals(key)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns whether the notification with the given key is an ambient
- * notification, that is a notification that doesn't require the user's
- * immediate attention.
- */
- public boolean isAmbient(String key) {
- // TODO: Optimize.
- int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
- if (firstAmbientIndex < 0) {
- return false;
- }
+ private void initializeRankingCache() {
String[] orderedKeys = mRankingUpdate.getOrderedKeys();
- for (int i = firstAmbientIndex; i < orderedKeys.length; i++) {
- if (orderedKeys[i].equals(key)) {
- return true;
+ int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
+ for (int i = 0; i < orderedKeys.length; i++) {
+ String key = orderedKeys[i];
+ boolean isAmbient = firstAmbientIndex > -1 && firstAmbientIndex <= i;
+ boolean isInterceptedByDnd = false;
+ // TODO: Optimize.
+ for (String s : mRankingUpdate.getDndInterceptedKeys()) {
+ if (s.equals(key)) {
+ isInterceptedByDnd = true;
+ break;
+ }
}
+ mRankingCache.put(key, new Ranking(key, i, isAmbient, isInterceptedByDnd));
}
- return false;
}
// ----------- Parcelable
@@ -453,16 +541,16 @@ public abstract class NotificationListenerService extends Service {
dest.writeParcelable(mRankingUpdate, flags);
}
- public static final Creator<Ranking> CREATOR = new Creator<Ranking>() {
+ public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() {
@Override
- public Ranking createFromParcel(Parcel source) {
+ public RankingMap createFromParcel(Parcel source) {
NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
- return new Ranking(rankingUpdate);
+ return new RankingMap(rankingUpdate);
}
@Override
- public Ranking[] newArray(int size) {
- return new Ranking[size];
+ public RankingMap[] newArray(int size) {
+ return new RankingMap[size];
}
};
}
diff --git a/core/java/android/service/voice/DspInfo.java b/core/java/android/service/voice/DspInfo.java
new file mode 100644
index 0000000..0862309
--- /dev/null
+++ b/core/java/android/service/voice/DspInfo.java
@@ -0,0 +1,56 @@
+/*
+ * 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.voice;
+
+import java.util.UUID;
+
+/**
+ * Properties of the DSP hardware on the device.
+ * @hide
+ */
+public class DspInfo {
+ /**
+ * Unique voice engine Id (changes with each version).
+ */
+ public final UUID voiceEngineId;
+
+ /**
+ * Human readable voice detection engine implementor.
+ */
+ public final String voiceEngineImplementor;
+ /**
+ * Human readable voice detection engine description.
+ */
+ public final String voiceEngineDescription;
+ /**
+ * Human readable voice detection engine version
+ */
+ public final int voiceEngineVersion;
+ /**
+ * Rated power consumption when detection is active.
+ */
+ public final int powerConsumptionMw;
+
+ public DspInfo(UUID voiceEngineId, String voiceEngineImplementor,
+ String voiceEngineDescription, int version, int powerConsumptionMw) {
+ this.voiceEngineId = voiceEngineId;
+ this.voiceEngineImplementor = voiceEngineImplementor;
+ this.voiceEngineDescription = voiceEngineDescription;
+ this.voiceEngineVersion = version;
+ this.powerConsumptionMw = powerConsumptionMw;
+ }
+}
diff --git a/core/java/android/service/voice/KeyphraseEnrollmentInfo.java b/core/java/android/service/voice/KeyphraseEnrollmentInfo.java
new file mode 100644
index 0000000..ebe41ce
--- /dev/null
+++ b/core/java/android/service/voice/KeyphraseEnrollmentInfo.java
@@ -0,0 +1,246 @@
+/*
+ * 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.voice;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+/** @hide */
+public class KeyphraseEnrollmentInfo {
+ private static final String TAG = "KeyphraseEnrollmentInfo";
+ /**
+ * Name under which a Hotword enrollment component publishes information about itself.
+ * This meta-data should reference an XML resource containing a
+ * <code>&lt;{@link
+ * android.R.styleable#VoiceEnrollmentApplication
+ * voice-enrollment-application}&gt;</code> tag.
+ */
+ private static final String VOICE_KEYPHRASE_META_DATA = "android.voice_enrollment";
+ /**
+ * Activity Action: Show activity for managing the keyphrases for hotword detection.
+ * This needs to be defined by an activity that supports enrolling users for hotword/keyphrase
+ * detection.
+ */
+ public static final String ACTION_MANAGE_VOICE_KEYPHRASES =
+ "com.android.intent.action.MANAGE_VOICE_KEYPHRASES";
+ /**
+ * Intent extra: The intent extra for un-enrolling a user for a particular keyphrase.
+ */
+ public static final String EXTRA_VOICE_KEYPHRASE_UNENROLL =
+ "com.android.intent.extra.VOICE_KEYPHRASE_UNENROLL";
+ /**
+ * Intent extra: The hint text to be shown on the voice keyphrase management UI.
+ */
+ public static final String EXTRA_VOICE_KEYPHRASE_HINT_TEXT =
+ "com.android.intent.extra.VOICE_KEYPHRASE_HINT_TEXT";
+ /**
+ * Intent extra: The voice locale to use while managing the keyphrase.
+ */
+ public static final String EXTRA_VOICE_KEYPHRASE_LOCALE =
+ "com.android.intent.extra.VOICE_KEYPHRASE_LOCALE";
+
+ private KeyphraseInfo[] mKeyphrases;
+ private String mEnrollmentPackage;
+ private String mParseError;
+
+ public KeyphraseEnrollmentInfo(PackageManager pm) {
+ // Find the apps that supports enrollment for hotword keyhphrases,
+ // Pick a privileged app and obtain the information about the supported keyphrases
+ // from its metadata.
+ List<ResolveInfo> ris = pm.queryIntentActivities(
+ new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY);
+ if (ris == null || ris.isEmpty()) {
+ // No application capable of enrolling for voice keyphrases is present.
+ mParseError = "No enrollment application found";
+ return;
+ }
+
+ boolean found = false;
+ ApplicationInfo ai = null;
+ for (ResolveInfo ri : ris) {
+ try {
+ ai = pm.getApplicationInfo(
+ ri.activityInfo.packageName, PackageManager.GET_META_DATA);
+ if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+ // The application isn't privileged (/system/priv-app).
+ // The enrollment application needs to be a privileged system app.
+ Slog.w(TAG, ai.packageName + "is not a privileged system app");
+ continue;
+ }
+ if (!Manifest.permission.MANAGE_VOICE_KEYPHRASES.equals(ai.permission)) {
+ // The application trying to manage keyphrases doesn't
+ // require the MANAGE_VOICE_KEYPHRASES permission.
+ Slog.w(TAG, ai.packageName + " does not require MANAGE_VOICE_KEYPHRASES");
+ continue;
+ }
+ mEnrollmentPackage = ai.packageName;
+ found = true;
+ break;
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "error parsing voice enrollment meta-data", e);
+ }
+ }
+
+ if (!found) {
+ mKeyphrases = null;
+ mParseError = "No suitable enrollment application found";
+ return;
+ }
+
+ XmlResourceParser parser = null;
+ try {
+ parser = ai.loadXmlMetaData(pm, VOICE_KEYPHRASE_META_DATA);
+ if (parser == null) {
+ mParseError = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for "
+ + ai.packageName;
+ return;
+ }
+
+ Resources res = pm.getResourcesForApplication(ai);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!"voice-enrollment-application".equals(nodeName)) {
+ mParseError = "Meta-data does not start with voice-enrollment-application tag";
+ return;
+ }
+
+ TypedArray array = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.VoiceEnrollmentApplication);
+ int searchKeyphraseId = array.getInt(
+ com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId,
+ -1);
+ if (searchKeyphraseId != -1) {
+ String searchKeyphrase = array.getString(com.android.internal.R.styleable
+ .VoiceEnrollmentApplication_searchKeyphrase);
+ String searchKeyphraseSupportedLocales =
+ array.getString(com.android.internal.R.styleable
+ .VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
+ String[] supportedLocales = new String[0];
+ // Get all the supported locales from the comma-delimted string.
+ if (searchKeyphraseSupportedLocales != null
+ && !searchKeyphraseSupportedLocales.isEmpty()) {
+ supportedLocales = searchKeyphraseSupportedLocales.split(",");
+ }
+ mKeyphrases = new KeyphraseInfo[1];
+ mKeyphrases[0] = new KeyphraseInfo(
+ searchKeyphraseId, searchKeyphrase, supportedLocales);
+ } else {
+ mParseError = "searchKeyphraseId not specified in meta-data";
+ return;
+ }
+ } catch (XmlPullParserException e) {
+ mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+ Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+ return;
+ } catch (IOException e) {
+ mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+ Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+ return;
+ } catch (PackageManager.NameNotFoundException e) {
+ mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+ Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+ return;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ public String getParseError() {
+ return mParseError;
+ }
+
+ /**
+ * @return An array of available keyphrases that can be enrolled on the system.
+ * It may be null if no keyphrases can be enrolled.
+ */
+ public KeyphraseInfo[] getKeyphrases() {
+ return mKeyphrases;
+ }
+
+ /**
+ * Returns an intent to launch an activity that manages the given keyphrase
+ * for the locale.
+ *
+ * @param enroll Indicates if the intent should enroll the user or un-enroll them.
+ * @param keyphrase The keyphrase that the user needs to be enrolled to.
+ * @param locale The locale for which the enrollment needs to be performed.
+ * @return An {@link Intent} to manage the keyphrase. This can be null if managing the
+ * given keyphrase/locale combination isn't possible.
+ */
+ public Intent getManageKeyphraseIntent(boolean enroll, String keyphrase, String locale) {
+ if (mEnrollmentPackage == null || mEnrollmentPackage.isEmpty()) {
+ Slog.w(TAG, "No enrollment application exists");
+ return null;
+ }
+
+ if (isKeyphraseEnrollmentSupported(keyphrase, locale)) {
+ Intent intent = new Intent(ACTION_MANAGE_VOICE_KEYPHRASES)
+ .setPackage(mEnrollmentPackage)
+ .putExtra(EXTRA_VOICE_KEYPHRASE_HINT_TEXT, keyphrase)
+ .putExtra(EXTRA_VOICE_KEYPHRASE_LOCALE, locale);
+ if (!enroll) intent.putExtra(EXTRA_VOICE_KEYPHRASE_UNENROLL, true);
+ return intent;
+ }
+ return null;
+ }
+
+ /**
+ * Indicates if enrollment is supported for the given keyphrase & locale.
+ *
+ * @param keyphrase The keyphrase that the user needs to be enrolled to.
+ * @param locale The locale for which the enrollment needs to be performed.
+ * @return true, if an enrollment client supports the given keyphrase and the given locale.
+ */
+ public boolean isKeyphraseEnrollmentSupported(String keyphrase, String locale) {
+ if (mKeyphrases == null || mKeyphrases.length == 0) {
+ Slog.w(TAG, "Enrollment application doesn't support keyphrases");
+ return false;
+ }
+ for (KeyphraseInfo keyphraseInfo : mKeyphrases) {
+ // Check if the given keyphrase is supported in the locale provided by
+ // the enrollment application.
+ String supportedKeyphrase = keyphraseInfo.keyphrase;
+ if (supportedKeyphrase.equalsIgnoreCase(keyphrase)
+ && keyphraseInfo.supportedLocales.contains(locale)) {
+ return true;
+ }
+ }
+ Slog.w(TAG, "Enrollment application doesn't support the given keyphrase");
+ return false;
+ }
+}
diff --git a/core/java/android/service/voice/KeyphraseInfo.java b/core/java/android/service/voice/KeyphraseInfo.java
new file mode 100644
index 0000000..d266e1a
--- /dev/null
+++ b/core/java/android/service/voice/KeyphraseInfo.java
@@ -0,0 +1,27 @@
+package android.service.voice;
+
+import android.util.ArraySet;
+
+/**
+ * A Voice Keyphrase.
+ * @hide
+ */
+public class KeyphraseInfo {
+ public final int id;
+ public final String keyphrase;
+ public final ArraySet<String> supportedLocales;
+
+ public KeyphraseInfo(int id, String keyphrase, String[] supportedLocales) {
+ this.id = id;
+ this.keyphrase = keyphrase;
+ this.supportedLocales = new ArraySet<String>(supportedLocales.length);
+ for (String locale : supportedLocales) {
+ this.supportedLocales.add(locale);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "id=" + id + ", keyphrase=" + keyphrase + ", supported-locales=" + supportedLocales;
+ }
+}
diff --git a/core/java/android/service/voice/SoundTriggerManager.java b/core/java/android/service/voice/SoundTriggerManager.java
new file mode 100644
index 0000000..2d049b9
--- /dev/null
+++ b/core/java/android/service/voice/SoundTriggerManager.java
@@ -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.
+ */
+
+package android.service.voice;
+
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
+
+import java.util.ArrayList;
+
+/**
+ * Manager for {@link SoundTrigger} APIs.
+ * Currently this just acts as an abstraction over all SoundTrigger API calls.
+ * @hide
+ */
+public class SoundTriggerManager {
+ /** The {@link DspInfo} for the system, or null if none exists. */
+ public DspInfo dspInfo;
+
+ public SoundTriggerManager() {
+ ArrayList <ModuleProperties> modules = new ArrayList<>();
+ int status = SoundTrigger.listModules(modules);
+ if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
+ // TODO(sansid, elaurent): Figure out how to handle errors in listing the modules here.
+ dspInfo = null;
+ } else {
+ // TODO(sansid, elaurent): Figure out how to determine which module corresponds to the
+ // DSP hardware.
+ ModuleProperties properties = modules.get(0);
+ dspInfo = new DspInfo(properties.uuid, properties.implementor, properties.description,
+ properties.version, properties.powerConsumptionMw);
+ }
+ }
+
+ /**
+ * @return True, if the keyphrase is supported on DSP for the given locale.
+ */
+ public boolean isKeyphraseSupported(String keyphrase, String locale) {
+ // TODO(sansid): We also need to look into a SoundTrigger API that let's us
+ // query this. For now just return supported if there's a DSP available.
+ return dspInfo != null;
+ }
+
+ /**
+ * @return True, if the keyphrase is has been enrolled for the given locale.
+ */
+ public boolean isKeyphraseEnrolled(String keyphrase, String locale) {
+ // TODO(sansid, elaurent): Query SoundTrigger to list currently loaded sound models.
+ // They have been enrolled.
+ return false;
+ }
+
+ /**
+ * @return True, if a recognition for the keyphrase is active for the given locale.
+ */
+ public boolean isKeyphraseActive(String keyphrase, String locale) {
+ // TODO(sansid, elaurent): Check if the recognition for the keyphrase is currently active.
+ return false;
+ }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index e15489b..e0329f8 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -17,7 +17,6 @@
package android.service.voice;
import android.annotation.SdkConstant;
-import android.app.Instrumentation;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -25,8 +24,11 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractionManagerService;
+
/**
* Top-level service of the current global voice interactor, which is providing
* support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
@@ -51,6 +53,16 @@ public class VoiceInteractionService extends Service {
public static final String SERVICE_INTERFACE =
"android.service.voice.VoiceInteractionService";
+ // TODO(sansid): Unhide these.
+ /** @hide */
+ public static final int KEYPHRASE_UNAVAILABLE = 0;
+ /** @hide */
+ public static final int KEYPHRASE_UNENROLLED = 1;
+ /** @hide */
+ public static final int KEYPHRASE_ENROLLED = 2;
+ /** @hide */
+ public static final int KEYPHRASE_ACTIVE = 3;
+
/**
* Name under which a VoiceInteractionService component publishes information about itself.
* This meta-data should reference an XML resource containing a
@@ -64,6 +76,9 @@ public class VoiceInteractionService extends Service {
IVoiceInteractionManagerService mSystemService;
+ private SoundTriggerManager mSoundTriggerManager;
+ private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
+
public void startSession(Bundle args) {
try {
mSystemService.startSession(mInterface, args);
@@ -76,6 +91,8 @@ public class VoiceInteractionService extends Service {
super.onCreate();
mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+ mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager());
+ mSoundTriggerManager = new SoundTriggerManager();
}
@Override
@@ -85,4 +102,44 @@ public class VoiceInteractionService extends Service {
}
return null;
}
+
+ /**
+ * Gets the state of always-on hotword detection for the given keyphrase and locale
+ * on this system.
+ * Availability implies that the hardware on this system is capable of listening for
+ * the given keyphrase or not.
+ * The return code is one of {@link #KEYPHRASE_UNAVAILABLE}, {@link #KEYPHRASE_UNENROLLED}
+ * {@link #KEYPHRASE_ENROLLED} or {@link #KEYPHRASE_ACTIVE}.
+ *
+ * @param keyphrase The keyphrase whose availability is being checked.
+ * @param locale The locale for which the availability is being checked.
+ * @return Indicates if always-on hotword detection is available for the given keyphrase.
+ * TODO(sansid): Unhide this.
+ * @hide
+ */
+ public final int getAlwaysOnKeyphraseAvailability(String keyphrase, String locale) {
+ // The available keyphrases is a combination of DSP availability and
+ // the keyphrases that have an enrollment application for them.
+ if (!mSoundTriggerManager.isKeyphraseSupported(keyphrase, locale)
+ || !mKeyphraseEnrollmentInfo.isKeyphraseEnrollmentSupported(keyphrase, locale)) {
+ return KEYPHRASE_UNAVAILABLE;
+ }
+ if (!mSoundTriggerManager.isKeyphraseEnrolled(keyphrase, locale)) {
+ return KEYPHRASE_UNENROLLED;
+ }
+ if (!mSoundTriggerManager.isKeyphraseActive(keyphrase, locale)) {
+ return KEYPHRASE_ENROLLED;
+ } else {
+ return KEYPHRASE_ACTIVE;
+ }
+ }
+
+ /**
+ * @return Details of keyphrases available for enrollment.
+ * @hide
+ */
+ @VisibleForTesting
+ protected final KeyphraseEnrollmentInfo getKeyphraseEnrollmentInfo() {
+ return mKeyphraseEnrollmentInfo;
+ }
}
diff --git a/core/java/android/speech/tts/RequestConfig.java b/core/java/android/speech/tts/RequestConfig.java
index 4b5385f..84880c0 100644
--- a/core/java/android/speech/tts/RequestConfig.java
+++ b/core/java/android/speech/tts/RequestConfig.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.media.AudioManager;
diff --git a/core/java/android/speech/tts/RequestConfigHelper.java b/core/java/android/speech/tts/RequestConfigHelper.java
index b25c985..3b5490b 100644
--- a/core/java/android/speech/tts/RequestConfigHelper.java
+++ b/core/java/android/speech/tts/RequestConfigHelper.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.speech.tts.TextToSpeechClient.EngineStatus;
diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java
index 130e3f9..a42aa16 100644
--- a/core/java/android/speech/tts/SynthesisRequestV2.java
+++ b/core/java/android/speech/tts/SynthesisRequestV2.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.os.Bundle;
diff --git a/core/java/android/speech/tts/VoiceInfo.java b/core/java/android/speech/tts/VoiceInfo.java
index 16b9a97..71629dc 100644
--- a/core/java/android/speech/tts/VoiceInfo.java
+++ b/core/java/android/speech/tts/VoiceInfo.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.os.Bundle;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index de46804..15dfed1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -89,6 +89,7 @@ LOCAL_SRC_FILES:= \
android_util_Process.cpp \
android_util_StringBlock.cpp \
android_util_XmlBlock.cpp \
+ android/graphics/AndroidPicture.cpp \
android/graphics/AutoDecodeCancel.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f8e6bc3..f2b9bac 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -244,9 +244,6 @@ AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength)
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
- // this sets our preference for 16bit images during decode
- // in case the src is opaque and 24bit
- SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config);
// There is also a global font cache, but its budget is specified in code
// see SkFontHost_android.cpp
@@ -825,8 +822,9 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
mOptions.add(opt);
}
- // Whether the profile should start upon app startup or be delayed by some random offset.
- property_get("dalvik.vm.profile.start-immediately", propBuf, "0");
+ // Whether the profile should start upon app startup or be delayed by some random offset
+ // (in seconds) that is bound between 0 and a fixed value.
+ property_get("dalvik.vm.profile.start-immed", propBuf, "0");
if (propBuf[0] == '1') {
opt.optionString = "-Xprofile-start-immediately";
mOptions.add(opt);
diff --git a/core/jni/android/graphics/AndroidPicture.cpp b/core/jni/android/graphics/AndroidPicture.cpp
new file mode 100644
index 0000000..5977ab2
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "AndroidPicture.h"
+#include "SkCanvas.h"
+#include "SkStream.h"
+
+AndroidPicture::AndroidPicture(const AndroidPicture* src) {
+ if (NULL != src) {
+ mWidth = src->width();
+ mHeight = src->height();
+ if (NULL != src->mPicture.get()) {
+ mPicture.reset(SkRef(src->mPicture.get()));
+ } if (NULL != src->mRecorder.get()) {
+ mPicture.reset(src->makePartialCopy());
+ }
+ } else {
+ mWidth = 0;
+ mHeight = 0;
+ }
+}
+
+SkCanvas* AndroidPicture::beginRecording(int width, int height) {
+ mPicture.reset(NULL);
+ mRecorder.reset(new SkPictureRecorder);
+ mWidth = width;
+ mHeight = height;
+ return mRecorder->beginRecording(width, height, NULL, 0);
+}
+
+void AndroidPicture::endRecording() {
+ if (NULL != mRecorder.get()) {
+ mPicture.reset(mRecorder->endRecording());
+ mRecorder.reset(NULL);
+ }
+}
+
+int AndroidPicture::width() const {
+ if (NULL != mPicture.get()) {
+ SkASSERT(mPicture->width() == mWidth);
+ SkASSERT(mPicture->height() == mHeight);
+ }
+
+ return mWidth;
+}
+
+int AndroidPicture::height() const {
+ if (NULL != mPicture.get()) {
+ SkASSERT(mPicture->width() == mWidth);
+ SkASSERT(mPicture->height() == mHeight);
+ }
+
+ return mHeight;
+}
+
+AndroidPicture* AndroidPicture::CreateFromStream(SkStream* stream) {
+ AndroidPicture* newPict = new AndroidPicture;
+
+ newPict->mPicture.reset(SkPicture::CreateFromStream(stream));
+ if (NULL != newPict->mPicture.get()) {
+ newPict->mWidth = newPict->mPicture->width();
+ newPict->mHeight = newPict->mPicture->height();
+ }
+
+ return newPict;
+}
+
+void AndroidPicture::serialize(SkWStream* stream) const {
+ if (NULL != mRecorder.get()) {
+ SkAutoTDelete<SkPicture> tempPict(this->makePartialCopy());
+ tempPict->serialize(stream);
+ } else if (NULL != mPicture.get()) {
+ mPicture->serialize(stream);
+ } else {
+ SkPicture empty;
+ empty.serialize(stream);
+ }
+}
+
+void AndroidPicture::draw(SkCanvas* canvas) {
+ if (NULL != mRecorder.get()) {
+ this->endRecording();
+ SkASSERT(NULL != mPicture.get());
+ }
+ if (NULL != mPicture.get()) {
+ // TODO: remove this const_cast once pictures are immutable
+ const_cast<SkPicture*>(mPicture.get())->draw(canvas);
+ }
+}
+
+SkPicture* AndroidPicture::makePartialCopy() const {
+ SkASSERT(NULL != mRecorder.get());
+
+ SkPictureRecorder reRecorder;
+
+ SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+ mRecorder->partialReplay(canvas);
+ return reRecorder.endRecording();
+}
diff --git a/core/jni/android/graphics/AndroidPicture.h b/core/jni/android/graphics/AndroidPicture.h
new file mode 100644
index 0000000..f434941
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PICTURE_H
+#define ANDROID_PICTURE_H
+
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkRefCnt.h"
+#include "SkTemplates.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPictureRecorder;
+class SkStream;
+class SkWStream;
+
+// Skia's SkPicture class has been split into an SkPictureRecorder
+// and an SkPicture. AndroidPicture recreates the functionality
+// of the old SkPicture interface by flip-flopping between the two
+// new classes.
+class AndroidPicture {
+public:
+ explicit AndroidPicture(const AndroidPicture* src = NULL);
+
+ SkCanvas* beginRecording(int width, int height);
+
+ void endRecording();
+
+ int width() const;
+
+ int height() const;
+
+ static AndroidPicture* CreateFromStream(SkStream* stream);
+
+ void serialize(SkWStream* stream) const;
+
+ void draw(SkCanvas* canvas);
+
+private:
+ int mWidth;
+ int mHeight;
+ SkAutoTUnref<const SkPicture> mPicture;
+ SkAutoTDelete<SkPictureRecorder> mRecorder;
+
+ // Make a copy of a picture that is in the midst of being recorded. The
+ // resulting picture will have balanced saves and restores.
+ SkPicture* makePartialCopy() const;
+};
+#endif // ANDROID_PICTURE_H
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0328517..9998995 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -361,24 +361,50 @@ static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
}
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint width, jint height, jint configHandle, jint allocSize) {
+ jint width, jint height, jint configHandle, jint allocSize,
+ jboolean requestPremul) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
- if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+ SkColorType colorType = SkBitmapConfigToColorType(config);
+
+ // ARGB_4444 is a deprecated format, convert automatically to 8888
+ if (colorType == kARGB_4444_SkColorType) {
+ colorType = kN32_SkColorType;
+ }
+
+ if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
// done in native as there's no way to get BytesPerPixel in Java
doThrowIAE(env, "Bitmap not large enough to support new configuration");
return;
}
SkPixelRef* ref = bitmap->pixelRef();
- SkSafeRef(ref);
- bitmap->setConfig(config, width, height);
+ ref->ref();
+ SkAlphaType alphaType;
+ if (bitmap->colorType() != kRGB_565_SkColorType
+ && bitmap->alphaType() == kOpaque_SkAlphaType) {
+ // If the original bitmap was set to opaque, keep that setting, unless it
+ // was 565, which is required to be opaque.
+ alphaType = kOpaque_SkAlphaType;
+ } else {
+ // Otherwise respect the premultiplied request.
+ alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
+ }
+ bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
+ // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for
+ // its alphatype), so it would make more sense from Skia's perspective to create a
+ // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key
+ // for its cache, so it won't realize this is the same Java Bitmap.
+ SkImageInfo& info = const_cast<SkImageInfo&>(ref->info());
+ // Use the updated from the SkBitmap, which may have corrected an invalid alphatype.
+ // (e.g. 565 non-opaque)
+ info = bitmap->info();
bitmap->setPixelRef(ref);
// notifyPixelsChanged will increment the generation ID even though the actual pixel data
// hasn't been touched. This signals the renderer that the bitmap (including width, height,
- // and config) has changed.
+ // colortype and alphatype) has changed.
ref->notifyPixelsChanged();
- SkSafeUnref(ref);
+ ref->unref();
}
// These must match the int values in Bitmap.java
@@ -799,7 +825,7 @@ static JNINativeMethod gBitmapMethods[] = {
(void*)Bitmap_copy },
{ "nativeDestructor", "(J)V", (void*)Bitmap_destructor },
{ "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure },
+ { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure },
{ "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(JI)V", (void*)Bitmap_erase },
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3b44f97..6de3b9e 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -19,11 +19,14 @@
#include <android_runtime/AndroidRuntime.h>
#include "SkCanvas.h"
+#include "SkClipStack.h"
#include "SkDevice.h"
+#include "SkDeque.h"
#include "SkDrawFilter.h"
#include "SkGraphics.h"
#include "SkPorterDuff.h"
#include "SkShader.h"
+#include "SkTArray.h"
#include "SkTemplates.h"
#ifdef USE_MINIKIN
@@ -43,11 +46,42 @@
namespace android {
+class ClipCopier : public SkCanvas::ClipVisitor {
+public:
+ ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
+
+ virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
+ m_dstCanvas->clipRect(rect, op, antialias);
+ }
+ virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
+ m_dstCanvas->clipRRect(rrect, op, antialias);
+ }
+ virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
+ m_dstCanvas->clipPath(path, op, antialias);
+ }
+
+private:
+ SkCanvas* m_dstCanvas;
+};
+
// Holds an SkCanvas reference plus additional native data.
class NativeCanvasWrapper {
+private:
+ struct SaveRec {
+ int saveCount;
+ SkCanvas::SaveFlags saveFlags;
+ };
+
public:
NativeCanvasWrapper(SkCanvas* canvas)
- : mCanvas(canvas) { }
+ : mCanvas(canvas)
+ , mSaveStack(NULL) {
+ SkASSERT(canvas);
+ }
+
+ ~NativeCanvasWrapper() {
+ delete mSaveStack;
+ }
SkCanvas* getCanvas() const {
return mCanvas.get();
@@ -56,28 +90,127 @@ public:
void setCanvas(SkCanvas* canvas) {
SkASSERT(canvas);
mCanvas.reset(canvas);
- }
-private:
- SkAutoTUnref<SkCanvas> mCanvas;
-};
+ delete mSaveStack;
+ mSaveStack = NULL;
+ }
-class ClipCopier : public SkCanvas::ClipVisitor {
-public:
- ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
+ int save(SkCanvas::SaveFlags flags) {
+ int count = mCanvas->save();
+ recordPartialSave(flags);
+ return count;
+ }
- virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
- m_dstCanvas->clipRect(rect, op, antialias);
+ int saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SkCanvas::SaveFlags flags) {
+ int count = mCanvas->saveLayer(bounds, paint,
+ static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag));
+ recordPartialSave(flags);
+ return count;
}
- virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
- m_dstCanvas->clipRRect(rrect, op, antialias);
+
+ int saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
+ SkCanvas::SaveFlags flags) {
+ int count = mCanvas->saveLayerAlpha(bounds, alpha,
+ static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag));
+ recordPartialSave(flags);
+ return count;
}
- virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
- m_dstCanvas->clipPath(path, op, antialias);
+
+ void restore() {
+ const SaveRec* rec = (NULL == mSaveStack)
+ ? NULL
+ : static_cast<SaveRec*>(mSaveStack->back());
+ int currentSaveCount = mCanvas->getSaveCount() - 1;
+ SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount);
+
+ if (NULL == rec || rec->saveCount != currentSaveCount) {
+ // Fast path - no record for this frame.
+ mCanvas->restore();
+ return;
+ }
+
+ bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag);
+ bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag);
+
+ SkMatrix savedMatrix;
+ if (preserveMatrix) {
+ savedMatrix = mCanvas->getTotalMatrix();
+ }
+
+ SkTArray<SkClipStack::Element> savedClips;
+ if (preserveClip) {
+ saveClipsForFrame(savedClips, currentSaveCount);
+ }
+
+ mCanvas->restore();
+
+ if (preserveMatrix) {
+ mCanvas->setMatrix(savedMatrix);
+ }
+
+ if (preserveClip && !savedClips.empty()) {
+ applyClips(savedClips);
+ }
+
+ mSaveStack->pop_back();
}
private:
- SkCanvas* m_dstCanvas;
+ void recordPartialSave(SkCanvas::SaveFlags flags) {
+ // A partial save is a save operation which doesn't capture the full canvas state.
+ // (either kMatrix_SaveFlags or kClip_SaveFlag is missing).
+
+ // Mask-out non canvas state bits.
+ flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag);
+
+ if (SkCanvas::kMatrixClip_SaveFlag == flags) {
+ // not a partial save.
+ return;
+ }
+
+ if (NULL == mSaveStack) {
+ mSaveStack = new SkDeque(sizeof(struct SaveRec), 8);
+ }
+
+ SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
+ // Store the save counter in the SkClipStack domain.
+ // (0-based, equal to the number of save ops on the stack).
+ rec->saveCount = mCanvas->getSaveCount() - 1;
+ rec->saveFlags = flags;
+ }
+
+ void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips,
+ int frameSaveCount) {
+ SkClipStack::Iter clipIterator(*mCanvas->getClipStack(),
+ SkClipStack::Iter::kTop_IterStart);
+ while (const SkClipStack::Element* elem = clipIterator.next()) {
+ if (elem->getSaveCount() < frameSaveCount) {
+ // done with the current frame.
+ break;
+ }
+ SkASSERT(elem->getSaveCount() == frameSaveCount);
+ clips.push_back(*elem);
+ }
+ }
+
+ void applyClips(const SkTArray<SkClipStack::Element>& clips) {
+ ClipCopier clipCopier(mCanvas);
+
+ // The clip stack stores clips in device space.
+ SkMatrix origMatrix = mCanvas->getTotalMatrix();
+ mCanvas->resetMatrix();
+
+ // We pushed the clips in reverse order.
+ for (int i = clips.count() - 1; i >= 0; --i) {
+ clips[i].replay(&clipCopier);
+ }
+
+ mCanvas->setMatrix(origMatrix);
+ }
+
+ SkAutoTUnref<SkCanvas> mCanvas;
+ SkDeque* mSaveStack; // lazily allocated, tracks partial saves.
};
// Returns true if the SkCanvas's clip is non-empty.
@@ -88,11 +221,15 @@ static jboolean hasNonEmptyClip(const SkCanvas& canvas) {
class SkCanvasGlue {
public:
+ // Get the native wrapper for a given handle.
+ static inline NativeCanvasWrapper* getNativeWrapper(jlong nativeHandle) {
+ SkASSERT(nativeHandle);
+ return reinterpret_cast<NativeCanvasWrapper*>(nativeHandle);
+ }
// Get the SkCanvas for a given native handle.
static inline SkCanvas* getNativeCanvas(jlong nativeHandle) {
- SkASSERT(nativeHandle);
- NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle);
+ NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle);
SkCanvas* canvas = wrapper->getCanvas();
SkASSERT(canvas);
@@ -186,56 +323,56 @@ public:
}
static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
- return static_cast<jint>(canvas->save(flags));
+ return static_cast<jint>(wrapper->save(flags));
}
static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle,
jfloat l, jfloat t, jfloat r, jfloat b,
- jlong paintHandle, jint flags) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ jlong paintHandle, jint flagsHandle) {
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
SkRect bounds;
bounds.set(l, t, r, b);
- int result = canvas->saveLayer(&bounds, paint,
- static_cast<SkCanvas::SaveFlags>(flags));
- return static_cast<jint>(result);
+ return static_cast<jint>(wrapper->saveLayer(&bounds, paint, flags));
}
static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle,
jfloat l, jfloat t, jfloat r, jfloat b,
- jint alpha, jint flags) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ jint alpha, jint flagsHandle) {
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
+ SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
SkRect bounds;
bounds.set(l, t, r, b);
- int result = canvas->saveLayerAlpha(&bounds, alpha,
- static_cast<SkCanvas::SaveFlags>(flags));
- return static_cast<jint>(result);
+ return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags));
}
static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
- if (canvas->getSaveCount() <= 1) { // cannot restore anymore
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
+ if (wrapper->getCanvas()->getSaveCount() <= 1) { // cannot restore anymore
doThrowISE(env, "Underflow in restore");
return;
}
- canvas->restore();
+ wrapper->restore();
}
static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
- return static_cast<jint>(canvas->getSaveCount());
+ return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount());
}
static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle,
jint restoreCount) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
if (restoreCount < 1) {
doThrowIAE(env, "Underflow in restoreToCount");
return;
}
- canvas->restoreToCount(restoreCount);
+
+ while (wrapper->getCanvas()->getSaveCount() > restoreCount) {
+ wrapper->restore();
+ }
}
static void translate(JNIEnv*, jobject, jlong canvasHandle,
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 64ad223..a4337cc 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -3,6 +3,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "GraphicsJNI.h"
+#include "AndroidPicture.h"
#include "SkCanvas.h"
#include "SkDevice.h"
@@ -345,13 +346,13 @@ android::TypefaceImpl* GraphicsJNI::getNativeTypeface(JNIEnv* env, jobject paint
return p;
}
-SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
+AndroidPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
{
SkASSERT(env);
SkASSERT(picture);
SkASSERT(env->IsInstanceOf(picture, gPicture_class));
jlong pictureHandle = env->GetLongField(picture, gPicture_nativeInstanceID);
- SkPicture* p = reinterpret_cast<SkPicture*>(pictureHandle);
+ AndroidPicture* p = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkASSERT(p);
return p;
}
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 73dd11b..2e2f920 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -14,7 +14,7 @@
class SkBitmapRegionDecoder;
class SkCanvas;
class SkPaint;
-class SkPicture;
+class AndroidPicture;
class GraphicsJNI {
public:
@@ -50,7 +50,7 @@ public:
static SkPaint* getNativePaint(JNIEnv*, jobject paint);
static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
- static SkPicture* getNativePicture(JNIEnv*, jobject picture);
+ static AndroidPicture* getNativePicture(JNIEnv*, jobject picture);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
// Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index a8a3dae..0683f73 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -17,9 +17,9 @@
#include "jni.h"
#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>
+#include "AndroidPicture.h"
#include "SkCanvas.h"
-#include "SkPicture.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "CreateJavaOutputStreamAdaptor.h"
@@ -29,45 +29,41 @@ namespace android {
class SkPictureGlue {
public:
static jlong newPicture(JNIEnv* env, jobject, jlong srcHandle) {
- const SkPicture* src = reinterpret_cast<SkPicture*>(srcHandle);
- if (src) {
- return reinterpret_cast<jlong>(new SkPicture(*src));
- } else {
- return reinterpret_cast<jlong>(new SkPicture);
- }
+ const AndroidPicture* src = reinterpret_cast<AndroidPicture*>(srcHandle);
+ return reinterpret_cast<jlong>(new AndroidPicture(src));
}
static jlong deserialize(JNIEnv* env, jobject, jobject jstream,
jbyteArray jstorage) {
- SkPicture* picture = NULL;
+ AndroidPicture* picture = NULL;
SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
if (strm) {
- picture = SkPicture::CreateFromStream(strm);
+ picture = AndroidPicture::CreateFromStream(strm);
delete strm;
}
return reinterpret_cast<jlong>(picture);
}
static void killPicture(JNIEnv* env, jobject, jlong pictureHandle) {
- SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+ AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkASSERT(picture);
- picture->unref();
+ delete picture;
}
static void draw(JNIEnv* env, jobject, jlong canvasHandle,
jlong pictureHandle) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle);
- SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+ AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkASSERT(canvas);
SkASSERT(picture);
picture->draw(canvas);
}
static jboolean serialize(JNIEnv* env, jobject, jlong pictureHandle,
- jobject jstream, jbyteArray jstorage) {
- SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+ jobject jstream, jbyteArray jstorage) {
+ AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
-
+
if (NULL != strm) {
picture->serialize(strm);
delete strm;
@@ -78,19 +74,21 @@ public:
static jint getWidth(JNIEnv* env, jobject jpic) {
NPE_CHECK_RETURN_ZERO(env, jpic);
- int width = GraphicsJNI::getNativePicture(env, jpic)->width();
+ AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+ int width = pict->width();
return static_cast<jint>(width);
}
static jint getHeight(JNIEnv* env, jobject jpic) {
NPE_CHECK_RETURN_ZERO(env, jpic);
- int height = GraphicsJNI::getNativePicture(env, jpic)->height();
+ AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+ int height = pict->height();
return static_cast<jint>(height);
}
static jlong beginRecording(JNIEnv* env, jobject, jlong pictHandle,
- jint w, jint h) {
- SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+ jint w, jint h) {
+ AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
// beginRecording does not ref its return value, it just returns it.
SkCanvas* canvas = pict->beginRecording(w, h);
// the java side will wrap this guy in a Canvas.java, which will call
@@ -101,7 +99,7 @@ public:
}
static void endRecording(JNIEnv* env, jobject, jlong pictHandle) {
- SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+ AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
pict->endRecording();
}
};
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index d54aaa8..3812c27 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -24,6 +24,7 @@
#include "SkCanvas.h"
#include "SkDocument.h"
#include "SkPicture.h"
+#include "SkPictureRecorder.h"
#include "SkStream.h"
#include "SkRect.h"
@@ -32,15 +33,22 @@ namespace android {
struct PageRecord {
PageRecord(int width, int height, const SkRect& contentRect)
- : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
+ : mPictureRecorder(new SkPictureRecorder())
+ , mPicture(NULL)
+ , mWidth(width)
+ , mHeight(height) {
mContentRect = contentRect;
}
~PageRecord() {
- mPicture->unref();
+ delete mPictureRecorder;
+ if (NULL != mPicture) {
+ mPicture->unref();
+ }
}
- SkPicture* const mPicture;
+ SkPictureRecorder* mPictureRecorder;
+ SkPicture* mPicture;
const int mWidth;
const int mHeight;
SkRect mContentRect;
@@ -62,8 +70,8 @@ public:
mPages.push_back(page);
mCurrentPage = page;
- SkCanvas* canvas = page->mPicture->beginRecording(
- contentRect.width(), contentRect.height(), 0);
+ SkCanvas* canvas = page->mPictureRecorder->beginRecording(
+ contentRect.width(), contentRect.height(), NULL, 0);
// We pass this canvas to Java where it is used to construct
// a Java Canvas object which dereferences the pointer when it
@@ -75,7 +83,11 @@ public:
void finishPage() {
assert(mCurrentPage != NULL);
- mCurrentPage->mPicture->endRecording();
+ assert(mCurrentPage->mPictureRecorder != NULL);
+ assert(mCurrentPage->mPicture == NULL);
+ mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
+ delete mCurrentPage->mPictureRecorder;
+ mCurrentPage->mPictureRecorder = NULL;
mCurrentPage = NULL;
}
@@ -89,7 +101,7 @@ public:
canvas->clipRect(page->mContentRect);
canvas->translate(page->mContentRect.left(), page->mContentRect.top());
- canvas->drawPicture(*page->mPicture);
+ canvas->drawPicture(page->mPicture);
document->endPage();
}
@@ -97,11 +109,10 @@ public:
}
void close() {
+ assert(NULL == mCurrentPage);
for (unsigned i = 0; i < mPages.size(); i++) {
delete mPages[i];
}
- delete mCurrentPage;
- mCurrentPage = NULL;
}
private:
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index bf47dd3..ee4c619 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -244,6 +244,12 @@ android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
}
static jint
+android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
+{
+ return AudioSystem::newAudioSessionId();
+}
+
+static jint
android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
@@ -1295,6 +1301,7 @@ static JNINativeMethod gMethods[] = {
{"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
{"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely},
{"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
+ {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
{"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
{"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 11f87cc..3d14aaf 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -95,6 +95,7 @@ sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
env->GetLongField(surfaceObj, gSurfaceClassInfo.mNativeObject));
env->MonitorExit(lock);
}
+ env->DeleteLocalRef(lock);
return sur;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f3b5ccf..3067cdd0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2071,6 +2071,14 @@
android:description="@string/permdesc_bindVoiceInteraction"
android:protectionLevel="signature" />
+ <!-- Must be required by hotword enrollment application,
+ to ensure that only the system can interact with it.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
+ android:label="@string/permlab_manageVoiceKeyphrases"
+ android:description="@string/permdesc_manageVoiceKeyphrases"
+ android:protectionLevel="signature|system" />
+
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
to ensure that only the system can bind to it.
@hide -->
@@ -2699,7 +2707,8 @@
android:theme="@style/Theme.Holo.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
- android:multiprocess="true">
+ android:multiprocess="true"
+ android:documentLaunchMode="never">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index bdf27c8..0564a8f 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -145,7 +145,7 @@
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
- style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+ style="@style/Widget.StatusBar.Material.ProgressBar"
/>
</LinearLayout>
<ImageView
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index c89b9f9..f8e1986 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -38,7 +38,6 @@
android:minHeight="@dimen/notification_large_icon_height"
android:paddingTop="2dp"
android:orientation="vertical"
- android:background="@color/notification_media_info_bg"
>
<LinearLayout
android:id="@+id/line1"
@@ -147,7 +146,7 @@
android:layout_height="6dp"
android:layout_gravity="top"
android:visibility="gone"
- style="@style/Widget.StatusBar.Material.ProgressBar"
+ style="@style/Widget.StatusBar.Material.ProgressBar.Media"
/>
</FrameLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 6f8c3a9..1de5add 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -99,7 +99,7 @@
android:layout_marginEnd="8dp"
android:visibility="gone"
android:layout_weight="0"
- style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+ style="@style/Widget.StatusBar.Material.ProgressBar"
/>
<TextView android:id="@+id/big_text"
android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 8d82a17..6052fb0 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -36,4 +36,8 @@
<!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
<dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+ <!-- Number of notifications to keep in the notification service historical archive.
+ Reduced intentionally for watches to retain minimal memory footprint -->
+ <integer name="config_notificationServiceArchiveSize">1</integer>
+
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5b362fc..2fea91e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6390,6 +6390,16 @@
<attr name="settingsActivity" />
</declare-styleable>
+ <!-- Use <code>voice-enrollment-application</code>
+ as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
+ by the enrollment application.
+ Described here are the attributes that can be included in that tag. -->
+ <declare-styleable name="VoiceEnrollmentApplication">
+ <attr name="searchKeyphraseId" format="integer" />
+ <attr name="searchKeyphrase" format="string" />
+ <attr name="searchKeyphraseSupportedLocales" format="string" />
+ </declare-styleable>
+
<!-- Attributes used to style the Action Bar. -->
<declare-styleable name="ActionBar">
<!-- The type of navigation to use. -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 9bf2ce8..9f6c7ad 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -135,7 +135,6 @@
<color name="notification_action_legacy_color_filter">#ff555555</color>
<color name="notification_media_action_bg">#00000000</color>
- <color name="notification_media_info_bg">#40FFFFFF</color>
<color name="notification_media_progress">#FFFFFFFF</color>
<!-- Keyguard colors -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9716f0c..9ff9b11 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -595,10 +595,11 @@
<integer name="config_shutdownBatteryTemperature">680</integer>
<!-- Display low battery warning when battery level dips to this value -->
- <integer name="config_lowBatteryWarningLevel">20</integer>
+ <integer name="config_lowBatteryWarningLevel">15</integer>
- <!-- Close low battery warning when battery level reaches this value -->
- <integer name="config_lowBatteryCloseWarningLevel">25</integer>
+ <!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel
+ plus this -->
+ <integer name="config_lowBatteryCloseWarningBump">5</integer>
<!-- Default color for notification LED. -->
<color name="config_defaultNotificationColor">#ffffffff</color>
@@ -627,6 +628,9 @@
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
+ <!-- Number of notifications to keep in the notification service historical archive -->
+ <integer name="config_notificationServiceArchiveSize">250</integer>
+
<!-- Allow the menu hard key to be disabled in LockScreen on some devices -->
<bool name="config_disableMenuKeyInLockScreen">false</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8f3ee60..2792c93 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2185,6 +2185,9 @@
<public type="attr" name="translateY" />
<public type="attr" name="selectableItemBackgroundBorderless" />
<public type="attr" name="elegantTextHeight" />
+ <public type="attr" name="searchKeyphraseId" />
+ <public type="attr" name="searchKeyphrase" />
+ <public type="attr" name="searchKeyphraseSupportedLocales" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2903ac2..f1d9dc3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1122,6 +1122,12 @@
interface of a voice interaction service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_manageVoiceKeyphrases">manage voice keyphrases</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_manageVoiceKeyphrases">Allows the holder to manage the keyphrases for voice hotword detection.
+ Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindRemoteDisplay">bind to a remote display</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 92cce25..a40835c 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -345,6 +345,9 @@ please see styles_device_defaults.xml.
</style>
<style name="Widget.StatusBar.Material.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal">
+ </style>
+
+ <style name="Widget.StatusBar.Material.ProgressBar.Media">
<item name="android:progressDrawable">@drawable/notification_material_media_progress</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2ea7421..f2550ab 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1509,7 +1509,7 @@
<java-symbol type="integer" name="config_defaultNotificationLedOn" />
<java-symbol type="integer" name="config_deskDockKeepsScreenOn" />
<java-symbol type="integer" name="config_lightSensorWarmupTime" />
- <java-symbol type="integer" name="config_lowBatteryCloseWarningLevel" />
+ <java-symbol type="integer" name="config_lowBatteryCloseWarningBump" />
<java-symbol type="integer" name="config_lowBatteryWarningLevel" />
<java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
<java-symbol type="integer" name="config_networkTransitionTimeout" />
@@ -1518,6 +1518,7 @@
<java-symbol type="integer" name="config_notificationsBatteryLedOn" />
<java-symbol type="integer" name="config_notificationsBatteryLowARGB" />
<java-symbol type="integer" name="config_notificationsBatteryMediumARGB" />
+ <java-symbol type="integer" name="config_notificationServiceArchiveSize" />
<java-symbol type="integer" name="config_radioScanningTimeout" />
<java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
@@ -1678,7 +1679,6 @@
<java-symbol type="drawable" name="notification_material_bg" />
<java-symbol type="drawable" name="notification_material_media_progress" />
<java-symbol type="color" name="notification_media_action_bg" />
- <java-symbol type="color" name="notification_media_info_bg" />
<java-symbol type="color" name="notification_media_progress" />
<java-symbol type="id" name="media_action_area" />
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index c6bccfe..abb960c 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -106,6 +106,7 @@ font_src_files := \
ifeq ($(MINIMAL_FONT_FOOTPRINT),true)
$(eval $(call create-font-symlink,Roboto-Black.ttf,Roboto-Bold.ttf))
+$(eval $(call create-font-symlink,Roboto-BlackItalic.ttf,Roboto-BoldItalic.ttf))
$(eval $(call create-font-symlink,Roboto-Light.ttf,Roboto-Regular.ttf))
$(eval $(call create-font-symlink,Roboto-LightItalic.ttf,Roboto-Italic.ttf))
$(eval $(call create-font-symlink,Roboto-Medium.ttf,Roboto-Regular.ttf))
@@ -120,6 +121,7 @@ $(eval $(call create-font-symlink,RobotoCondensed-BoldItalic.ttf,Roboto-BoldItal
else # !MINIMAL_FONT
font_src_files += \
Roboto-Black.ttf \
+ Roboto-BlackItalic.ttf \
Roboto-Light.ttf \
Roboto-LightItalic.ttf \
Roboto-Medium.ttf \
diff --git a/data/fonts/Roboto-BlackItalic.ttf b/data/fonts/Roboto-BlackItalic.ttf
new file mode 100644
index 0000000..3ebdc7d
--- /dev/null
+++ b/data/fonts/Roboto-BlackItalic.ttf
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index e5573bb..70fc6a2 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -25,6 +25,7 @@ PRODUCT_PACKAGES := \
Roboto-Italic.ttf \
Roboto-BoldItalic.ttf \
Roboto-Black.ttf \
+ Roboto-BlackItalic.ttf \
Roboto-Light.ttf \
Roboto-LightItalic.ttf \
Roboto-Medium.ttf \
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
index 646b33b..8c59fea 100644
--- a/data/fonts/system_fonts.xml
+++ b/data/fonts/system_fonts.xml
@@ -82,6 +82,7 @@
</nameset>
<fileset>
<file>Roboto-Black.ttf</file>
+ <file>Roboto-BlackItalic.ttf</file>
</fileset>
</family>
diff --git a/docs/html/distribute/engage/analytics.jd b/docs/html/distribute/engage/analytics.jd
new file mode 100644
index 0000000..5f7cade
--- /dev/null
+++ b/docs/html/distribute/engage/analytics.jd
@@ -0,0 +1,50 @@
+page.title=Understand User Behavior
+page.metaDescription=Use Google Analytics to learn what your users like and what keeps them coming back.
+page.tags="analytics, user behavior"
+page.image=/images/gp-analytics.jpg
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-analytics.jpg" style="width:320px">
+</div>
+
+
+<p>
+ Link your Google Play Developer Console with Google Analytics to learn much
+ more about how users interact with your app &mdash; before and after they
+ download it.
+</p>
+
+<p>
+ Start by discovering how many people visit your Google Play listing page,
+ where they come from, and how many go on to install your app. Once the app is
+ launched, use Google Analytics to see which of your features are most
+ popular, where power users spend their time, who tends to make in-app
+ purchases, and more.
+</p>
+
+<p>
+ Google Analytics delivers the numbers in real time, so you can act fast to
+ update your landing page and your app. <a href=
+ "http://www.google.com/analytics/mobile/">Learn more</a>.
+</p>
+
+<p>
+ If you have a Google Analytics account already, linking it to Google Play
+ takes just a few moments. You can also link your Google Analytics account to
+ Admob to start gaining more user insights to improve your in-app marketing.
+</p>
+
+ <div class="headerLine clearfloat">
+ <h2 id="related-resources">
+ Related Resources
+ </h2>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/engage/analytics"
+ data-sortorder="-timestamp"
+ data-cardsizes="9x3"
+ data-maxresults="6">
+</div> \ No newline at end of file
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
index 0417ba1..a25c3c6 100644
--- a/docs/html/distribute/engage/deep-linking.jd
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -1,13 +1,13 @@
page.title=Deep Link to Bring Users Back
-page.metaDescription=Use deep links to bring your users into your apps from social posts or search.
+page.metaDescription=Use deep links to bring your users into your apps from social posts, search, or ads.
page.tags="app indexing, google+ signin"
page.image=/images/gp-listing-4.jpg
@jd:body
<p>
- Use deep links to bring your users into your apps from social posts or
- search.
+ Use deep links to bring your users into your apps from social posts,
+ search, or ads.
</p>
<div class="headerLine">
@@ -47,6 +47,11 @@ page.image=/images/gp-listing-4.jpg
<h2>Deep Linking from Google Search &mdash; App Indexing</h2>
</div>
+
+<div style="float:right;">
+ <img src="/images/gp-listing-4.jpg" style="padding-top:1em;padding-left:2em;">
+</div>
+
<p>
Another way to bring users back to your apps is to apply for app indexing.
</p>
@@ -60,11 +65,29 @@ page.image=/images/gp-listing-4.jpg
content</a>.
</p>
-<div>
- <img src="{@docRoot}images/gp-listing-4.jpg" style="padding-top:1em;">
+<div class="clearfloat" style="margin-top:2em;"></div>
+
+<div style="float:right;width:340px;padding-left:2em;">
+ <img src="/images/gp-ads-linking2.jpg" style="padding-top:1em;">
</div>
-<div class="headerLine">
+<div class="headerLine ">
+<h2>Deep Linking from Google Ads</h2>
+</div>
+<p>
+ Ads can remind users about the apps they already have.
+</p>
+
+<p>
+ As with deep links from Google's organic search results, AdWords deep links
+ send users directly to the relevant pages in apps they already have on their
+ mobile device. A mobile search for "flights to London," for instance, could
+ take a user straight to the London page in a travel app. <a href=
+ "http://www.thinkwithgoogle.com/products/ads-apps.html"
+ class="external-link">Learn more</a>.
+</p>
+
+<div class="headerLine clearfloat">
<h2 id="related-resources">
Related Resources
</h2>
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
index 0314f8c..596051a 100644
--- a/docs/html/distribute/engage/engage_toc.cs
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -37,6 +37,12 @@
</li>
<li class="nav-section">
<div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/analytics.html">
+ <span class="en">Understand User Behavior</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
var:toroot?>distribute/engage/app-updates.html">
<span class="en">Update Regularly</span></a>
</div>
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
index f8cd1ee..2b103c3 100644
--- a/docs/html/distribute/engage/index.jd
+++ b/docs/html/distribute/engage/index.jd
@@ -15,8 +15,8 @@ nonavpage=true
<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/engagelanding"
- data-cardSizes="6x6"
- data-maxResults="9">
+ data-cardSizes="9x6,9x6,6x6,6x6,6x6,9x6,9x6,6x6,6x6,6x6"
+ data-maxResults="10">
</div>
<h3>Related Resources</h3>
diff --git a/docs/html/distribute/engage/widgets.jd b/docs/html/distribute/engage/widgets.jd
index 286adea..6adb55c 100644
--- a/docs/html/distribute/engage/widgets.jd
+++ b/docs/html/distribute/engage/widgets.jd
@@ -1,5 +1,5 @@
page.title=Build Useful Widgets
-page.metaDescription=Use widgets to remind users about important information in your apps and games, even when your apps are closed.
+page.metaDescription=Use home screen widgets to remind users about important information in your apps and games, even when your apps are closed.
page.tags=""
page.image=/images/gp-engage-0.jpg
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
index bcb1e52..9a847ff 100644
--- a/docs/html/distribute/monetize/ads.jd
+++ b/docs/html/distribute/monetize/ads.jd
@@ -10,17 +10,32 @@ page.image=/distribute/images/advertising.png
</div>
<p>
- In-app advertising offers a quick and easy way to incorporate a monetization
- option into both your <a href=
+ Ads can be a quick and easy way to earn more from your <a href=
"{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
"{@docRoot}distribute/monetize/premium.html">premium</a>, and <a href=
- "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps. </p>
+ "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps.
+ AdMob and the Google Mobile Ads SDK let you add advertising to your apps with
+ just a few lines of code.
+</p>
+
+<p>
+ The question is: which model gets the best results for your app? Google's ad
+ tools are made to help you figure out what combination works best for both
+ your audience and your bottom line. </p>
-<p>Using <a href=
+<p>Start by linking your AdMob and Google
+ Analytics accounts to get better insights and more earning power: for
+ instance, AdMob can promote in-app purchases to the people who buy them most
+ often, while showing income-generating ads to those less likely to buy right
+ now.
+</p>
+
+<p>
+ Using <a href=
"http://www.google.com/ads/admob/monetize.html#subid=us-en-et-dac">AdMob</a>
- and the <a href="{@docRoot}google/play-services/ads.html">Google
- Mobile Ads SDK</a> included in Google Play Services, you’re able to add
- advertising into your apps, with just a few lines of code.
+ and the <a href="{@docRoot}google/play-services/ads.html">Google Mobile Ads
+ SDK</a> included in Google Play Services, you’re able to add advertising into
+ your apps, with just a few lines of code.
</p>
<p>
@@ -30,36 +45,33 @@ page.image=/distribute/images/advertising.png
<ul>
<li>
<p>
- <strong>Placement within your apps</strong> &mdash; Well placed ads will
- optimize your revenue by making it more likely that users will ‘click
- through’. Poorly placed ads can result in low click-through rates, and in
- the worse cases poor rating and users rapidly abandoning your apps. You
- can get advice on how to best place ads from the developer training on
- <a href=
- "{@docRoot}training/monetization/ads-and-ux.html">using
- ads</a>.
+ <strong>Placement within your apps</strong> &mdash; Well-placed ads make
+ it more likely that users will click through and convert. Poorly-placed
+ ads lead to lower click-through rates, and even poor ratings and users
+ abandoning your apps. Our <a href=
+ "{@docRoot}training/monetization/ads-and-ux.html">developer training</a>
+ on using ads shows some of the best ways to place ads.
</p>
</li>
<li>
<p>
<strong>Ad formats</strong> &mdash; Every app offers a different type of
- experience for users, so it’s important to consider the format of ads
- you’re using to ensure it’s compatible with the experience. While banner
- ads may work well for a flashlight utility app, an immersive gaming app
- may benefit more from a video interstitial. Mismatched ad formats may
- negatively affect your users’ experience and ad revenue, so try to select
- formats that fit well with the content and flow of your apps.
+ experience for users, so it’s important that your ad formats match that
+ experience. While banner ads may work well for a flashlight utility app,
+ an immersive gaming app may benefit more from a video interstitial.
+ Mismatched ad formats can make users unhappy and leave money on the
+ table.
</p>
</li>
<li>
<p>
- <strong>Maximizing your performance</strong> &mdash; Ensure you’re optimizing
- your advertising revenue by maximizing your CPMs <em>and</em> fill rate.
- Often ad providers will cite very high CPMs but will have a low fill rate
- that can severely decrease your effective CPM, so look at both of these
- figures. Also consider using a <a href=
+ <strong>Maximizing your performance</strong> &mdash; Make sure you’re
+ optimizing your advertising revenue by maximizing your CPMs and fill
+ rate. Ad providers often cite their very high CPMs but don't mention low
+ fill rates that can severely decrease your effective CPM. Be sure to look
+ at both of these figures. Consider using a <a href=
"https://support.google.com/admob/v2/answer/3063564?hl=en&amp;ref_topic=3063091#subid=us-en-et-dac">
mediation</a> solution if you’d like to use multiple ad providers in your
apps. Look for solutions that offer yield management or <a href=
@@ -71,30 +83,43 @@ page.image=/distribute/images/advertising.png
<li>
<p>
- <strong>Exercising control options</strong> &mdash; A variety of ads promoting a
- broad selection of other services or apps may show up within you apps.
- Depending on your goals and the type of experience you want to provide
- your users, it may make sense to <a href=
+ <strong>Exercising control options</strong> &mdash; A variety of ads may
+ show up within your app. It may make sense to <a href=
"https://support.google.com/admob/v2/answer/3150235?hl=enl#subid=us-en-et-dac">
- block</a> certain advertisements from appearing. Some developers don’t
- want apps in a similar category showing to their users, but some don’t
- mind.
+ block</a> certain of those advertisements from appearing, depending on
+ your goals and the type of experience you want to provide. Some
+ developers, for instance, don’t want ads for apps in their same category
+ showing to their users, while others don’t mind at all.
</p>
</li>
<li>
<p>
- <strong>Cross promoting your other apps</strong> &mdash; Ads can be used for
- more than just earning revenue. Consider using <a href=
+ <strong>Cross promoting your other apps</strong> &mdash; Ads can do more
+ than earn revenue. Consider running <a href=
"https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
- house ads</a> within your apps to create awareness and promote your
- entire portfolio of apps. When launching new apps, an easy way to quickly
- attract users is to promote directly to your existing customers.
+ house ads</a> within your apps to promote other apps in your portfolio.
+ When you launch a new app, this kind of promotion is a free and easy way
+ to attract new users quickly.
</p>
</li>
</ul>
<p>
+ Don't forget that paid channels like AdWords and YouTube can help you cast a
+ wider net by reaching targeted audiences outside the app ecosystem. They're a
+ great way to find new users at a price that you control. <a href=
+ "https://support.google.com/adwords/answer/2549053">Learn more</a>.
+</p>
+
+<p>
+ To start monetizing with ads, sign up for AdMob and integrate the Google
+ Mobile Ads SDK into your apps. If you also need to manage direct deals with
+ advertisers, consider using DoubleClick for Publishers Small Business.
+</p>
+
+
+<p>
To start monetizing with ads sign up for <a href=
"http://www.google.com/ads/admob/#subid=us-en-et-dac">AdMob</a> and integrate
the <a href="https://developers.google.com/mobile-ads-sdk/download">Google
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
index 77ef609..a810f36 100644
--- a/docs/html/distribute/users/index.jd
+++ b/docs/html/distribute/users/index.jd
@@ -14,8 +14,8 @@ nonavpage=true
<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/users"
- data-cardSizes="6x6, 6x6, 6x6, 9x6, 9x6, 6x6, 6x6, 6x6"
- data-maxResults="8">
+ data-cardSizes="6x6"
+ data-maxResults="6">
</div>
<h3>Related resources</h3>
diff --git a/docs/html/distribute/users/promote-with-ads.jd b/docs/html/distribute/users/promote-with-ads.jd
new file mode 100644
index 0000000..1e28ae1
--- /dev/null
+++ b/docs/html/distribute/users/promote-with-ads.jd
@@ -0,0 +1,45 @@
+page.title=Promote Your App with Ads
+page.metaDescription=Promote your app through AdMob, AdWords, and YouTube to find new users at the right moment.
+page.image=/images/gp-ads-console.jpg
+page.tags="users, ads, analytics"
+
+@jd:body
+
+<p>
+ AdMob is Google's advertising platform for mobile apps. You can use it to
+ monetize your app and promote your apps, and you can link your Google
+ Analytics account to AdMob so you can analyze your apps &mdash; all in one
+ place.
+</p>
+
+<p>
+ <a href="http://www.google.com/ads/admob/">AdMob</a> is the largest mobile ad
+ app network. But you get more than just massive scale: AdMob will soon help
+ you find the right users in related apps. If your app is for bicycling, AdMob
+ can promote your app on other fitness and cycling-related apps worldwide.
+ <a href=
+ "https://apps.admob.com/admob/signup?subid=us-en-et-dac&_adc=ww-ww-et-admob2&hl=en">
+ Sign up for AdMob</a>.
+</p>
+
+<p>
+ AdMob also offers new solutions to help you achieve app-related goals such as
+ downloads, re-engagement and in-app purchases using Google search and the
+ Google Display Network. These solutions include streamlined campaign creation
+ flows and tools to track performance across the entire app lifecycle.
+ <a href="https://support.google.com/adwords/answer/2549053?hl=en">Learn
+ More</a>.
+</p>
+<div style="margin-top:2em;">
+ <img src="{@docRoot}images/gp-ads-console.jpg">
+</div>
+
+<div class="headerLine">
+<h2 id="related-resources">Related Resources</h2>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/users/promotewithads"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div> \ No newline at end of file
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
index a2437a6..1f173cb 100644
--- a/docs/html/distribute/users/users_toc.cs
+++ b/docs/html/distribute/users/users_toc.cs
@@ -28,7 +28,12 @@
</a>
</div>
</li>
-
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/promote-with-ads.html">
+ <span class="en">Promote with Ads</span>
+ </a>
+ </div>
+ </li>
</ul>
diff --git a/docs/html/images/gp-ads-console.jpg b/docs/html/images/gp-ads-console.jpg
new file mode 100644
index 0000000..158e31d
--- /dev/null
+++ b/docs/html/images/gp-ads-console.jpg
Binary files differ
diff --git a/docs/html/images/gp-ads-linking2.jpg b/docs/html/images/gp-ads-linking2.jpg
new file mode 100644
index 0000000..0c2f731
--- /dev/null
+++ b/docs/html/images/gp-ads-linking2.jpg
Binary files differ
diff --git a/docs/html/images/gp-analytics.jpg b/docs/html/images/gp-analytics.jpg
new file mode 100644
index 0000000..e1a92c7
--- /dev/null
+++ b/docs/html/images/gp-analytics.jpg
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 8a4ac47..5ee01f3 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -49,7 +49,8 @@ var RESOURCE_COLLECTIONS = {
"distribute/users/your-listing.html",
"distribute/users/build-buzz.html",
"distribute/users/build-community.html",
- "distribute/users/expand-to-new-markets.html"
+ "distribute/users/expand-to-new-markets.html",
+ "distribute/users/promote-with-ads.html"
]
},
"distribute/engagelanding": {
@@ -60,6 +61,7 @@ var RESOURCE_COLLECTIONS = {
"distribute/engage/easy-signin.html",
"distribute/engage/deep-linking.html",
"distribute/engage/game-services.html",
+ "distribute/engage/analytics.html",
"distribute/engage/app-updates.html",
"distribute/engage/community.html",
"distribute/engage/video.html"
@@ -214,6 +216,13 @@ var RESOURCE_COLLECTIONS = {
"distribute/stories/localization.html"
]
},
+ "distribute/users/promotewithads": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+ "distribute/essentials/optimizing-your-app.html"
+ ]
+ },
"distribute/users/buildbuzz": {
"title": "",
"resources": [
@@ -394,6 +403,14 @@ var RESOURCE_COLLECTIONS = {
"http://play.google.com/about/developer-content-policy.html"
]
},
+ "distribute/engage/analytics": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/analytics/mobile/",
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
+ "https://developers.google.com/analytics/devguides/collection/android/"
+ ]
+ },
"distribute/engage/widgets": {
"title": "",
"resources": [
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index f26b747..d8db5bf 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -726,6 +726,21 @@ DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
"tags": [
"#engagement",
],
+ "url": "http://www.google.com/analytics/mobile/",
+ "timestamp": 1383243492000,
+ "image": "http://www.google.com//analytics/images/heros/mobile-index.jpg",
+ "title": "Google Mobile App Analytics",
+ "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
+ "keywords": ["analytics,user behavior"],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#engagement",
+ ],
"url": "https://developers.google.com/app-indexing/",
"timestamp": 1383243492000,
"image": "https://developers.google.com/app-indexing/images/allthecooks_srp.png",
@@ -1101,4 +1116,17 @@ DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
"type": "Google+",
"titleFriendly": ""
},
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["analytics"],
+ "url": "https://developers.google.com/analytics/devguides/collection/android/",
+ "timestamp": null,
+ "image": "https://developers.google.com/analytics/images/home/gear-logo.png",
+ "title": "Google Mobile App Analytics SDK",
+ "summary": "The Google Analytics for Mobile Apps SDKs make it easy for you to implement Google Analytics in your mobile application.",
+ "keywords": ["analytics, user behavior"],
+ "type": "sdk",
+ "titleFriendly": ""
+ }
]); \ No newline at end of file
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 06cf253..ef0a411 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -194,6 +194,11 @@ public final class Bitmap implements Parcelable {
* while {@link #getAllocationByteCount()} will reflect that of the initial
* configuration.</p>
*
+ * <p>Note: This may change this result of hasAlpha(). When converting to 565,
+ * the new bitmap will always be considered opaque. When converting from 565,
+ * the new bitmap will be considered non-opaque, and will respect the value
+ * set by setPremultiplied().</p>
+ *
* <p>WARNING: This method should NOT be called on a bitmap currently used
* by the view system. It does not make guarantees about how the underlying
* pixel buffer is remapped to the new config, just that the allocation is
@@ -217,7 +222,8 @@ public final class Bitmap implements Parcelable {
throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
}
- nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length);
+ nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+ mIsPremultiplied);
mWidth = width;
mHeight = height;
}
@@ -1586,7 +1592,8 @@ public final class Bitmap implements Parcelable {
private static native void nativeDestructor(long nativeBitmap);
private static native boolean nativeRecycle(long nativeBitmap);
private static native void nativeReconfigure(long nativeBitmap, int width, int height,
- int config, int allocSize);
+ int config, int allocSize,
+ boolean isPremultiplied);
private static native boolean nativeCompress(long nativeBitmap, int format,
int quality, OutputStream stream,
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index de458af..a021165 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -53,7 +53,7 @@ public class Picture {
public Picture(Picture src) {
this(nativeConstructor(src != null ? src.mNativePicture : 0), false);
}
-
+
/**
* To record a picture, call beginRecording() and then draw into the Canvas
* that is returned. Nothing we appear on screen, but all of the draw
@@ -67,7 +67,7 @@ public class Picture {
mRecordingCanvas = new RecordingCanvas(this, ni);
return mRecordingCanvas;
}
-
+
/**
* Call endRecording when the picture is built. After this call, the picture
* may be drawn, but the canvas that was returned by beginRecording must not
@@ -92,16 +92,19 @@ public class Picture {
* does not reflect (per se) the content of the picture.
*/
public native int getHeight();
-
+
/**
- * Draw this picture on the canvas. The picture may have the side effect
- * of changing the matrix and clip of the canvas.
- *
+ * Draw this picture on the canvas.
+ * <p>
+ * Prior to {@link android.os.Build.VERSION_CODES#L}, this call could
+ * have the side effect of changing the matrix and clip of the canvas
+ * if this picture had imbalanced saves/restores.
+ *
* <p>
* <strong>Note:</strong> This forces the picture to internally call
* {@link Picture#endRecording()} in order to prepare for playback.
*
- * @param canvas The picture is drawn to this canvas
+ * @param canvas The picture is drawn to this canvas
*/
public void draw(Canvas canvas) {
if (mRecordingCanvas != null) {
@@ -119,7 +122,7 @@ public class Picture {
* <p>
* <strong>Note:</strong> a picture created from an input stream cannot be
* replayed on a hardware accelerated canvas.
- *
+ *
* @see #writeToStream(java.io.OutputStream)
* @deprecated The recommended alternative is to not use writeToStream and
* instead draw the picture into a Bitmap from which you can persist it as
@@ -167,7 +170,7 @@ public class Picture {
final long ni() {
return mNativePicture;
}
-
+
private Picture(long nativePicture, boolean fromStream) {
if (nativePicture == 0) {
throw new RuntimeException();
@@ -187,7 +190,7 @@ public class Picture {
private static native boolean nativeWriteToStream(long nativePicture,
OutputStream stream, byte[] storage);
private static native void nativeDestructor(long nativePicture);
-
+
private static class RecordingCanvas extends Canvas {
private final Picture mPicture;
@@ -195,7 +198,7 @@ public class Picture {
super(nativeCanvas);
mPicture = pict;
}
-
+
@Override
public void setBitmap(Bitmap bitmap) {
throw new RuntimeException(
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 41cc9d2..79fe4d3 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -165,12 +165,12 @@ public:
ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius)
- : drawTransform(drawTransform)
+ : drawTransform(*drawTransform)
, localClip(localClip)
, opaque(opaque)
- , casterPerimeter(casterPerimeter)
- , transformXY(transformXY)
- , transformZ(transformZ)
+ , casterPerimeter(*casterPerimeter)
+ , transformXY(*transformXY)
+ , transformZ(*transformZ)
, lightCenter(lightCenter)
, lightRadius(lightRadius) {
}
@@ -182,14 +182,19 @@ public:
delete bufferPair;
}
- // Note - only the localClip is deep copied, since other pointers point at Allocator controlled
- // objects, which are safe for the entire frame
- const Matrix4* drawTransform;
+ /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
+ * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
+ * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
+ *
+ * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
+ * before tearning down single-frame LinearAllocators.
+ */
+ const Matrix4 drawTransform;
const Rect localClip;
bool opaque;
- const SkPath* casterPerimeter;
- const Matrix4* transformXY;
- const Matrix4* transformZ;
+ const SkPath casterPerimeter;
+ const Matrix4 transformXY;
+ const Matrix4 transformZ;
const Vector3 lightCenter;
const float lightRadius;
};
@@ -281,8 +286,8 @@ public:
VertexBuffer* ambientBuffer = new VertexBuffer;
VertexBuffer* spotBuffer = new VertexBuffer;
- tessellateShadows(t->drawTransform, &t->localClip, t->opaque, t->casterPerimeter,
- t->transformXY, t->transformZ, t->lightCenter, t->lightRadius,
+ tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
+ &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
*ambientBuffer, *spotBuffer);
t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ded10a1..4988f19 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -47,7 +47,7 @@ namespace renderthread {
#define SETUP_TASK(method) \
LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
- "METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
+ "METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \
METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c3d5d94..ba6b214 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1653,6 +1653,25 @@ public class AudioManager {
}
}
+
+ /**
+ * Return a new audio session identifier not associated with any player or effect.
+ * It can for instance be used to create one of the {@link android.media.audiofx.AudioEffect}
+ * objects.
+ * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
+ * system failed to allocate a new session.
+ */
+ public int allocateAudioSessionId() {
+ int session = AudioSystem.newAudioSessionId();
+ if (session > 0) {
+ return session;
+ } else {
+ Log.e(TAG, "Failure to allocate a new audio session ID");
+ return ERROR;
+ }
+ }
+
+
/*
* Sets a generic audio configuration parameter. The use of these parameters
* are platform dependant, see libaudio
@@ -2998,7 +3017,8 @@ public class AudioManager {
/** @hide
*/
public static final int SUCCESS = AudioSystem.SUCCESS;
- /** @hide
+ /**
+ * A default error code.
*/
public static final int ERROR = AudioSystem.ERROR;
/** @hide
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index c8d64ce..9fbcd18 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -130,6 +130,11 @@ public class AudioSystem
public static native boolean isSourceActive(int source);
/*
+ * Returns a new unused audio session ID
+ */
+ public static native int newAudioSessionId();
+
+ /*
* Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependent, see libaudio
*
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 52045d3..7ff2c2e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -272,6 +272,15 @@ public final class TvContract {
/** A generic channel type. */
public static final int TYPE_OTHER = 0x0;
+ /** The channel type for NTSC. */
+ public static final int TYPE_NTSC = 0x1;
+
+ /** The channel type for PAL. */
+ public static final int TYPE_PAL = 0x2;
+
+ /** The channel type for SECAM. */
+ public static final int TYPE_SECAM = 0x3;
+
/** The special channel type used for pass-through inputs such as HDMI. */
public static final int TYPE_PASSTHROUGH = 0x00010000;
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 157dd49..fbe5340 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -24,6 +24,7 @@
#include <SkBitmap.h>
#include <media/IMediaHTTPService.h>
#include <media/mediametadataretriever.h>
+#include <media/mediascanner.h>
#include <private/media/VideoFrame.h>
#include "jni.h"
@@ -337,17 +338,13 @@ static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
return NULL;
}
- unsigned int len = mediaAlbumArt->mSize;
- char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
- jbyteArray array = env->NewByteArray(len);
+ jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
if (!array) { // OutOfMemoryError exception has already been thrown.
ALOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
} else {
- jbyte* bytes = env->GetByteArrayElements(array, NULL);
- if (bytes != NULL) {
- memcpy(bytes, data, len);
- env->ReleaseByteArrayElements(array, bytes, 0);
- }
+ const jbyte* data =
+ reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+ env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
}
// No need to delete mediaAlbumArt here
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index b520440..321c2e3 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -348,17 +348,16 @@ android_media_MediaScanner_extractAlbumArt(
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- MediaAlbumArt* mediaAlbumArt =
- reinterpret_cast<MediaAlbumArt*>(mp->extractAlbumArt(fd));
+ MediaAlbumArt* mediaAlbumArt = mp->extractAlbumArt(fd);
if (mediaAlbumArt == NULL) {
return NULL;
}
- jbyteArray array = env->NewByteArray(mediaAlbumArt->mSize);
+ jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
if (array != NULL) {
- jbyte* bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, &mediaAlbumArt->mData[0], mediaAlbumArt->mSize);
- env->ReleaseByteArrayElements(array, bytes, 0);
+ const jbyte* data =
+ reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+ env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
}
done:
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
deleted file mode 100644
index 5ce8708..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
deleted file mode 100644
index bdf0f67..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
deleted file mode 100644
index 461535c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
deleted file mode 100644
index 7b03a11..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_01.xml b/packages/SystemUI/res/drawable/ic_notify_zen.xml
index ff37d9a..c46455b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_01.xml
+++ b/packages/SystemUI/res/drawable/ic_notify_zen.xml
@@ -15,14 +15,14 @@ Copyright (C) 2014 The Android Open Source Project
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="24dp"
+ android:height="24dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+ android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
deleted file mode 100644
index dc30a53..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_02.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
index bb4465f..b6a5cad 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_02.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
@@ -19,10 +19,10 @@ Copyright (C) 2014 The Android Open Source Project
android:height="64dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,4.0c-3.48,0.0 -6.3,2.82 -6.3,6.3C5.7,15.02 12.0,22.0 12.0,22.0s6.3,-6.98 6.3,-11.7C18.3,6.82 15.48,4.0 12.0,4.0zM12.0,12.55c-1.24,0.0 -2.25,-1.01 -2.25,-2.25S10.76,8.05 12.0,8.05c1.24,0.0 2.25,1.01 2.25,2.25S13.24,12.55 12.0,12.55z"/>
+ android:fill="#4DFFFFFF"
+ android:pathData="M41.3,41.7L36.6,37.0L24.0,24.5l-7.1,-7.1L14.0,14.5L8.5,9.0L6.0,11.5l5.6,5.6c-5.1,6.3 -4.7,15.5 1.1,21.4c3.1,3.1 7.2,4.7 11.3,4.7c3.6,0.0 7.1,-1.2 10.1,-3.6l5.4,5.4l2.5,-2.5L41.3,41.7zM24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5c0.0,-2.6 0.9,-5.1 2.4,-7.2l9.6,9.6L24.0,39.2zM24.0,10.2l0.0,9.2l14.5,14.5c2.7,-5.9 1.7,-13.1 -3.2,-18.0L24.0,4.5l0.0,0.0l0.0,0.0L16.6,12.0l2.8,2.8L24.0,10.2z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_04.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
index 0c0fb3b..e8d59e0 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_04.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
@@ -19,10 +19,10 @@ Copyright (C) 2014 The Android Open Source Project
android:height="64dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M12.0,10.0c-2.32,0.0 -4.2,1.88 -4.2,4.2C7.8,17.35 12.0,22.0 12.0,22.0s4.2,-4.65 4.2,-7.8C16.2,11.88 14.32,10.0 12.0,10.0zM12.0,15.7c-0.83,0.0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.83,0.0 1.5,0.67 1.5,1.5S12.83,15.7 12.0,15.7z"/>
+ android:pathData="M35.3,15.9L24.0,4.5l0.0,0.0l0.0,0.0L12.7,15.9c-6.2,6.2 -6.2,16.4 0.0,22.6c3.1,3.1 7.2,4.7 11.3,4.7s8.2,-1.6 11.3,-4.7C41.6,32.2 41.6,22.1 35.3,15.9zM24.0,39.2L24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5s1.2,-6.2 3.5,-8.5l8.5,-8.5L24.0,39.2z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_03.xml b/packages/SystemUI/res/drawable/ic_qs_location_03.xml
deleted file mode 100644
index 956a8c3..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_03.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_05.xml b/packages/SystemUI/res/drawable/ic_qs_location_05.xml
deleted file mode 100644
index 1a21e2f..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_05.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_06.xml b/packages/SystemUI/res/drawable/ic_qs_location_06.xml
deleted file mode 100644
index 5642a8a..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_06.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,16.0c-1.16,0.0 -2.1,0.94 -2.1,2.1C9.9,19.67 12.0,22.0 12.0,22.0s2.1,-2.33 2.1,-3.9C14.1,16.94 13.16,16.0 12.0,16.0zM12.0,18.85c-0.41,0.0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75c0.41,0.0 0.75,0.34 0.75,0.75S12.41,18.85 12.0,18.85z"/>
- <path
- android:pathData="M11.99,15c-1.35,0,-2.45,1.1,-2.45,2.45 c0,1.84,2.45,4.55,2.45,4.55s2.45,-2.71,2.45,-4.55C14.44,16.1,13.34,15,11.99,15z M11.99,18.33c-0.48,0,-0.88,-0.39,-0.88,-0.88 s0.39,-0.88,0.88,-0.88c0.48,0,0.87,0.39,0.87,0.88S12.47,18.33,11.99,18.33z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_07.xml b/packages/SystemUI/res/drawable/ic_qs_location_07.xml
deleted file mode 100644
index 1ad2ebc..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_07.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,9c-2.51,0,-4.55,2.04,-4.55,4.55 C7.45,16.96,12,22,12,22s4.55,-5.04,4.55,-8.45C16.55,11.04,14.51,9,12,9z M12,15.18c-0.9,0,-1.63,-0.73,-1.63,-1.62 s0.73,-1.62,1.63,-1.62c0.9,0,1.62,0.73,1.62,1.62S12.9,15.18,12,15.18z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_08.xml b/packages/SystemUI/res/drawable/ic_qs_location_08.xml
deleted file mode 100644
index 179bc66..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_08.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,6c-3.09,0,-5.6,2.51,-5.6,5.6 C6.4,15.8,12,22,12,22s5.6,-6.2,5.6,-10.4C17.6,8.51,15.09,6,12,6z M12,13.6c-1.1,0,-2,-0.9,-2,-2s0.9,-2,2,-2c1.1,0,2,0.9,2,2 S13.1,13.6,12,13.6z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_09.xml b/packages/SystemUI/res/drawable/ic_qs_location_09.xml
deleted file mode 100644
index 6169af5..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_09.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,4c-3.48,0,-6.3,2.82,-6.3,6.3 C5.7,15.02,12,22,12,22s6.3,-6.98,6.3,-11.7C18.3,6.82,15.48,4,12,4z M12,12.55c-1.24,0,-2.25,-1.01,-2.25,-2.25S10.76,8.05,12,8.05 c1.24,0,2.25,1.01,2.25,2.25S13.24,12.55,12,12.55z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_10.xml b/packages/SystemUI/res/drawable/ic_qs_location_10.xml
deleted file mode 100644
index 93e2eb4..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_10.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,3C8.33,3,5.35,5.98,5.35,9.65 C5.35,14.64,12,22,12,22s6.65,-7.36,6.65,-12.35C18.65,5.98,15.67,3,12,3z M12,12.02c-1.31,0,-2.38,-1.06,-2.38,-2.38 S10.69,7.28,12,7.28c1.31,0,2.37,1.06,2.37,2.37S13.31,12.02,12,12.02z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
index d28d347..26ebfbf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
@@ -14,18 +13,19 @@ Copyright (C) 2014 The Android Open Source Project
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
-</animation-list>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#4DFFFFFF"
+ android:pathData="M24.0,13.0c2.8,0.0 5.0,2.2 5.0,5.0c0.0,1.5 -0.7,2.8 -1.7,3.7l7.3,7.3c2.0,-3.7 3.4,-7.6 3.4,-11.0c0.0,-7.7 -6.3,-14.0 -14.0,-14.0c-4.0,0.0 -7.5,1.6 -10.1,4.3l6.4,6.4C21.2,13.6 22.5,13.0 24.0,13.0zM32.7,32.2l-9.3,-9.3l-0.2,-0.2L6.5,6.0L4.0,8.5l6.4,6.4c-0.2,1.0 -0.4,2.0 -0.4,3.1c0.0,10.5 14.0,26.0 14.0,26.0s3.3,-3.7 6.8,-8.7l6.7,6.7l2.5,-2.5L32.7,32.2z"/>
+ <path
+ android:pathData="M23.5,22.9l0.0,0.0 -0.20000076,-0.19999886z"
+ android:fill="#4DFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
index 72512ac..bc73005 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
@@ -14,18 +13,16 @@ Copyright (C) 2014 The Android Open Source Project
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
-</animation-list>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M24.0,4.0c-7.7,0.0 -14.0,6.3 -14.0,14.0c0.0,10.5 14.0,26.0 14.0,26.0s14.0,-15.5 14.0,-26.0C38.0,10.3 31.7,4.0 24.0,4.0zM24.0,23.0c-2.8,0.0 -5.0,-2.2 -5.0,-5.0s2.2,-5.0 5.0,-5.0c2.8,0.0 5.0,2.2 5.0,5.0S26.8,23.0 24.0,23.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_11.xml b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
index 09a3e63..70948b7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_11.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
@@ -15,14 +15,14 @@ Copyright (C) 2014 The Android Open Source Project
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="18dp"
+ android:height="18dp"/>
<viewport
android:viewportWidth="24.0"
android:viewportHeight="24.0"/>
<path
- android:pathData="M12,2C8.13,2,5,5.13,5,9c0,5.25,7,13,7,13s7,-7.75,7,-13 C19,5.13,15.87,2,12,2z M12,11.5c-1.38,0,-2.5,-1.12,-2.5,-2.5s1.12,-2.5,2.5,-2.5c1.38,0,2.5,1.12,2.5,2.5S13.38,11.5,12,11.5z"
- android:fill="#4DFFFFFF"/>
+ android:fill="#4DFFFFFF"
+ android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/>
</vector>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
index 84d64b9..e220a16 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -18,48 +18,13 @@
<com.android.systemui.statusbar.SpeedBumpView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:focusable="true"
- android:clickable="true"
+ android:layout_height="@dimen/speed_bump_height"
android:visibility="gone"
>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/speed_bump_height_collapsed"
- android:layout_gravity="top"
- android:orientation="horizontal">
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line_left"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
- <com.android.systemui.statusbar.SpeedBumpDotsLayout
- android:id="@+id/speed_bump_dots_layout"
- android:layout_width="34dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:layout_height="match_parent"
- android:layout_weight="0"/>
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line_right"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
- </LinearLayout>
- <TextView
- android:id="@+id/speed_bump_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:fontFamily="sans-serif-condensed"
- android:textSize="15sp"
- android:singleLine="true"
- android:textColor="#eeeeee"
- android:visibility="invisible"
- android:text="@string/speed_bump_explanation"
- android:paddingTop="4dp" />
+ <com.android.systemui.statusbar.AlphaOptimizedView
+ android:id="@+id/speedbump_line"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="#6fdddddd"
+ android:layout_gravity="center_vertical"/>
</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index bb6f1a9..8c1a9c7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -45,18 +45,6 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
- <!-- The color of the red speed bump dot -->
- <color name="speed_bump_dot_red">#ffd50000</color>
-
- <!-- The color of the blue speed bump dot -->
- <color name="speed_bump_dot_blue">#ff2962ff</color>
-
- <!-- The color of the yellow speed bump dot -->
- <color name="speed_bump_dot_yellow">#ffffd600</color>
-
- <!-- The color of the green speed bump dot -->
- <color name="speed_bump_dot_green">#ff00c853</color>
-
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#e6444444</color>
<!-- The default recents task bar text color. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 35bc7e3..1664c8a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -275,14 +275,8 @@
<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
- <!-- The height of the collapsed speed bump view. -->
- <dimen name="speed_bump_height_collapsed">24dp</dimen>
-
- <!-- The padding inset the explanation text needs compared to the collapsed height -->
- <dimen name="speed_bump_text_padding_inset">10dp</dimen>
-
- <!-- The height of the speed bump dots. -->
- <dimen name="speed_bump_dots_height">5dp</dimen>
+ <!-- The height of the speed bump view. -->
+ <dimen name="speed_bump_height">16dp</dimen>
<!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
<dimen name="collapsed_stack_height">94dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 0fb0f8b..192ba57 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -17,13 +17,16 @@
package com.android.systemui.power;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -54,17 +57,22 @@ public class PowerUI extends SystemUI {
public void start() {
- mLowBatteryAlertCloseLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
- mLowBatteryReminderLevels[0] = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryWarningLevel);
- mLowBatteryReminderLevels[1] = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_criticalBatteryWarningLevel);
-
final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenOffTime = pm.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
mWarnings = new PowerDialogWarnings(mContext);
+ ContentObserver obs = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateBatteryWarningLevels();
+ }
+ };
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, obs, UserHandle.USER_ALL);
+ updateBatteryWarningLevels();
+
// Register for Intent broadcasts for...
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
@@ -73,6 +81,29 @@ public class PowerUI extends SystemUI {
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
}
+ void updateBatteryWarningLevels() {
+ int critLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+
+ final ContentResolver resolver = mContext.getContentResolver();
+ int defWarnLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryWarningLevel);
+ int warnLevel = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+ if (warnLevel == 0) {
+ warnLevel = defWarnLevel;
+ }
+ if (warnLevel < critLevel) {
+ warnLevel = critLevel;
+ }
+
+ mLowBatteryReminderLevels[0] = warnLevel;
+ mLowBatteryReminderLevels[1] = critLevel;
+ mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
+ + mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
+ }
+
/**
* Buckets the battery level.
*
@@ -87,7 +118,7 @@ public class PowerUI extends SystemUI {
if (level >= mLowBatteryAlertCloseLevel) {
return 1;
}
- if (level >= mLowBatteryReminderLevels[0]) {
+ if (level > mLowBatteryReminderLevels[0]) {
return 0;
}
final int N = mLowBatteryReminderLevels.length;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index c76ee8c..786cd9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -287,6 +287,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
public boolean activityIn;
public boolean activityOut;
public int overlayIconId;
+ public boolean filter;
@Override
public boolean copyTo(State other) {
@@ -300,6 +301,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
o.activityIn = activityIn;
o.activityOut = activityOut;
o.overlayIconId = overlayIconId;
+ o.filter = filter;
return super.copyTo(other) || changed;
}
@@ -311,6 +313,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
+ rt.insert(rt.length() - 1, ",filter=" + filter);
return rt;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index 901cc10..d5fe033 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -93,12 +93,12 @@ public final class SignalTileView extends QSTileView {
final SignalState s = (SignalState) state;
mSignal.setImageDrawable(null); // force refresh
mSignal.setImageResource(s.iconId);
- mSignal.setColorFilter(FILTER);
+ mSignal.setColorFilter(s.filter ? FILTER : null);
if (s.overlayIconId > 0) {
mOverlay.setVisibility(VISIBLE);
mOverlay.setImageDrawable(null); // force refresh
mOverlay.setImageResource(s.overlayIconId);
- mOverlay.setColorFilter(FILTER);
+ mOverlay.setColorFilter(s.filter ? FILTER : null);
} else {
mOverlay.setVisibility(GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 182a0ce..6d91d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -72,12 +72,15 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
if (cb == null) return;
final Resources r = mContext.getResources();
- state.iconId = cb.enabled && (cb.mobileSignalIconId > 0)
+ state.iconId = cb.noSim
+ ? R.drawable.stat_sys_no_sim
+ : cb.enabled && (cb.mobileSignalIconId > 0)
? cb.mobileSignalIconId
: R.drawable.ic_qs_signal_no_signal;
state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
? cb.dataTypeIconId
: 0;
+ state.filter = state.iconId != R.drawable.stat_sys_no_sim;
state.activityIn = cb.enabled && cb.activityIn;
state.activityOut = cb.enabled && cb.activityOut;
@@ -117,6 +120,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
boolean activityIn;
boolean activityOut;
String enabledDesc;
+ boolean noSim;
}
private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
@@ -134,7 +138,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description) {
+ String dataTypeContentDescriptionId, String description, boolean noSim) {
final CallbackInfo info = new CallbackInfo(); // TODO pool?
info.enabled = enabled;
info.wifiEnabled = mWifiEnabled;
@@ -145,6 +149,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
info.activityIn = activityIn;
info.activityOut = activityOut;
info.enabledDesc = description;
+ info.noSim = noSim;
refreshState(info);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5301362..7c2c7c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,6 +71,6 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
state.visible = mVisible;
state.value = enabled;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
- state.iconId = R.drawable.ic_qs_color_inversion;
+ state.iconId = enabled ? R.drawable.ic_qs_inversion_on : R.drawable.ic_qs_inversion_off;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index db9b054..04f1eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,9 +16,6 @@
package com.android.systemui.qs.tiles;
-import android.content.res.Resources;
-import android.graphics.drawable.AnimationDrawable;
-
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.LocationController;
@@ -63,28 +60,15 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean locationEnabled = mController.isLocationEnabled();
state.visible = true;
- if (state.value != locationEnabled) {
- state.value = locationEnabled;
- final Resources res = mContext.getResources();
- final AnimationDrawable d = (AnimationDrawable) res.getDrawable(locationEnabled
- ? R.drawable.ic_qs_location_on
- : R.drawable.ic_qs_location_off);
- state.icon = d;
- mUiHandler.post(new Runnable() {
- @Override
- public void run() {
- d.start();
- }
- });
- }
+ state.value = locationEnabled;
if (locationEnabled) {
- if (state.icon == null) state.iconId = R.drawable.ic_qs_location_01;
+ state.iconId = R.drawable.ic_qs_location_on;
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
mContext.getString(R.string.accessibility_desc_on));
} else {
- if (state.icon == null) state.iconId = R.drawable.ic_qs_location_11;
+ state.iconId = R.drawable.ic_qs_location_off;
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 6b73002..a236497 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -87,6 +87,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
state.connected = wifiConnected;
state.activityIn = cb.enabled && cb.activityIn;
state.activityOut = cb.enabled && cb.activityOut;
+ state.filter = true;
final String signalContentDescription;
final Resources r = mContext.getResources();
if (wifiConnected) {
@@ -159,7 +160,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description) {
+ String dataTypeContentDescriptionId, String description, boolean noSim) {
// noop
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index b91e129..8d19f50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -158,7 +158,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private final Runnable mTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
- makeInactive();
+ makeInactive(true /* animate */);
}
};
@@ -183,7 +183,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
break;
case MotionEvent.ACTION_MOVE:
if (!isWithinTouchSlop(event)) {
- makeInactive();
+ makeInactive(true /* animate */);
return false;
}
break;
@@ -193,14 +193,17 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- performClick();
+ boolean performed = performClick();
+ if (performed) {
+ removeCallbacks(mTapTimeoutRunnable);
+ }
}
} else {
- makeInactive();
+ makeInactive(true /* animate */);
}
break;
case MotionEvent.ACTION_CANCEL:
- makeInactive();
+ makeInactive(true /* animate */);
break;
default:
break;
@@ -257,10 +260,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
/**
* Cancels the hotspot and makes the notification inactive.
*/
- private void makeInactive() {
+ public void makeInactive(boolean animate) {
if (mActivated) {
if (mDimmed) {
- startActivateAnimation(true /* reverse */);
+ if (animate) {
+ startActivateAnimation(true /* reverse */);
+ } else {
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
+ }
}
mActivated = false;
}
@@ -351,6 +358,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
mBackgroundNormal.setAlpha(1f);
+ removeCallbacks(mTapTimeoutRunnable);
}
}
@@ -581,7 +589,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
public interface OnActivatedListener {
- void onActivated(View view);
- void onActivationReset(View view);
+ void onActivated(ActivatableNotificationView view);
+ void onActivationReset(ActivatableNotificationView view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 508c34e..5a9fe91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -48,7 +48,7 @@ import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -80,11 +80,10 @@ import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
+import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.Locale;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -106,6 +105,7 @@ public abstract class BaseStatusBar extends SystemUI implements
protected static final int MSG_SHOW_HEADS_UP = 1026;
protected static final int MSG_HIDE_HEADS_UP = 1027;
protected static final int MSG_ESCALATE_HEADS_UP = 1028;
+ protected static final int MSG_DECAY_HEADS_UP = 1029;
protected static final boolean ENABLE_HEADS_UP = true;
// scores above this threshold should be displayed in heads up mode.
@@ -129,7 +129,9 @@ public abstract class BaseStatusBar extends SystemUI implements
protected NotificationData mNotificationData = new NotificationData();
protected NotificationStackScrollLayout mStackScroller;
- protected NotificationData.Entry mInterruptingNotificationEntry;
+ // for heads up notifications
+ protected HeadsUpNotificationView mHeadsUpNotificationView;
+ protected int mHeadsUpNotificationDecay;
protected long mInterruptingNotificationTime;
// used to notify status bar for suppressing notification LED
@@ -291,7 +293,7 @@ public abstract class BaseStatusBar extends SystemUI implements
public void onListenerConnected() {
if (DEBUG) Log.d(TAG, "onListenerConnected");
final StatusBarNotification[] notifications = getActiveNotifications();
- final Ranking currentRanking = getCurrentRanking();
+ final RankingMap currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -303,41 +305,40 @@ public abstract class BaseStatusBar extends SystemUI implements
}
@Override
- public void onNotificationPosted(final StatusBarNotification sbn) {
+ public void onNotificationPosted(final StatusBarNotification sbn,
+ final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
- final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
if (mNotificationData.findByKey(sbn.getKey()) != null) {
- updateNotificationInternal(sbn, currentRanking);
+ updateNotificationInternal(sbn, rankingMap);
} else {
- addNotificationInternal(sbn, currentRanking);
+ addNotificationInternal(sbn, rankingMap);
}
}
});
}
@Override
- public void onNotificationRemoved(final StatusBarNotification sbn) {
+ public void onNotificationRemoved(final StatusBarNotification sbn,
+ final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
- final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
- removeNotificationInternal(sbn.getKey(), currentRanking);
+ removeNotificationInternal(sbn.getKey(), rankingMap);
}
});
}
@Override
- public void onNotificationRankingUpdate() {
+ public void onNotificationRankingUpdate(final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onRankingUpdate");
- final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
- updateRankingInternal(currentRanking);
+ updateRankingInternal(rankingMap);
}
});
}
@@ -505,8 +506,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
- if (n.isClearable() || (mInterruptingNotificationEntry != null
- && mInterruptingNotificationEntry.row == row)) {
+ if (n.isClearable() || (mHeadsUpNotificationView.getEntry() != null
+ && mHeadsUpNotificationView.getEntry().row == row)) {
final String _pkg = n.getPackageName();
final String _tag = n.getTag();
final int _id = n.getId();
@@ -765,6 +766,12 @@ public abstract class BaseStatusBar extends SystemUI implements
public abstract void resetHeadsUpDecayTimer();
+ public abstract void scheduleHeadsUpOpen();
+
+ public abstract void scheduleHeadsUpClose();
+
+ public abstract void scheduleHeadsUpEscalation();
+
/**
* Save the current "public" (locked and secure) state of the lockscreen.
*/
@@ -796,6 +803,18 @@ public abstract class BaseStatusBar extends SystemUI implements
return mUsersAllowingPrivateNotifications.get(userHandle);
}
+ public void onNotificationClear(StatusBarNotification notification) {
+ try {
+ mBarService.onNotificationClear(
+ notification.getPackageName(),
+ notification.getTag(),
+ notification.getId(),
+ notification.getUserId());
+ } catch (android.os.RemoteException ex) {
+ // oh well
+ }
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
Intent intent;
@@ -1101,7 +1120,7 @@ public abstract class BaseStatusBar extends SystemUI implements
try {
if (mIsHeadsUp) {
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ mHeadsUpNotificationView.clear();
}
mBarService.onNotificationClick(mNotificationKey);
} catch (RemoteException ex) {
@@ -1157,7 +1176,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- protected StatusBarNotification removeNotificationViews(String key, Ranking ranking) {
+ protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
NotificationData.Entry entry = mNotificationData.remove(key, ranking);
if (entry == null) {
Log.w(TAG, "removeNotification for unknown key: " + key);
@@ -1197,7 +1216,7 @@ public abstract class BaseStatusBar extends SystemUI implements
return entry;
}
- protected void addNotificationViews(Entry entry, Ranking ranking) {
+ protected void addNotificationViews(Entry entry, RankingMap ranking) {
if (entry == null) {
return;
}
@@ -1206,7 +1225,7 @@ public abstract class BaseStatusBar extends SystemUI implements
updateNotifications();
}
- private void addNotificationViews(StatusBarNotification notification, Ranking ranking) {
+ private void addNotificationViews(StatusBarNotification notification, RankingMap ranking) {
addNotificationViews(createNotificationViews(notification), ranking);
}
@@ -1292,9 +1311,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
public abstract void addNotificationInternal(StatusBarNotification notification,
- Ranking ranking);
+ RankingMap ranking);
- protected abstract void updateRankingInternal(Ranking ranking);
+ protected abstract void updateRankingInternal(RankingMap ranking);
@Override
public void removeNotification(String key) {
@@ -1303,7 +1322,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- public abstract void removeNotificationInternal(String key, Ranking ranking);
+ public abstract void removeNotificationInternal(String key, RankingMap ranking);
public void updateNotification(StatusBarNotification notification) {
if (!USE_NOTIFICATION_LISTENER) {
@@ -1311,7 +1330,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
@@ -1394,15 +1413,15 @@ public abstract class BaseStatusBar extends SystemUI implements
try {
updateNotificationViews(oldEntry, notification);
- if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
- && oldNotification == mInterruptingNotificationEntry.notification) {
+ if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
+ && oldNotification == mHeadsUpNotificationView.getEntry().notification) {
if (!shouldInterrupt(notification)) {
if (DEBUG) Log.d(TAG, "no longer interrupts!");
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ scheduleHeadsUpClose();
} else {
if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
- mInterruptingNotificationEntry.notification = notification;
- updateHeadsUpViews(mInterruptingNotificationEntry, notification);
+ mHeadsUpNotificationView.getEntry().notification = notification;
+ updateHeadsUpViews(mHeadsUpNotificationView.getEntry(), notification);
}
}
@@ -1511,8 +1530,8 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected void notifyHeadsUpScreenOn(boolean screenOn) {
- if (!screenOn && mInterruptingNotificationEntry != null) {
- mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+ if (!screenOn) {
+ scheduleHeadsUpEscalation();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 4233ab8..bfa74fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.os.Process;
import android.provider.Settings;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -58,17 +59,18 @@ public class InterceptedNotifications {
updateSyntheticNotification();
}
- public boolean tryIntercept(StatusBarNotification notification, Ranking ranking) {
- if (ranking == null) return false;
+ public boolean tryIntercept(StatusBarNotification notification, RankingMap rankingMap) {
+ if (rankingMap == null) return false;
if (shouldDisplayIntercepted()) return false;
if (mReleased.contains(notification.getKey())) return false;
- if (!ranking.isInterceptedByDoNotDisturb(notification.getKey())) return false;
+ Ranking ranking = rankingMap.getRanking(notification.getKey());
+ if (!ranking.isInterceptedByDoNotDisturb()) return false;
mIntercepted.put(notification.getKey(), notification);
updateSyntheticNotification();
return true;
}
- public void retryIntercepts(Ranking ranking) {
+ public void retryIntercepts(RankingMap ranking) {
if (ranking == null) return;
final int N = mIntercepted.size();
@@ -111,7 +113,7 @@ public class InterceptedNotifications {
return;
}
final Notification n = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_qs_zen_on)
+ .setSmallIcon(R.drawable.ic_notify_zen)
.setContentTitle(mContext.getResources().getQuantityString(
R.plurals.zen_mode_notification_title,
mIntercepted.size(), mIntercepted.size()))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 631e19c..c313c58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar;
import android.app.Notification;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
@@ -70,12 +71,16 @@ public class NotificationData {
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
- private Ranking mRanking;
+ private RankingMap mRanking;
private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
@Override
public int compare(Entry a, Entry b) {
if (mRanking != null) {
- return mRanking.getRank(a.key) - mRanking.getRank(b.key);
+ Ranking aRanking = mRanking.getRanking(a.key);
+ Ranking bRanking = mRanking.getRanking(b.key);
+ int aRank = aRanking != null ? aRanking.getRank() : -1;
+ int bRank = bRanking != null ? bRanking.getRank() : -1;
+ return aRank - bRank;
}
final StatusBarNotification na = a.notification;
@@ -108,12 +113,12 @@ public class NotificationData {
return null;
}
- public void add(Entry entry, Ranking ranking) {
+ public void add(Entry entry, RankingMap ranking) {
mEntries.add(entry);
updateRankingAndSort(ranking);
}
- public Entry remove(String key, Ranking ranking) {
+ public Entry remove(String key, RankingMap ranking) {
Entry e = findByKey(key);
if (e == null) {
return null;
@@ -123,7 +128,7 @@ public class NotificationData {
return e;
}
- public void updateRanking(Ranking ranking) {
+ public void updateRanking(RankingMap ranking) {
updateRankingAndSort(ranking);
}
@@ -137,12 +142,13 @@ public class NotificationData {
}
}
} else {
- return mRanking.isAmbient(key);
+ Ranking ranking = mRanking.getRanking(key);
+ return ranking != null && ranking.isAmbient();
}
return false;
}
- private void updateRankingAndSort(Ranking ranking) {
+ private void updateRankingAndSort(RankingMap ranking) {
if (ranking != null) {
mRanking = ranking;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
deleted file mode 100644
index 1503072..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotView extends View {
-
- private final Paint mPaint = new Paint();
-
- public SpeedBumpDotView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mPaint.setAntiAlias(true);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- float radius = getWidth() / 2.0f;
- canvas.drawCircle(radius, radius, radius, mPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- public void setColor(int color) {
- mPaint.setColor(color);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
deleted file mode 100644
index cac6327..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import com.android.systemui.R;
-
-/**
- * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
- * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
- */
-public class SpeedBumpDotsAlgorithm {
-
- private final float mDotRadius;
-
- public SpeedBumpDotsAlgorithm(Context context) {
- mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
- / 2.0f;
- }
-
- public void getState(SpeedBumpDotsState resultState) {
-
- // First reset the current state and ensure that every View has a ViewState
- resultState.resetViewStates();
-
- SpeedBumpDotsLayout hostView = resultState.getHostView();
- boolean currentlyVisible = hostView.isCurrentlyVisible();
- resultState.setActiveState(currentlyVisible
- ? SpeedBumpDotsState.SHOWN
- : SpeedBumpDotsState.HIDDEN);
- int hostWidth = hostView.getWidth();
- float layoutWidth = hostWidth - 2 * mDotRadius;
- int childCount = hostView.getChildCount();
- float paddingBetween = layoutWidth / (childCount - 1);
- float centerY = hostView.getHeight() / 2.0f;
- for (int i = 0; i < childCount; i++) {
- View child = hostView.getChildAt(i);
- SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
- if (currentlyVisible) {
- float xTranslation = i * paddingBetween;
- viewState.xTranslation = xTranslation;
- viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
- layoutWidth);
- } else {
- viewState.xTranslation = layoutWidth / 2;
- viewState.yTranslation = centerY - mDotRadius;
- }
- viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
- viewState.scale = currentlyVisible ? 1.0f : 0.5f;
- }
- }
-
- private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
- float xTranslation, float layoutWidth) {
- float t = hostView.getAnimationProgress();
- if (t == 0.0f || t == 1.0f) {
- return centerY - mDotRadius;
- }
- float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
- float partialOffset = xTranslation / layoutWidth;
- float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
- return (1.0f - indentFactor) * centerY - mDotRadius;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
deleted file mode 100644
index ddf5215..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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 com.android.systemui.statusbar;
-
-import android.animation.TimeAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import com.android.systemui.R;
-
-/**
- * A layout with a certain number of dots which are integrated in the
- * {@link com.android.systemui.statusbar.SpeedBumpView}
- */
-public class SpeedBumpDotsLayout extends ViewGroup {
-
- private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
- private final int mDotSize;
- private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
- private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
- private boolean mIsCurrentlyVisible = true;
- private final ValueAnimator mClickAnimator;
- private float mAnimationProgress;
- private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mAnimationProgress = animation.getAnimatedFraction();
- updateChildren();
- }
- };
-
- public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
- createDots(context, attrs);
- mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
- mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
- mClickAnimator.addUpdateListener(mClickUpdateListener);
- }
-
- private void createDots(Context context, AttributeSet attrs) {
- SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
- blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
- addView(blueDot);
-
- SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
- redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
- addView(redDot);
-
- SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
- yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
- addView(yellowDot);
-
- SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
- greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
- addView(greenDot);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
- MeasureSpec.getMode(widthMeasureSpec));
- int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
- MeasureSpec.getMode(heightMeasureSpec));
- measureChildren(childWidthSpec, childHeightSpec);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- child.layout(0, 0, mDotSize, mDotSize);
- }
- if (changed) {
- updateChildren();
- }
- }
-
- private void updateChildren() {
- mAlgorithm.getState(mCurrentState);
- mCurrentState.apply();
- }
-
- public void performVisibilityAnimation(boolean visible) {
- if (mClickAnimator.isRunning()) {
- mClickAnimator.cancel();
- }
- mIsCurrentlyVisible = visible;
- mAlgorithm.getState(mCurrentState);
- mCurrentState.animateToState();
- }
-
- public void setInvisible() {
- mIsCurrentlyVisible = false;
- mAlgorithm.getState(mCurrentState);
- mCurrentState.apply();
- }
-
- public boolean isCurrentlyVisible() {
- return mIsCurrentlyVisible;
- }
-
- public void performDotClickAnimation() {
- if (mClickAnimator.isRunning()) {
- // don't perform an animation if it's running already
- return;
- }
- mClickAnimator.start();
- }
-
-
- public float getAnimationProgress() {
- return mAnimationProgress;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
deleted file mode 100644
index 4febab1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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 com.android.systemui.statusbar;
-
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotsState {
-
- public static final int HIDDEN = 1;
- public static final int SHOWN = 2;
- private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
-
- private final SpeedBumpDotsLayout mHostView;
- private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
- private final Interpolator mFastOutSlowInInterpolator;
- private int mActiveState = 0;
-
- public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
- mHostView = hostLayout;
- mFastOutSlowInInterpolator = AnimationUtils
- .loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
- }
-
- public SpeedBumpDotsLayout getHostView() {
- return mHostView;
- }
-
- public void resetViewStates() {
- int numChildren = mHostView.getChildCount();
- for (int i = 0; i < numChildren; i++) {
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- if (viewState == null) {
- viewState = new ViewState();
- mStateMap.put(child, viewState);
- }
- }
- }
-
- public ViewState getViewStateForView(View requestedView) {
- return mStateMap.get(requestedView);
- }
-
- public void apply() {
- int childCount = mHostView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
-
- child.setTranslationX(viewState.xTranslation);
- child.setTranslationY(viewState.yTranslation);
- child.setScaleX(viewState.scale);
- child.setScaleY(viewState.scale);
- child.setAlpha(viewState.alpha);
- }
- }
-
- public void animateToState() {
- int childCount = mHostView.getChildCount();
- int middleIndex = (childCount - 1) / 2;
- long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
- boolean isAppearing = getActiveState() == SHOWN;
- boolean isDisappearing = getActiveState() == HIDDEN;
- for (int i = 0; i < childCount; i++) {
- int delayIndex;
- if (i <= middleIndex) {
- delayIndex = i * 2;
- } else {
- int distToMiddle = i - middleIndex;
- delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
- }
- long startDelay = 0;
- if (isAppearing || isDisappearing) {
- if (isDisappearing) {
- delayIndex = childCount - 1 - delayIndex;
- }
- startDelay = delayIndex * delayPerElement;
- }
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- child.animate().setInterpolator(mFastOutSlowInInterpolator)
- .setStartDelay(startDelay)
- .alpha(viewState.alpha)
- .translationX(viewState.xTranslation)
- .translationY(viewState.yTranslation)
- .scaleX(viewState.scale).scaleY(viewState.scale);
- }
- }
-
- public int getActiveState() {
- return mActiveState;
- }
-
- public void setActiveState(int mActiveState) {
- this.mActiveState = mActiveState;
- }
-
- public static class ViewState {
- float xTranslation;
- float yTranslation;
- float alpha;
- float scale;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index 689d0e9..f80f0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -16,71 +16,26 @@
package com.android.systemui.statusbar;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Outline;
import android.util.AttributeSet;
-import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.widget.TextView;
import com.android.systemui.R;
/**
* The view representing the separation between important and less important notifications
*/
-public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+public class SpeedBumpView extends ExpandableView {
- private final int mCollapsedHeight;
- private final int mDotsHeight;
- private final int mTextPaddingInset;
- private SpeedBumpDotsLayout mDots;
- private AlphaOptimizedView mLineLeft;
- private AlphaOptimizedView mLineRight;
- private boolean mIsExpanded;
- private boolean mDividerVisible = true;
- private ValueAnimator mCurrentAnimator;
+ private final int mSpeedBumpHeight;
+ private AlphaOptimizedView mLine;
+ private boolean mIsVisible = true;
private final Interpolator mFastOutSlowInInterpolator;
- private float mCenterX;
- private TextView mExplanationText;
- private boolean mExplanationTextVisible = false;
- private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCancelled) {
- mExplanationText.setVisibility(View.INVISIBLE);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mCancelled = false;
- }
- };
- private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCurrentAnimator = null;
- }
- };
public SpeedBumpView(Context context, AttributeSet attrs) {
super(context, attrs);
- mCollapsedHeight = getResources()
- .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
- mTextPaddingInset = getResources().getDimensionPixelSize(
- R.dimen.speed_bump_text_padding_inset);
- mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
- setOnClickListener(this);
+ mSpeedBumpHeight = getResources()
+ .getDimensionPixelSize(R.dimen.speed_bump_height);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
}
@@ -88,111 +43,41 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
- mLineLeft = (AlphaOptimizedView) findViewById(R.id.speedbump_line_left);
- mLineRight = (AlphaOptimizedView) findViewById(R.id.speedbump_line_right);
- mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
- resetExplanationText();
-
+ mLine = (AlphaOptimizedView) findViewById(R.id.speedbump_line);
}
@Override
protected int getInitialHeight() {
- return mCollapsedHeight;
+ return mSpeedBumpHeight;
}
@Override
public int getIntrinsicHeight() {
- if (mCurrentAnimator != null) {
- // expand animation is running
- return getActualHeight();
- }
- return mIsExpanded ? getHeight() : mCollapsedHeight;
+ return mSpeedBumpHeight;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- Outline outline = new Outline();
- mCenterX = getWidth() / 2;
- float centerY = getHeight() / 2;
- // TODO: hide outline better
- // Temporary workaround to hide outline on a transparent view
- int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
- int outlineTop = (int) (centerY - mDotsHeight / 2);
- outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
- outlineTop + mDotsHeight);
- setOutline(outline);
- mLineLeft.setPivotX(mLineLeft.getWidth());
- mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
- mLineRight.setPivotX(0);
- mLineRight.setPivotY(mLineRight.getHeight() / 2);
+ mLine.setPivotX(mLine.getWidth() / 2);
+ mLine.setPivotY(mLine.getHeight() / 2);
+ setOutline(null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
- int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+ int height = mSpeedBumpHeight;
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
}
@Override
- public void onClick(View v) {
- if (mCurrentAnimator != null) {
- return;
- }
- int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
- int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
- mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
- mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
- mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- setActualHeight((int) animation.getAnimatedValue());
- }
- });
- mCurrentAnimator.addListener(mAnimationFinishedListener);
- mCurrentAnimator.start();
- mIsExpanded = !mIsExpanded;
- mDots.performDotClickAnimation();
- animateExplanationTextInternal(mIsExpanded);
- }
-
- private void animateExplanationTextInternal(boolean visible) {
- if (mExplanationTextVisible != visible) {
- float translationY = 0.0f;
- float scale = 0.5f;
- float alpha = 0.0f;
- boolean needsHideListener = true;
- if (visible) {
- mExplanationText.setVisibility(VISIBLE);
- translationY = mDots.getBottom() - mTextPaddingInset;
- scale = 1.0f;
- alpha = 1.0f;
- needsHideListener = false;
- }
- mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
- .alpha(alpha)
- .scaleX(scale)
- .scaleY(scale)
- .translationY(translationY)
- .setListener(needsHideListener ? mHideExplanationListener : null);
- mExplanationTextVisible = visible;
- }
- }
-
- @Override
public boolean isTransparent() {
return true;
}
public void performVisibilityAnimation(boolean nowVisible) {
animateDivider(nowVisible, null /* onFinishedRunnable */);
-
- // Animate explanation Text
- if (mIsExpanded) {
- animateExplanationTextInternal(nowVisible);
- }
}
/**
@@ -203,28 +88,16 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
* finished.
*/
public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) {
- if (nowVisible != mDividerVisible) {
+ if (nowVisible != mIsVisible) {
// Animate dividers
float endValue = nowVisible ? 1.0f : 0.0f;
- float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
- float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
- mLineLeft.animate()
+ mLine.animate()
.alpha(endValue)
.scaleX(endValue)
.scaleY(endValue)
- .translationX(endTranslationXLeft)
.setInterpolator(mFastOutSlowInInterpolator)
.withEndAction(onFinishedRunnable);
- mLineRight.animate()
- .alpha(endValue)
- .scaleX(endValue)
- .scaleY(endValue)
- .translationX(endTranslationXRight)
- .setInterpolator(mFastOutSlowInInterpolator);
-
- // Animate dots
- mDots.performVisibilityAnimation(nowVisible);
- mDividerVisible = nowVisible;
+ mIsVisible = nowVisible;
} else {
if (onFinishedRunnable != null) {
onFinishedRunnable.run();
@@ -233,34 +106,10 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
}
public void setInvisible() {
- float endTranslationXLeft = mCenterX - mLineLeft.getRight();
- float endTranslationXRight = mCenterX - mLineRight.getLeft();
- mLineLeft.setAlpha(0.0f);
- mLineLeft.setScaleX(0.0f);
- mLineLeft.setScaleY(0.0f);
- mLineLeft.setTranslationX(endTranslationXLeft);
- mLineRight.setAlpha(0.0f);
- mLineRight.setScaleX(0.0f);
- mLineRight.setScaleY(0.0f);
- mLineRight.setTranslationX(endTranslationXRight);
- mDots.setInvisible();
- resetExplanationText();
-
- mDividerVisible = false;
- }
-
- public void collapse() {
- if (mIsExpanded) {
- setActualHeight(mCollapsedHeight);
- mIsExpanded = false;
- }
- resetExplanationText();
- }
-
- public void animateExplanationText(boolean nowVisible) {
- if (mIsExpanded) {
- animateExplanationTextInternal(nowVisible);
- }
+ mLine.setAlpha(0.0f);
+ mLine.setScaleX(0.0f);
+ mLine.setScaleY(0.0f);
+ mIsVisible = false;
}
@Override
@@ -272,17 +121,4 @@ public class SpeedBumpView extends ExpandableView implements View.OnClickListene
public void performAddAnimation(long delay) {
performVisibilityAnimation(true);
}
-
- private void resetExplanationText() {
- mExplanationText.setTranslationY(0);
- mExplanationText.setVisibility(INVISIBLE);
- mExplanationText.setAlpha(0.0f);
- mExplanationText.setScaleX(0.5f);
- mExplanationText.setScaleY(0.5f);
- mExplanationTextVisible = false;
- }
-
- public boolean isExpanded() {
- return mIsExpanded;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
index 086a266..e312d58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
@@ -423,6 +423,7 @@ public class KeyguardPageSwipeHelper {
return;
}
if (!animate) {
+ view.animate().cancel();
view.setAlpha(alpha);
view.setScaleX(scale);
view.setScaleY(scale);
@@ -465,6 +466,13 @@ public class KeyguardPageSwipeHelper {
}
public void reset() {
+ if (mSwipeAnimator != null) {
+ mSwipeAnimator.cancel();
+ }
+ ArrayList<View> targetViews = mCallback.getTranslationViews();
+ for (View view : targetViews) {
+ view.animate().cancel();
+ }
setTranslation(0.0f, true);
mSwipingInProgress = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 772d0e7..1f3098d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -27,6 +27,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -67,6 +68,11 @@ public abstract class PanelView extends FrameLayout {
private VelocityTrackerInterface mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ /**
+ * Whether an instant expand request is currently pending and we are just waiting for layout.
+ */
+ private boolean mInstantExpanding;
+
PanelBar mBar;
protected int mMaxPanelHeight = -1;
@@ -128,6 +134,9 @@ public abstract class PanelView extends FrameLayout {
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (mInstantExpanding) {
+ return false;
+ }
/*
* We capture touch events here and update the expand height here in case according to
@@ -263,6 +272,9 @@ public abstract class PanelView extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mInstantExpanding) {
+ return false;
+ }
/*
* If the user drags anywhere inside the panel we intercept it if he moves his finger
@@ -556,6 +568,41 @@ public abstract class PanelView extends FrameLayout {
}
}
+ public void instantExpand() {
+ mInstantExpanding = true;
+ abortAnimations();
+ if (mTracking) {
+ onTrackingStopped(true /* expands */); // The panel is expanded after this call.
+ onExpandingFinished();
+ }
+ setVisibility(VISIBLE);
+
+ // Wait for window manager to pickup the change, so we know the maximum height of the panel
+ // then.
+ getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (mStatusBar.getStatusBarWindow().getHeight()
+ != mStatusBar.getStatusBarHeight()) {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ setExpandedFraction(1f);
+ mInstantExpanding = false;
+ }
+ }
+ });
+
+ // Make sure a layout really happens.
+ requestLayout();
+ }
+
+ private void abortAnimations() {
+ cancelPeek();
+ if (mHeightAnimator != null) {
+ mHeightAnimator.cancel();
+ }
+ }
+
protected void startUnlockHintAnimation() {
// We don't need to hint the user if an animation is already running or the user is changing
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 a8f61f3..4ed1888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -64,7 +64,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.DisplayMetrics;
@@ -103,6 +103,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.CircularClipper;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
@@ -277,10 +278,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// the date view
DateView mDateView;
- // for heads up notifications
- private HeadsUpNotificationView mHeadsUpNotificationView;
- private int mHeadsUpNotificationDecay;
-
// on-screen navigation buttons
private NavigationBarView mNavigationBarView = null;
private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -366,7 +363,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (!mUseHeadsUp) {
Log.d(TAG, "dismissing any existing heads up notification on disable event");
setHeadsUpVisibility(false);
- mHeadsUpNotificationView.setNotification(null);
+ mHeadsUpNotificationView.release();
removeHeadsUpView();
} else {
addHeadsUpView();
@@ -818,6 +815,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mStatusBarView;
}
+ public StatusBarWindowView getStatusBarWindow() {
+ return mStatusBarWindow;
+ }
+
@Override
protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
boolean opaque = false;
@@ -1050,7 +1051,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification, ranking)) {
// Forward the ranking so we can sort the new notification.
@@ -1061,31 +1062,28 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
displayNotification(notification, ranking);
}
- public void displayNotification(StatusBarNotification notification,
- Ranking ranking) {
- Entry shadeEntry = createNotificationViews(notification);
- if (shadeEntry == null) {
- return;
- }
+ public void displayNotification(StatusBarNotification notification, RankingMap ranking) {
if (mUseHeadsUp && shouldInterrupt(notification)) {
if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
Entry interruptionCandidate = new Entry(notification, null);
ViewGroup holder = mHeadsUpNotificationView.getHolder();
if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
mInterruptingNotificationTime = System.currentTimeMillis();
- mInterruptingNotificationEntry = interruptionCandidate;
- shadeEntry.setInterruption();
// 1. Populate mHeadsUpNotificationView
- mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
+ mHeadsUpNotificationView.showNotification(interruptionCandidate);
- // 2. Animate mHeadsUpNotificationView in
- mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
-
- // 3. Set alarm to age the notification off
- resetHeadsUpDecayTimer();
+ // do not show the notification in the shade, yet.
+ return;
}
- } else if (notification.getNotification().fullScreenIntent != null) {
+ }
+
+ Entry shadeEntry = createNotificationViews(notification);
+ if (shadeEntry == null) {
+ return;
+ }
+
+ if (notification.getNotification().fullScreenIntent != null) {
// Stop screensaver if the notification has a full-screen intent.
// (like an incoming phone call)
awakenDreams();
@@ -1100,7 +1098,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// usual case: status bar visible & not immersive
// show the ticker if there isn't already a heads up
- if (mInterruptingNotificationEntry == null) {
+ if (mHeadsUpNotificationView.getEntry() == null) {
tick(notification, true);
}
}
@@ -1110,31 +1108,64 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
}
+ public void displayNotificationFromHeadsUp(StatusBarNotification notification) {
+ NotificationData.Entry shadeEntry = createNotificationViews(notification);
+ if (shadeEntry == null) {
+ return;
+ }
+ shadeEntry.setInterruption();
+
+ addNotificationViews(shadeEntry, null);
+ // Recalculate the position of the sliding windows and the titles.
+ setAreThereNotifications();
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ }
+
@Override
public void resetHeadsUpDecayTimer() {
- mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+ mHandler.removeMessages(MSG_DECAY_HEADS_UP);
if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
&& mHeadsUpNotificationView.isClearable()) {
- mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
+ mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay);
}
}
@Override
- public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void scheduleHeadsUpOpen() {
+ mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+ }
+
+ @Override
+ public void scheduleHeadsUpClose() {
+ mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ }
+
+ @Override
+ public void scheduleHeadsUpEscalation() {
+ mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+ }
+
+ @Override
+ public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
super.updateNotificationInternal(notification, ranking);
// if we're here, then the notification is already in the shade
mIntercepted.remove(notification.getKey());
}
@Override
- protected void updateRankingInternal(Ranking ranking) {
+ protected void updateRankingInternal(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
mIntercepted.retryIntercepts(ranking);
updateNotifications();
}
@Override
- public void removeNotificationInternal(String key, Ranking ranking) {
+ public void removeNotificationInternal(String key, RankingMap ranking) {
+ if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
+ && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) {
+ mHeadsUpNotificationView.clear();
+ }
+
StatusBarNotification old = removeNotificationViews(key, ranking);
if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
@@ -1147,11 +1178,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Recalculate the position of the sliding windows and the titles.
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
- && old == mInterruptingNotificationEntry.notification) {
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
- }
-
if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
&& !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
animateCollapsePanels();
@@ -1574,7 +1600,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
case MSG_SHOW_HEADS_UP:
setHeadsUpVisibility(true);
break;
+ case MSG_DECAY_HEADS_UP:
+ mHeadsUpNotificationView.release();
+ setHeadsUpVisibility(false);
+ break;
case MSG_HIDE_HEADS_UP:
+ mHeadsUpNotificationView.release();
setHeadsUpVisibility(false);
break;
case MSG_ESCALATE_HEADS_UP:
@@ -1587,8 +1618,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
/** if the interrupting notification had a fullscreen intent, fire it now. */
private void escalateHeadsUp() {
- if (mInterruptingNotificationEntry != null) {
- final StatusBarNotification sbn = mInterruptingNotificationEntry.notification;
+ if (mHeadsUpNotificationView.getEntry() != null) {
+ final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification;
+ mHeadsUpNotificationView.release();
final Notification notification = sbn.getNotification();
if (notification.fullScreenIntent != null) {
if (DEBUG)
@@ -2243,7 +2275,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
pw.print(" mUseHeadsUp=");
pw.println(mUseHeadsUp);
pw.print(" interrupting package: ");
- pw.println(hunStateToString(mInterruptingNotificationEntry));
+ pw.println(hunStateToString(mHeadsUpNotificationView.getEntry()));
dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
if (mNavigationBarView != null) {
pw.print(" mNavigationBarWindowState=");
@@ -2517,26 +2549,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (!ENABLE_HEADS_UP) return;
if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
- if (!vis) {
- if (DEBUG) Log.d(TAG, "setting heads up entry to null");
- mInterruptingNotificationEntry = null;
- }
}
public void onHeadsUpDismissed() {
- if (mInterruptingNotificationEntry == null) return;
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
- if (mHeadsUpNotificationView.isClearable()) {
- try {
- mBarService.onNotificationClear(
- mInterruptingNotificationEntry.notification.getPackageName(),
- mInterruptingNotificationEntry.notification.getTag(),
- mInterruptingNotificationEntry.notification.getId(),
- mInterruptingNotificationEntry.notification.getUserId());
- } catch (android.os.RemoteException ex) {
- // oh well
- }
- }
+ mHeadsUpNotificationView.dismiss();
}
/**
@@ -2905,7 +2921,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNotificationPanel.setKeyguardShowing(false);
mScrimController.setKeyguardShowing(false);
}
-
updateStackScrollerState();
updatePublicMode();
updateNotifications();
@@ -2921,6 +2936,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
? View.INVISIBLE : View.VISIBLE);
mStackScroller.setScrollingEnabled(!onKeyguard);
mStackScroller.setExpandingEnabled(!onKeyguard);
+ ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
+ mStackScroller.setActivatedChild(null);
+ if (activatedChild != null) {
+ activatedChild.makeInactive(false /* animate */);
+ }
}
public void userActivity() {
@@ -2954,22 +2974,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void instantExpandNotificationsPanel() {
- // Make our window larger and the panel visible.
+ // Make our window larger and the panel expanded.
makeExpandedVisible(true);
- mNotificationPanel.setVisibility(View.VISIBLE);
-
- // Wait for window manager to pickup the change, so we know the maximum height of the panel
- // then.
- mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (mStatusBarWindow.getHeight() != getStatusBarHeight()) {
- mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- mNotificationPanel.setExpandedFraction(1);
- }
- }
- });
+ mNotificationPanel.instantExpand();
}
private void instantCollapseNotificationPanel() {
@@ -2977,9 +2984,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void onActivated(View view) {
+ public void onActivated(ActivatableNotificationView view) {
userActivity();
mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
+ ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
+ if (previousView != null) {
+ previousView.makeInactive(true /* animate */);
+ }
mStackScroller.setActivatedChild(view);
}
@@ -2992,7 +3003,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
@Override
- public void onActivationReset(View view) {
+ public void onActivationReset(ActivatableNotificationView view) {
if (view == mStackScroller.getActivatedChild()) {
mKeyguardIndicationController.hideTransientIndication();
mStackScroller.setActivatedChild(null);
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 df01c12..d778ccb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -33,9 +33,9 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
-import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback,
ViewTreeObserver.OnComputeInternalInsetsListener {
@@ -51,7 +51,7 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
private SwipeHelper mSwipeHelper;
private EdgeSwipeHelper mEdgeSwipeHelper;
- private BaseStatusBar mBar;
+ private PhoneStatusBar mBar;
private ExpandHelper mExpandHelper;
private long mStartTouchTime;
@@ -69,7 +69,7 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
}
- public void setBar(BaseStatusBar bar) {
+ public void setBar(PhoneStatusBar bar) {
mBar = bar;
}
@@ -77,7 +77,10 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
return mContentHolder;
}
- public boolean setNotification(NotificationData.Entry headsUp) {
+ public boolean showNotification(NotificationData.Entry headsUp) {
+ // bump any previous heads up back to the shade
+ release();
+
mHeadsUp = headsUp;
if (mContentHolder != null) {
mContentHolder.removeAllViews();
@@ -97,10 +100,46 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
mSwipeHelper.snapChild(mContentHolder, 1f);
mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+
+ // 2. Animate mHeadsUpNotificationView in
+ mBar.scheduleHeadsUpOpen();
+
+ // 3. Set alarm to age the notification off
+ mBar.resetHeadsUpDecayTimer();
}
return true;
}
+ /** Discard the Heads Up notification. */
+ public void clear() {
+ mHeadsUp = null;
+ mBar.scheduleHeadsUpClose();
+ }
+
+ /** Respond to dismissal of the Heads Up window. */
+ public void dismiss() {
+ if (mHeadsUp == null) return;
+ if (mHeadsUp.notification.isClearable()) {
+ mBar.onNotificationClear(mHeadsUp.notification);
+ } else {
+ release();
+ }
+ mHeadsUp = null;
+ mBar.scheduleHeadsUpClose();
+ }
+
+ /** Push any current Heads Up notification down into the shade. */
+ public void release() {
+ if (mHeadsUp != null) {
+ mBar.displayNotificationFromHeadsUp(mHeadsUp.notification);
+ }
+ mHeadsUp = null;
+ }
+
+ public NotificationData.Entry getEntry() {
+ return mHeadsUp;
+ }
+
public boolean isClearable() {
return mHeadsUp == null || mHeadsUp.notification.isClearable();
}
@@ -125,7 +164,7 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
if (mHeadsUp != null) {
// whoops, we're on already!
- setNotification(mHeadsUp);
+ showNotification(mHeadsUp);
}
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
@@ -282,6 +321,10 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.
mTmpTwoArray[1] + mContentHolder.getHeight());
}
+ public void escalate() {
+ mBar.scheduleHeadsUpEscalation();
+ }
+
private class EdgeSwipeHelper implements Gefingerpoken {
private static final boolean DEBUG_EDGE_SWIPE = false;
private final float mTouchSlop;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index dc8f315..1f68860 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -30,7 +30,7 @@ public interface NetworkController {
void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description);
+ String dataTypeContentDescriptionId, String description, boolean noSim);
void onAirplaneModeChanged(boolean enabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index bf908fe..4e54e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -88,6 +88,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
int mQSDataTypeIconId;
int mAirplaneIconId;
boolean mDataActive;
+ boolean mNoSim;
int mLastSignalLevel;
boolean mShowPhoneRSSIForData = false;
boolean mShowAtLeastThreeGees = false;
@@ -350,18 +351,18 @@ public class NetworkControllerImpl extends BroadcastReceiver
if (isEmergencyOnly()) {
cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, null);
+ mContentDescriptionDataType, null, mNoSim);
} else {
if (mIsWimaxEnabled && mWimaxConnected) {
// Wimax is special
cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, mNetworkName);
+ mContentDescriptionDataType, mNetworkName, mNoSim);
} else {
// Normal mobile data
cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, mNetworkName);
+ mContentDescriptionDataType, mNetworkName, mNoSim);
}
}
cb.onAirplaneModeChanged(mAirplaneMode);
@@ -737,6 +738,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
// GSM case, we have to check also the sim state
if (mSimState == IccCardConstants.State.READY ||
mSimState == IccCardConstants.State.UNKNOWN) {
+ mNoSim = false;
if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
switch (mDataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN:
@@ -759,6 +761,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
} else {
iconId = R.drawable.stat_sys_no_sim;
+ mNoSim = true;
visible = false; // no SIM? no data
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index b21e12c..6d92b05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.stack;
import android.view.View;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import java.util.ArrayList;
@@ -27,7 +28,7 @@ public class AmbientState {
private ArrayList<View> mDraggedViews = new ArrayList<View>();
private int mScrollY;
private boolean mDimmed;
- private View mActivatedChild;
+ private ActivatableNotificationView mActivatedChild;
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
private int mSpeedBumpIndex = -1;
@@ -64,7 +65,7 @@ public class AmbientState {
* In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
* interaction. This child is then scaled normally and its background is fully opaque.
*/
- public void setActivatedChild(View activatedChild) {
+ public void setActivatedChild(ActivatableNotificationView activatedChild) {
mActivatedChild = activatedChild;
}
@@ -72,7 +73,7 @@ public class AmbientState {
return mDimmed;
}
- public View getActivatedChild() {
+ public ActivatableNotificationView getActivatedChild() {
return mActivatedChild;
}
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 5ace89f..94472a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -33,6 +33,7 @@ import android.widget.OverScroller;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.SpeedBumpView;
@@ -1722,7 +1723,6 @@ public class NotificationStackScrollLayout extends ViewGroup
mStackScrollAlgorithm.setIsExpanded(isExpanded);
if (!isExpanded) {
mOwnScrollY = 0;
- mSpeedBumpView.collapse();
}
}
@@ -1760,7 +1760,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* See {@link AmbientState#setActivatedChild}.
*/
- public void setActivatedChild(View activatedChild) {
+ public void setActivatedChild(ActivatableNotificationView activatedChild) {
mAmbientState.setActivatedChild(activatedChild);
if (mAnimationsEnabled) {
mActivateNeedsAnimation = true;
@@ -1769,7 +1769,7 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
- public View getActivatedChild() {
+ public ActivatableNotificationView getActivatedChild() {
return mAmbientState.getActivatedChild();
}
@@ -1791,7 +1791,6 @@ public class NotificationStackScrollLayout extends ViewGroup
int newVisibility = visible ? VISIBLE : GONE;
mSpeedBumpView.setVisibility(newVisibility);
if (visible) {
- mSpeedBumpView.collapse();
// Make invisible to ensure that the appear animation is played.
mSpeedBumpView.setInvisible();
if (!mIsExpansionChanging) {
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 94cb16d..1ad4acc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -160,9 +160,8 @@ public class StackScrollState {
}
if(child instanceof SpeedBumpView) {
- float speedBumpEnd = newYTranslation + newHeight;
- performSpeedBumpAnimation(i, (SpeedBumpView) child, speedBumpEnd,
- newYTranslation);
+ float lineEnd = newYTranslation + newHeight / 2;
+ performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd);
}
}
}
@@ -183,20 +182,12 @@ public class StackScrollState {
child.setClipBounds(mClipRect);
}
- private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
- float speedBumpStart) {
+ private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd) {
View nextChild = getNextChildNotGone(i);
if (nextChild != null) {
ViewState nextState = getViewStateForView(nextChild);
- boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+ boolean startIsAboveNext = nextState.yTranslation > speedBumpEnd;
speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */);
-
- // handle expanded case
- if (speedBump.isExpanded()) {
- boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
- speedBump.animateExplanationText(endIsAboveNext);
- }
-
}
}
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 faea8de..9260aac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,14 +17,14 @@
package com.android.systemui.statusbar.tv;
import android.os.IBinder;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BaseStatusBar;
/*
@@ -51,11 +51,11 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
}
@Override
- protected void updateRankingInternal(Ranking ranking) {
+ protected void updateRankingInternal(RankingMap ranking) {
}
@Override
@@ -63,7 +63,7 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void removeNotificationInternal(String key, Ranking ranking) {
+ public void removeNotificationInternal(String key, RankingMap ranking) {
}
@Override
@@ -147,6 +147,18 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
+ public void scheduleHeadsUpOpen() {
+ }
+
+ @Override
+ public void scheduleHeadsUpEscalation() {
+ }
+
+ @Override
+ public void scheduleHeadsUpClose() {
+ }
+
+ @Override
protected int getMaxKeyguardNotifications() {
return 0;
}
@@ -164,10 +176,10 @@ public class TvStatusBar extends BaseStatusBar {
}
@Override
- public void onActivated(View view) {
+ public void onActivated(ActivatableNotificationView view) {
}
@Override
- public void onActivationReset(View view) {
+ public void onActivationReset(ActivatableNotificationView view) {
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index eca1bc1..faa0c57 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1640,6 +1640,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
pw.println("}]");
pw.println();
}
+ final int windowCount = mSecurityPolicy.mWindows.size();
+ for (int j = 0; j < windowCount; j++) {
+ if (j > 0) {
+ pw.append(',');
+ pw.println();
+ }
+ pw.append("Window[");
+ AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(j);
+ pw.append(window.toString());
+ pw.append(']');
+ }
}
}
@@ -3283,7 +3294,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
if (mTouchInteractionInProgress && activeWindowGone) {
- mActiveWindowId = INVALID_WINDOW_ID;
+ mActiveWindowId = mFocusedWindowId;
}
// Focused window may change the active one, so set the
@@ -3336,10 +3347,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
// The active window also determined events from which
// windows are delivered.
synchronized (mLock) {
- mFocusedWindowId = getFocusedWindowId();
- if (mWindowsForAccessibilityCallback == null
- && windowId == mFocusedWindowId) {
- mActiveWindowId = windowId;
+ if (mWindowsForAccessibilityCallback == null) {
+ mFocusedWindowId = getFocusedWindowId();
+ if (windowId == mFocusedWindowId) {
+ mActiveWindowId = windowId;
+ }
}
}
} break;
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index fe5c2ef..aeb195f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.database.ContentObserver;
import android.os.BatteryStats;
import com.android.internal.app.IBatteryStats;
import com.android.server.am.BatteryStatsService;
@@ -149,8 +150,8 @@ public final class BatteryService extends Binder {
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
- mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
+ mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shutdownBatteryTemperature);
@@ -173,9 +174,37 @@ public final class BatteryService extends Binder {
void systemReady() {
// check our power situation now that it is safe to display the shutdown dialog.
synchronized (mLock) {
- shutdownIfNoPowerLocked();
- shutdownIfOverTempLocked();
+ ContentObserver obs = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ updateBatteryWarningLevelLocked();
+ }
+ }
+ };
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, obs, UserHandle.USER_ALL);
+ updateBatteryWarningLevelLocked();
+ }
+ }
+
+ void updateBatteryWarningLevelLocked() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ int defWarnLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryWarningLevel);
+ mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+ if (mLowBatteryWarningLevel == 0) {
+ mLowBatteryWarningLevel = defWarnLevel;
+ }
+ if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
+ mLowBatteryWarningLevel = mCriticalBatteryLevel;
}
+ mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
+ processValuesLocked(true);
}
/**
@@ -232,7 +261,7 @@ public final class BatteryService extends Binder {
}
}
- public boolean isBatteryLowLocked() {
+ public boolean shouldSendBatteryLowLocked() {
final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
@@ -299,14 +328,14 @@ public final class BatteryService extends Binder {
if (!mUpdatesStopped) {
mBatteryProps = props;
// Process the new values.
- processValuesLocked();
+ processValuesLocked(false);
} else {
mLastBatteryProps.set(props);
}
}
}
- private void processValuesLocked() {
+ private void processValuesLocked(boolean force) {
boolean logOutlier = false;
long dischargeDuration = 0;
@@ -349,14 +378,14 @@ public final class BatteryService extends Binder {
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+ if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
mBatteryProps.batteryHealth != mLastBatteryHealth ||
mBatteryProps.batteryPresent != mLastBatteryPresent ||
mBatteryProps.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
- mInvalidCharger != mLastInvalidCharger) {
+ mInvalidCharger != mLastInvalidCharger)) {
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -400,7 +429,24 @@ public final class BatteryService extends Binder {
logOutlier = true;
}
- mBatteryLevelLow = isBatteryLowLocked();
+ if (!mBatteryLevelLow) {
+ // Should we now switch in to low battery mode?
+ if (mPlugType == BATTERY_PLUGGED_NONE
+ && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
+ mBatteryLevelLow = true;
+ }
+ } else {
+ // Should we now switch out of low battery mode?
+ if (mPlugType != BATTERY_PLUGGED_NONE) {
+ mBatteryLevelLow = false;
+ } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
+ mBatteryLevelLow = false;
+ } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
+ // If being forced, the previous state doesn't matter, we will just
+ // absolutely check to see if we are now above the warning level.
+ mBatteryLevelLow = false;
+ }
+ }
sendIntentLocked();
@@ -428,7 +474,7 @@ public final class BatteryService extends Binder {
});
}
- if (mBatteryLevelLow) {
+ if (shouldSendBatteryLowLocked()) {
mSentLowBatteryBroadcast = true;
mHandler.post(new Runnable() {
@Override
@@ -650,7 +696,7 @@ public final class BatteryService extends Binder {
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
- processValuesLocked();
+ processValuesLocked(false);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -664,7 +710,7 @@ public final class BatteryService extends Binder {
if (mUpdatesStopped) {
mUpdatesStopped = false;
mBatteryProps.set(mLastBatteryProps);
- processValuesLocked();
+ processValuesLocked(false);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 32722bc..11f855e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -906,6 +906,9 @@ final class ActivityRecord {
}
startTime = 0;
finishLaunchTickingLocked();
+ if (task != null) {
+ task.hasBeenVisible = true;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 39800f2..03ce530 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -32,12 +32,12 @@ import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
@@ -74,6 +74,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
import android.view.Display;
@@ -1405,7 +1406,7 @@ final class ActivityStack {
ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) ||
- !mActivityContainer.isAttached()) {
+ !mActivityContainer.isAttachedLocked()) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
@@ -2677,11 +2678,14 @@ final class ActivityStack {
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
// it right now.
- boolean activityRemoved = destroyActivityLocked(r, true,
- oomAdj, "finish-imm");
+ r.makeFinishing();
+ boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
if (activityRemoved) {
mStackSupervisor.resumeTopActivitiesLocked();
}
+ if (DEBUG_CONTAINERS) Slog.d(TAG,
+ "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
+ " destroy returned removed=" + activityRemoved);
return activityRemoved ? null : r;
}
@@ -3044,6 +3048,7 @@ final class ActivityStack {
if (r != null) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "activityDestroyedLocked: r=" + r);
if (isInStackLocked(token) != null) {
if (r.state == ActivityState.DESTROYING) {
@@ -3803,7 +3808,7 @@ final class ActivityStack {
mStacks.remove(this);
mStacks.add(0, this);
}
- mActivityContainer.onTaskListEmpty();
+ mActivityContainer.onTaskListEmptyLocked();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index dcdc610..545a9f7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -111,6 +111,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final boolean DEBUG_STATES = DEBUG || false;
static final boolean DEBUG_IDLE = DEBUG || false;
static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
+ static final boolean DEBUG_CONTAINERS = DEBUG || false;
public static final int HOME_STACK_ID = 0;
@@ -135,6 +136,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final int LOCK_TASK_START_MSG = FIRST_SUPERVISOR_STACK_MSG + 9;
static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 11;
+ static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 12;
private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
@@ -239,7 +241,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
- SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+ private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
/** Mapping from displayId to display current state */
private final SparseArray<ActivityDisplay> mActivityDisplays =
@@ -2255,8 +2257,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
ActivityContainer createActivityContainer(ActivityRecord parentActivity,
IActivityContainerCallback callback) {
- ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback);
+ ActivityContainer activityContainer =
+ new VirtualActivityContainer(parentActivity, callback);
mActivityContainers.put(activityContainer.mStackId, activityContainer);
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "createActivityContainer: " + activityContainer);
parentActivity.mChildContainers.add(activityContainer);
return activityContainer;
}
@@ -2265,6 +2269,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
ActivityContainer container = childStacks.remove(containerNdx);
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "removeChildActivityContainers: removing " +
+ container);
container.release();
}
}
@@ -2272,11 +2278,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
void deleteActivityContainer(IActivityContainer container) {
ActivityContainer activityContainer = (ActivityContainer)container;
if (activityContainer != null) {
- activityContainer.mStack.finishAllActivitiesLocked();
- final ActivityRecord parent = activityContainer.mParentActivity;
- if (parent != null) {
- parent.mChildContainers.remove(activityContainer);
- }
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "deleteActivityContainer: ",
+ new RuntimeException("here").fillInStackTrace());
final int stackId = activityContainer.mStackId;
mActivityContainers.remove(stackId);
mWindowManager.removeStack(stackId);
@@ -3128,13 +3131,20 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
} break;
+ case CONTAINER_TASK_LIST_EMPTY_TIMEOUT: {
+ synchronized (mService) {
+ Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
+ msg.obj);
+ ((ActivityContainer) msg.obj).onTaskListEmptyLocked();
+ }
+ } break;
}
}
}
class ActivityContainer extends android.app.IActivityContainer.Stub {
final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
final int mStackId;
IActivityContainerCallback mCallback = null;
final ActivityStack mStack;
@@ -3184,8 +3194,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
@Override
public int getDisplayId() {
- if (mActivityDisplay != null) {
- return mActivityDisplay.mDisplayId;
+ synchronized (mService) {
+ if (mActivityDisplay != null) {
+ return mActivityDisplay.mDisplayId;
+ }
}
return -1;
}
@@ -3194,10 +3206,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
public boolean injectEvent(InputEvent event) {
final long origId = Binder.clearCallingIdentity();
try {
- if (mActivityDisplay != null) {
- return mInputManagerInternal.injectInputEvent(event,
- mActivityDisplay.mDisplayId,
- InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ synchronized (mService) {
+ if (mActivityDisplay != null) {
+ return mInputManagerInternal.injectInputEvent(event,
+ mActivityDisplay.mDisplayId,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
}
return false;
} finally {
@@ -3207,10 +3221,16 @@ public final class ActivityStackSupervisor implements DisplayListener {
@Override
public void release() {
- mContainerState = CONTAINER_STATE_FINISHING;
- mStack.finishAllActivitiesLocked();
- detachLocked();
- mWindowManager.removeStack(mStackId);
+ synchronized (mService) {
+ if (mContainerState == CONTAINER_STATE_FINISHING) {
+ return;
+ }
+ mContainerState = CONTAINER_STATE_FINISHING;
+ final Message msg =
+ mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+ mHandler.sendMessageDelayed(msg, 1000);
+ mStack.finishAllActivitiesLocked();
+ }
}
private void detachLocked() {
@@ -3301,15 +3321,17 @@ public final class ActivityStackSupervisor implements DisplayListener {
return ActivityStackSupervisor.this;
}
- boolean isAttached() {
+ boolean isAttachedLocked() {
return mActivityDisplay != null;
}
void getBounds(Point outBounds) {
- if (mActivityDisplay != null) {
- mActivityDisplay.getBounds(outBounds);
- } else {
- outBounds.set(0, 0);
+ synchronized (mService) {
+ if (mActivityDisplay != null) {
+ mActivityDisplay.getBounds(outBounds);
+ } else {
+ outBounds.set(0, 0);
+ }
}
}
@@ -3332,7 +3354,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
return true;
}
- void onTaskListEmpty() {
+ void onTaskListEmptyLocked() {
+ mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+ if (!mStack.isHomeStack()) {
+ detachLocked();
+ deleteActivityContainer(this);
+ }
mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
}
@@ -3351,7 +3378,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mParentActivity = parent;
mCallback = callback;
mContainerState = CONTAINER_STATE_NO_SURFACE;
- mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+ mIdString = "VirtualActivityContainer{" + mStackId + ", parent=" + mParentActivity + "}";
}
@Override
@@ -3397,22 +3424,22 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- setSurfaceIfReady();
+ setSurfaceIfReadyLocked();
if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
+ virtualActivityDisplay);
}
@Override
- boolean isAttached() {
- return mSurface != null && super.isAttached();
+ boolean isAttachedLocked() {
+ return mSurface != null && super.isAttachedLocked();
}
@Override
void setDrawn() {
synchronized (mService) {
mDrawn = true;
- setSurfaceIfReady();
+ setSurfaceIfReadyLocked();
}
}
@@ -3422,8 +3449,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
return false;
}
- private void setSurfaceIfReady() {
- if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
+ private void setSurfaceIfReadyLocked() {
+ if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
" mContainerState=" + mContainerState + " mSurface=" + mSurface);
if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 79e2d9d..81a0b36 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -73,6 +73,7 @@ final class TaskRecord extends ThumbnailHolder {
boolean rootWasReset; // True if the intent at the root of the task had
// the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
boolean askedCompatMode;// Have asked the user about compat mode for this task.
+ boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
String stringName; // caching of toString() result.
int userId; // user for which this task was created
@@ -328,8 +329,12 @@ final class TaskRecord extends ThumbnailHolder {
}
boolean autoRemoveFromRecents() {
- return intent != null &&
- (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+ // We will automatically remove the task either if it has explicitly asked for
+ // this, or it is empty and has never contained an activity that got shown to
+ // the user.
+ return (intent != null &&
+ (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0) ||
+ (mActivities.isEmpty() && !hasBeenVisible);
}
/**
@@ -800,7 +805,8 @@ final class TaskRecord extends ThumbnailHolder {
}
pw.print(prefix); pw.print("lastThumbnail="); pw.print(lastThumbnail);
pw.print(" lastDescription="); pw.println(lastDescription);
- pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
+ pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
+ pw.print(" lastActiveTime="); pw.print(lastActiveTime);
pw.print(" (inactive for ");
pw.print((getInactiveDuration()/1000)); pw.println("s)");
}
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 6f42c8b..d36fc2c 100644
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -259,7 +259,7 @@ final class DeviceDiscoveryAction extends FeatureAction {
byte params[] = cmd.getParams();
if (params.length == 3) {
- current.mPhysicalAddress = ((params[0] & 0xFF) << 8) | (params[1] & 0xFF);
+ current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
current.mDeviceType = params[2] & 0xFF;
increaseProcessedDeviceCount();
@@ -307,9 +307,7 @@ final class DeviceDiscoveryAction extends FeatureAction {
byte[] params = cmd.getParams();
if (params.length == 3) {
- int vendorId = ((params[0] & 0xFF) << 16)
- | ((params[1] & 0xFF) << 8)
- | (params[2] & 0xFF);
+ int vendorId = HdmiUtils.threeBytesToInt(params);
current.mVendorId = vendorId;
} else {
Slog.w(TAG, "Invalid vendor id: " + cmd.toString());
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5c420d7..f869424 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -387,6 +387,41 @@ final class HdmiCecController {
}
/**
+ * Pass a option to CEC HAL.
+ *
+ * @param flag a key of option. For more details, look at
+ * {@link HdmiConstants#FLAG_HDMI_OPTION_WAKEUP} to
+ * {@link HdmiConstants#FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL}
+ * @param value a value of option. Actual value varies flag. For more
+ * details, look at description of flags
+ */
+ void setOption(int flag, int value) {
+ assertRunOnServiceThread();
+ nativeSetOption(mNativePtr, flag, value);
+ }
+
+ /**
+ * Configure ARC circuit in the hardware logic to start or stop the feature.
+ *
+ * @param enabled whether to enable/disable ARC
+ */
+ void setAudioReturnChannel(boolean enabled) {
+ assertRunOnServiceThread();
+ nativeSetAudioReturnChannel(mNativePtr, enabled);
+ }
+
+ /**
+ * Return the connection status of the specified port
+ *
+ * @param port port number to check connection status
+ * @return true if connected; otherwise, return false
+ */
+ boolean isConnected(int port) {
+ assertRunOnServiceThread();
+ return nativeIsConnected(mNativePtr, port);
+ }
+
+ /**
* Poll all remote devices. It sends &lt;Polling Message&gt; to all remote
* devices.
*
@@ -606,4 +641,8 @@ final class HdmiCecController {
private static native int nativeGetPhysicalAddress(long controllerPtr);
private static native int nativeGetVersion(long controllerPtr);
private static native int nativeGetVendorId(long controllerPtr);
+ private static native void nativeSetOption(long controllerPtr, int flag, int value);
+ private static native void nativeSetAudioReturnChannel(long controllerPtr, boolean flag);
+ private static native boolean nativeIsConnected(long controllerPtr, int port);
+
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 23454ad..6697a53 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -18,12 +18,15 @@ package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
/**
* Class that models a logical CEC device hosted in this system. Handles initialization,
* CEC commands that call for actions customized per device type.
*/
abstract class HdmiCecLocalDevice {
+ private static final String TAG = "HdmiCecLocalDevice";
protected final HdmiControlService mService;
protected final int mDeviceType;
@@ -59,6 +62,83 @@ abstract class HdmiCecLocalDevice {
*/
protected abstract void onAddressAllocated(int logicalAddress);
+ /**
+ * Dispatch incoming message.
+ *
+ * @param message incoming message
+ * @return true if consumed a message; otherwise, return false.
+ */
+ final boolean dispatchMessage(HdmiCecMessage message) {
+ int dest = message.getDestination();
+ if (dest != mAddress && dest != HdmiCec.ADDR_BROADCAST) {
+ return false;
+ }
+ return onMessage(message);
+ }
+
+ protected boolean onMessage(HdmiCecMessage message) {
+ switch (message.getOpcode()) {
+ case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
+ return handleGetMenuLanguage(message);
+ case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
+ return handleGivePhysicalAddress();
+ case HdmiCec.MESSAGE_GIVE_OSD_NAME:
+ return handleGiveOsdName(message);
+ case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
+ return handleGiveDeviceVendorId();
+ case HdmiCec.MESSAGE_GET_CEC_VERSION:
+ return handleGetCecVersion(message);
+ default:
+ return false;
+ }
+ }
+
+ protected boolean handleGivePhysicalAddress() {
+ int physicalAddress = mService.getPhysicalAddress();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ mAddress, physicalAddress, mDeviceType);
+ mService.sendCecCommand(cecMessage);
+ return true;
+ }
+
+ protected boolean handleGiveDeviceVendorId() {
+ int vendorId = mService.getVendorId();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ mAddress, vendorId);
+ mService.sendCecCommand(cecMessage);
+ return true;
+ }
+
+ protected boolean handleGetCecVersion(HdmiCecMessage message) {
+ int version = mService.getCecVersion();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
+ message.getSource(), version);
+ mService.sendCecCommand(cecMessage);
+ return true;
+ }
+
+ protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
+ Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
+ message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
+ HdmiConstants.ABORT_UNRECOGNIZED_MODE));
+ return true;
+ }
+
+ protected boolean handleGiveOsdName(HdmiCecMessage message) {
+ // Note that since this method is called after logical address allocation is done,
+ // mDeviceInfo should not be null.
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ mAddress, message.getSource(), mDeviceInfo.getDisplayName());
+ if (cecMessage != null) {
+ mService.sendCecCommand(cecMessage);
+ } else {
+ Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName());
+ }
+ return true;
+ }
+
final void handleAddressAllocated(int logicalAddress) {
mAddress = mPreferredAddress = logicalAddress;
onAddressAllocated(logicalAddress);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 72d7f2d..8bd81ea 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -17,11 +17,16 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+
+import java.util.Locale;
/**
* Represent a logical device of type TV residing in Android system.
*/
final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
+ private static final String TAG = "HdmiCecLocalDeviceTv";
HdmiCecLocalDeviceTv(HdmiControlService service) {
super(service, HdmiCec.DEVICE_TV);
@@ -39,4 +44,42 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
mService.launchDeviceDiscovery(mAddress);
// TODO: Start routing control action, device discovery action.
}
+
+ @Override
+ protected boolean onMessage(HdmiCecMessage message) {
+ switch (message.getOpcode()) {
+ case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
+ return handleReportPhysicalAddress(message);
+ default:
+ return super.onMessage(message);
+ }
+ }
+
+ @Override
+ protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
+ mAddress, Locale.getDefault().getISO3Language());
+ // TODO: figure out how to handle failed to get language code.
+ if (command != null) {
+ mService.sendCecCommand(command);
+ } else {
+ Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
+ }
+ return true;
+ }
+
+ private boolean handleReportPhysicalAddress(HdmiCecMessage message) {
+ // Ignore if [Device Discovery Action] is going on.
+ if (mService.hasAction(DeviceDiscoveryAction.class)) {
+ Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
+ + "because Device Discovery Action is on-going:" + message);
+ return true;
+ }
+
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ mService.addAndStartAction(new NewDeviceAction(mService,
+ mAddress, message.getSource(), physicalAddress));
+
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
index a83d1ed..54b5dcb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConstants.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -43,5 +43,31 @@ final class HdmiConstants {
static final int UI_COMMAND_MUTE_FUNCTION = 0x65;
static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66;
+ // Flags used for setOption to CEC HAL.
+ /**
+ * When set to false, HAL does not wake up the system upon receiving
+ * <Image View On> or <Text View On>. Used when user changes the TV
+ * settings to disable the auto TV on functionality.
+ * True by default.
+ */
+ static final int FLAG_HDMI_OPTION_WAKEUP = 1;
+ /**
+ * When set to false, all the CEC commands are discarded. Used when
+ * user changes the TV settings to disable CEC functionality.
+ * True by default.
+ */
+ static final int FLAG_HDMI_OPTION_ENABLE_CEC = 2;
+ /**
+ * Setting this flag to false means Android system will stop handling
+ * CEC service and yield the control over to the microprocessor that is
+ * powered on through the standby mode. When set to true, the system
+ * will gain the control over, hence telling the microprocessor to stop
+ * handling the cec commands. This is called when system goes
+ * in and out of standby mode to notify the microprocessor that it should
+ * start/stop handling CEC commands on behalf of the system.
+ * False by default.
+ */
+ static final int FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL = 3;
+
private HdmiConstants() { /* cannot be instantiated */ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 58bd5f1..d41da30 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -24,6 +24,7 @@ import android.hardware.hdmi.HdmiCecMessage;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -42,7 +43,6 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Locale;
/**
* Provides a service for sending and processing HDMI control messages,
@@ -239,6 +239,13 @@ public final class HdmiControlService extends SystemService {
}
/**
+ * Returns version of CEC.
+ */
+ int getCecVersion() {
+ return mCecController.getVersion();
+ }
+
+ /**
* Returns a list of {@link HdmiCecDeviceInfo}.
*
* @param includeLocalDevice whether to include local devices
@@ -277,7 +284,7 @@ public final class HdmiControlService extends SystemService {
}
// See if we have an action of a given type in progress.
- private <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
+ <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
for (FeatureAction action : mActions) {
if (action.getClass().equals(clazz)) {
return true;
@@ -335,10 +342,13 @@ public final class HdmiControlService extends SystemService {
* @return {@code true} if ARC was in "Enabled" status
*/
boolean setArcStatus(boolean enabled) {
+ assertRunOnServiceThread();
synchronized (mLock) {
boolean oldStatus = mArcStatusEnabled;
// 1. Enable/disable ARC circuit.
- // TODO: call set_audio_return_channel of hal interface.
+ mCecController.setAudioReturnChannel(enabled);
+
+ // TODO: notify arc mode change to AudioManager.
// 2. Update arc status;
mArcStatusEnabled = enabled;
@@ -366,31 +376,14 @@ public final class HdmiControlService extends SystemService {
// Commands that queries system information replies directly instead
// of creating FeatureAction because they are state-less.
+ // TODO: move the leftover message to local device.
switch (message.getOpcode()) {
- case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
- handleGetMenuLanguage(message);
- return true;
- case HdmiCec.MESSAGE_GIVE_OSD_NAME:
- handleGiveOsdName(message);
- return true;
- case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
- handleGivePhysicalAddress(message);
- return true;
- case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
- handleGiveDeviceVendorId(message);
- return true;
- case HdmiCec.MESSAGE_GET_CEC_VERSION:
- handleGetCecVersion(message);
- return true;
case HdmiCec.MESSAGE_INITIATE_ARC:
handleInitiateArc(message);
return true;
case HdmiCec.MESSAGE_TERMINATE_ARC:
handleTerminateArc(message);
return true;
- case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
- handleReportPhysicalAddress(message);
- return true;
case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
handleSetSystemAudioMode(message);
return true;
@@ -398,8 +391,22 @@ public final class HdmiControlService extends SystemService {
handleSystemAudioModeStatus(message);
return true;
default:
- return dispatchMessageToAction(message);
+ if (dispatchMessageToAction(message)) {
+ return true;
+ }
+ break;
}
+
+ return dispatchMessageToLocalDevice(message);
+ }
+
+ private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) {
+ for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
+ if (device.dispatchMessage(message)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -446,9 +453,8 @@ public final class HdmiControlService extends SystemService {
void launchDeviceDiscovery(final int sourceAddress) {
// At first, clear all existing device infos.
mCecController.clearDeviceInfoList();
- mCecMessageCache.flushAll();
+ // TODO: flush cec message cache when CEC is turned off.
- // TODO: check whether TV is one of local devices.
DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress,
new DeviceDiscoveryCallback() {
@Override
@@ -470,28 +476,12 @@ public final class HdmiControlService extends SystemService {
}
private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
- // TODO: get device name read from system configuration.
- String displayName = HdmiCec.getDefaultDeviceName(logicalAddress);
+ // TODO: find better name instead of model name.
+ String displayName = Build.MODEL;
return new HdmiCecDeviceInfo(logicalAddress,
getPhysicalAddress(), deviceType, getVendorId(), displayName);
}
- private void handleReportPhysicalAddress(HdmiCecMessage message) {
- // At first, try to consume it.
- if (dispatchMessageToAction(message)) {
- return;
- }
-
- // Ignore if [Device Discovery Action] is going on.
- if (hasAction(DeviceDiscoveryAction.class)) {
- Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
- + "because Device Discovery Action is on-going:" + message);
- return;
- }
-
- // TODO: start new device action.
- }
-
private void handleInitiateArc(HdmiCecMessage message){
// In case where <Initiate Arc> is started by <Request ARC Initiation>
// need to clean up RequestArcInitiationAction.
@@ -512,64 +502,6 @@ public final class HdmiControlService extends SystemService {
addAndStartAction(action);
}
- private void handleGetCecVersion(HdmiCecMessage message) {
- int version = mCecController.getVersion();
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
- message.getSource(),
- version);
- sendCecCommand(cecMessage);
- }
-
- private void handleGiveDeviceVendorId(HdmiCecMessage message) {
- int vendorId = mCecController.getVendorId();
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
- message.getDestination(), vendorId);
- sendCecCommand(cecMessage);
- }
-
- private void handleGivePhysicalAddress(HdmiCecMessage message) {
- int physicalAddress = mCecController.getPhysicalAddress();
- int deviceType = HdmiCec.getTypeFromAddress(message.getDestination());
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- message.getDestination(), physicalAddress, deviceType);
- sendCecCommand(cecMessage);
- }
-
- private void handleGiveOsdName(HdmiCecMessage message) {
- // TODO: read device name from settings or property.
- String name = HdmiCec.getDefaultDeviceName(message.getDestination());
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
- message.getDestination(), message.getSource(), name);
- if (cecMessage != null) {
- sendCecCommand(cecMessage);
- } else {
- Slog.w(TAG, "Failed to build <Get Osd Name>:" + name);
- }
- }
-
- private void handleGetMenuLanguage(HdmiCecMessage message) {
- // Only 0 (TV), 14 (specific use) can answer.
- if (message.getDestination() != HdmiCec.ADDR_TV
- && message.getDestination() != HdmiCec.ADDR_SPECIFIC_USE) {
- Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
- sendCecCommand(
- HdmiCecMessageBuilder.buildFeatureAbortCommand(message.getDestination(),
- message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
- HdmiConstants.ABORT_UNRECOGNIZED_MODE));
- return;
- }
-
- HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
- message.getDestination(),
- Locale.getDefault().getISO3Language());
- // TODO: figure out how to handle failed to get language code.
- if (command != null) {
- sendCecCommand(command);
- } else {
- Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
- }
- }
-
private boolean dispatchMessageToAction(HdmiCecMessage message) {
for (FeatureAction action : mActions) {
if (action.processCommand(message)) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index ef128ed1..ca09fe6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -71,4 +71,24 @@ final class HdmiUtils {
return cmd.getParams().length > 0
&& cmd.getParams()[0] == HdmiConstants.SYSTEM_AUDIO_STATUS_ON;
}
+
+ /**
+ * Assemble two bytes into single integer value.
+ *
+ * @param data to be assembled
+ * @return assembled value
+ */
+ static int twoBytesToInt(byte[] data) {
+ return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
+ }
+
+ /**
+ * Assemble three bytes into single integer value.
+ *
+ * @param data to be assembled
+ * @return assembled value
+ */
+ static int threeBytesToInt(byte[] data) {
+ return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 088c40b..c284d10 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -114,8 +114,7 @@ final class NewDeviceAction extends FeatureAction {
} else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
if (params.length == 3) {
- mVendorId = ((params[0] & 0xFF) << 16) + ((params[1] & 0xFF) << 8)
- + (params[2] & 0xFF);
+ mVendorId = HdmiUtils.threeBytesToInt(params);
} else {
Slog.e(TAG, "Failed to get device vendor ID: ");
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 386402b..06732ca 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -188,6 +188,8 @@ public class NotificationManagerService extends SystemService {
private AppOpsManager mAppOps;
+ private Archive mArchive;
+
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -223,10 +225,12 @@ public class NotificationManagerService extends SystemService {
private static final int REASON_LISTENER_CANCEL_ALL = 11;
private static class Archive {
- static final int BUFFER_SIZE = 250;
- ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
+ final int mBufferSize;
+ final ArrayDeque<StatusBarNotification> mBuffer;
- public Archive() {
+ public Archive(int size) {
+ mBufferSize = size;
+ mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
}
public String toString() {
@@ -240,7 +244,7 @@ public class NotificationManagerService extends SystemService {
}
public void record(StatusBarNotification nr) {
- if (mBuffer.size() == BUFFER_SIZE) {
+ if (mBuffer.size() == mBufferSize) {
mBuffer.removeFirst();
}
@@ -250,7 +254,6 @@ public class NotificationManagerService extends SystemService {
mBuffer.addLast(nr.cloneLight());
}
-
public void clear() {
mBuffer.clear();
}
@@ -300,7 +303,7 @@ public class NotificationManagerService extends SystemService {
}
public StatusBarNotification[] getArray(int count) {
- if (count == 0) count = Archive.BUFFER_SIZE;
+ if (count == 0) count = mBufferSize;
final StatusBarNotification[] a
= new StatusBarNotification[Math.min(count, mBuffer.size())];
Iterator<StatusBarNotification> iter = descendingIterator();
@@ -312,7 +315,7 @@ public class NotificationManagerService extends SystemService {
}
public StatusBarNotification[] getArray(int count, String pkg, int userId) {
- if (count == 0) count = Archive.BUFFER_SIZE;
+ if (count == 0) count = mBufferSize;
final StatusBarNotification[] a
= new StatusBarNotification[Math.min(count, mBuffer.size())];
Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
@@ -325,8 +328,6 @@ public class NotificationManagerService extends SystemService {
}
- Archive mArchive = new Archive();
-
private void loadPolicyFile() {
synchronized(mPolicyFile) {
mBlockedPackages.clear();
@@ -854,6 +855,9 @@ public class NotificationManagerService extends SystemService {
}
}
+ mArchive = new Archive(resources.getInteger(
+ R.integer.config_notificationServiceArchiveSize));
+
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8585b4e..6cfcbdc 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4991,6 +4991,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mResolveActivity.packageName = mAndroidApplication.packageName;
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
mResolveActivity.exported = true;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d8671d9..fb4b8f0 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -409,6 +409,9 @@ public final class PowerManagerService extends com.android.server.SystemService
// Current state of the low power mode setting.
private boolean mLowPowerModeSetting;
+ // Current state of whether the settings are allowing auto low power mode.
+ private boolean mAutoLowPowerModeEnabled;
+
// True if the battery level is currently considered low.
private boolean mBatteryLevelLow;
@@ -558,6 +561,9 @@ public final class PowerManagerService extends com.android.server.SystemService
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, mSettingsObserver, UserHandle.USER_ALL);
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -645,8 +651,12 @@ public final class PowerManagerService extends com.android.server.SystemService
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
- if (lowPowerModeEnabled != mLowPowerModeSetting) {
+ final boolean autoLowPowerModeEnabled = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15) != 0;
+ if (lowPowerModeEnabled != mLowPowerModeSetting
+ || autoLowPowerModeEnabled != mAutoLowPowerModeEnabled) {
mLowPowerModeSetting = lowPowerModeEnabled;
+ mAutoLowPowerModeEnabled = autoLowPowerModeEnabled;
updateLowPowerModeLocked();
}
@@ -654,7 +664,8 @@ public final class PowerManagerService extends com.android.server.SystemService
}
void updateLowPowerModeLocked() {
- final boolean lowPowerModeEnabled = mLowPowerModeSetting || mBatteryLevelLow;
+ final boolean lowPowerModeEnabled = !mIsPowered
+ && (mLowPowerModeSetting || (mAutoLowPowerModeEnabled && mBatteryLevelLow));
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
@@ -1197,7 +1208,7 @@ public final class PowerManagerService extends com.android.server.SystemService
}
}
- if (oldLevelLow != mBatteryLevelLow) {
+ if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
updateLowPowerModeLocked();
}
}
@@ -2168,6 +2179,8 @@ public final class PowerManagerService extends com.android.server.SystemService
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
pw.println(" mSandmanSummoned=" + mSandmanSummoned);
+ pw.println(" mLowPowerModeEnabled=" + mLowPowerModeEnabled);
+ pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
@@ -2204,6 +2217,8 @@ public final class PowerManagerService extends com.android.server.SystemService
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
+ pw.println(" mLowPowerModeSetting=" + mLowPowerModeSetting);
+ pw.println(" mAutoLowPowerModeEnabled=" + mAutoLowPowerModeEnabled);
pw.println(" mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
pw.println(" mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
pw.println(" mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 32546df..b9ef492 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -186,12 +186,16 @@ public class TrustManagerService extends SystemService {
if (resolveInfo.serviceInfo == null) continue;
String packageName = resolveInfo.serviceInfo.packageName;
+ // STOPSHIP Reenable this check once the GMS Core prebuild library has the
+ // permission.
+ /*
if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Skipping agent because package " + packageName
+ " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
continue;
}
+ */
ComponentName name = getComponentName(resolveInfo);
if (!enabledAgents.contains(name)) continue;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index cfd09e5..95cfa24 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -166,6 +166,15 @@ final class AccessibilityController {
}
}
+
+ public void onSomeWindowResizedOrMoved() {
+ // Not relevant for the display magnifier.
+
+ if (mWindowsForAccessibilityObserver != null) {
+ mWindowsForAccessibilityObserver.computeChangedWindows();
+ }
+ }
+
/** NOTE: This has to be called within a surface transaction. */
public void drawMagnifiedRegionBorderIfNeededLocked() {
if (mDisplayMagnifier != null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c5d7a54..93a763a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -151,7 +151,6 @@ import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -9228,6 +9227,13 @@ public class WindowManagerService extends IWindowManager.Stub
winAnimator.setAnimation(a);
winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+
+ //TODO (multidisplay): Accessibility supported only for the default display.
+ if (mAccessibilityController != null
+ && displayId == Display.DEFAULT_DISPLAY) {
+ mAccessibilityController.onSomeWindowResizedOrMoved();
+ }
+
try {
w.mClient.moved(w.mFrame.left, w.mFrame.top);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4a80e3e..fe771dc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -36,6 +36,7 @@ import android.os.Debug;
import android.os.RemoteCallbackList;
import android.os.SystemClock;
import android.util.TimeUtils;
+import android.view.Display;
import android.view.IWindowFocusObserver;
import android.view.IWindowId;
import com.android.server.input.InputWindowHandle;
@@ -1359,6 +1360,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
newConfig);
}
+
+ //TODO (multidisplay): Accessibility supported only for the default display.
+ if (mService.mAccessibilityController != null
+ && getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onSomeWindowResizedOrMoved();
+ }
+
mOverscanInsetsChanged = false;
mContentInsetsChanged = false;
mVisibleInsetsChanged = false;
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index a734026..cbc853d 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -57,6 +57,12 @@ public:
int getVersion();
// Get vendor id used for vendor command.
uint32_t getVendorId();
+ // Set a flag and its value.
+ void setOption(int flag, int value);
+ // Set audio return channel status.
+ void setAudioReturnChannel(bool flag);
+ // Whether to hdmi device is connected to the given port.
+ bool isConnected(int port);
jobject getCallbacksObj() const {
return mCallbacksObj;
@@ -222,6 +228,20 @@ uint32_t HdmiCecController::getVendorId() {
return vendorId;
}
+void HdmiCecController::setOption(int flag, int value) {
+ mDevice->set_option(mDevice, flag, value);
+}
+
+// Set audio return channel status.
+void HdmiCecController::setAudioReturnChannel(bool enabled) {
+ mDevice->set_audio_return_channel(mDevice, enabled ? 1 : 0);
+}
+
+// Whether to hdmi device is connected to the given port.
+bool HdmiCecController::isConnected(int port) {
+ return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
+}
+
// static
void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
@@ -326,6 +346,26 @@ static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
return controller->getVendorId();
}
+static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag,
+ jint value) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ controller->setOption(flag, value);
+}
+
+static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
+ jboolean enabled) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ controller->setAudioReturnChannel(enabled == JNI_TRUE);
+}
+
+static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
@@ -337,6 +377,9 @@ static JNINativeMethod sMethods[] = {
{ "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
{ "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
{ "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
+ { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
+ { "nativeSetAudioReturnChannel", "(JZ)V", (void *) nativeSetAudioReturnChannel },
+ { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
};
#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 5cfe0f1..29d6f7e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -818,12 +818,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
if (who != null) {
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
+ throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+ + " does not own the device");
+ }
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
+ throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+ + " does not own the profile");
+ }
throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+ " did not specify uses-policy for: "
+ candidates.get(0).info.getTagForPolicy(reqPolicy));
} else {
throw new SecurityException("No active admin owned by uid "
- + Binder.getCallingUid() + " for policy:" + reqPolicy);
+ + Binder.getCallingUid() + " for policy #" + reqPolicy);
}
}
diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk
new file mode 100644
index 0000000..7e5911d
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
new file mode 100644
index 0000000..a92b5d8
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.camera2.cameratoo">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:label="CameraToo">
+ <activity
+ android:name=".CameraTooActivity"
+ android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
new file mode 100644
index 0000000..f93f177
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/mainSurfaceView"
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:onClick="onClickOnSurfaceView" />
diff --git a/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
new file mode 100644
index 0000000..c630bad
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
@@ -0,0 +1,437 @@
+/*
+ * 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 com.example.android.camera2.cameratoo;
+
+import android.app.Activity;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Size;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A basic demonstration of how to write a point-and-shoot camera app against the new
+ * android.hardware.camera2 API.
+ */
+public class CameraTooActivity extends Activity {
+ /** Output files will be saved as /sdcard/Pictures/cameratoo*.jpg */
+ static final String CAPTURE_FILENAME_PREFIX = "cameratoo";
+ /** Tag to distinguish log prints. */
+ static final String TAG = "CameraToo";
+
+ /** An additional thread for running tasks that shouldn't block the UI. */
+ HandlerThread mBackgroundThread;
+ /** Handler for running tasks in the background. */
+ Handler mBackgroundHandler;
+ /** Handler for running tasks on the UI thread. */
+ Handler mForegroundHandler;
+ /** View for displaying the camera preview. */
+ SurfaceView mSurfaceView;
+ /** Used to retrieve the captured image when the user takes a snapshot. */
+ ImageReader mCaptureBuffer;
+ /** Handle to the Android camera services. */
+ CameraManager mCameraManager;
+ /** The specific camera device that we're using. */
+ CameraDevice mCamera;
+ /** Our image capture session. */
+ CameraCaptureSession mCaptureSession;
+
+ /**
+ * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+ * width and height are at least as large as the respective requested values.
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param width The minimum desired width
+ * @param height The minimum desired height
+ * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+ */
+ static Size chooseBigEnoughSize(Size[] choices, int width, int height) {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ List<Size> bigEnough = new ArrayList<Size>();
+ for (Size option : choices) {
+ if (option.getWidth() >= width && option.getHeight() >= height) {
+ bigEnough.add(option);
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ /**
+ * Compares two {@code Size}s based on their areas.
+ */
+ static class CompareSizesByArea implements Comparator<Size> {
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ // We cast here to ensure the multiplications won't overflow
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+ (long) rhs.getWidth() * rhs.getHeight());
+ }
+ }
+
+ /**
+ * Called when our {@code Activity} gains focus. <p>Starts initializing the camera.</p>
+ */
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Start a background thread to manage camera requests
+ mBackgroundThread = new HandlerThread("background");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ mForegroundHandler = new Handler(getMainLooper());
+
+ mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
+
+ // Inflate the SurfaceView, set it as the main layout, and attach a listener
+ View layout = getLayoutInflater().inflate(R.layout.mainactivity, null);
+ mSurfaceView = (SurfaceView) layout.findViewById(R.id.mainSurfaceView);
+ mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
+ setContentView(mSurfaceView);
+
+ // Control flow continues in mSurfaceHolderCallback.surfaceChanged()
+ }
+
+ /**
+ * Called when our {@code Activity} loses focus. <p>Tears everything back down.</p>
+ */
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ try {
+ // Ensure SurfaceHolderCallback#surfaceChanged() will run again if the user returns
+ mSurfaceView.getHolder().setFixedSize(/*width*/0, /*height*/0);
+
+ // Cancel any stale preview jobs
+ if (mCaptureSession != null) {
+ mCaptureSession.close();
+ mCaptureSession = null;
+ }
+ } finally {
+ if (mCamera != null) {
+ mCamera.close();
+ mCamera = null;
+ }
+ }
+
+ // Finish processing posted messages, then join on the handling thread
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ } catch (InterruptedException ex) {
+ Log.e(TAG, "Background worker thread was interrupted while joined", ex);
+ }
+
+ // Close the ImageReader now that the background thread has stopped
+ if (mCaptureBuffer != null) mCaptureBuffer.close();
+ }
+
+ /**
+ * Called when the user clicks on our {@code SurfaceView}, which has ID {@code mainSurfaceView}
+ * as defined in the {@code mainactivity.xml} layout file. <p>Captures a full-resolution image
+ * and saves it to permanent storage.</p>
+ */
+ public void onClickOnSurfaceView(View v) {
+ if (mCaptureSession != null) {
+ try {
+ CaptureRequest.Builder requester =
+ mCamera.createCaptureRequest(mCamera.TEMPLATE_STILL_CAPTURE);
+ requester.addTarget(mCaptureBuffer.getSurface());
+ try {
+ // This handler can be null because we aren't actually attaching any callback
+ mCaptureSession.capture(requester.build(), /*listener*/null, /*handler*/null);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to file actual capture request", ex);
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to build actual capture request", ex);
+ }
+ } else {
+ Log.e(TAG, "User attempted to perform a capture outside our session");
+ }
+
+ // Control flow continues in mImageCaptureListener.onImageAvailable()
+ }
+
+ /**
+ * Callbacks invoked upon state changes in our {@code SurfaceView}.
+ */
+ final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+ /** The camera device to use, or null if we haven't yet set a fixed surface size. */
+ private String mCameraId;
+
+ /** Whether we received a change callback after setting our fixed surface size. */
+ private boolean mGotSecondCallback;
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ // This is called every time the surface returns to the foreground
+ Log.i(TAG, "Surface created");
+ mCameraId = null;
+ mGotSecondCallback = false;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.i(TAG, "Surface destroyed");
+ holder.removeCallback(this);
+ // We don't stop receiving callbacks forever because onResume() will reattach us
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // On the first invocation, width and height were automatically set to the view's size
+ if (mCameraId == null) {
+ // Find the device's back-facing camera and set the destination buffer sizes
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ CameraCharacteristics cameraCharacteristics =
+ mCameraManager.getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics.get(cameraCharacteristics.LENS_FACING) ==
+ CameraCharacteristics.LENS_FACING_BACK) {
+ Log.i(TAG, "Found a back-facing camera");
+ StreamConfigurationMap info = cameraCharacteristics
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ // Bigger is better when it comes to saving our image
+ Size largestSize = Collections.max(
+ Arrays.asList(info.getOutputSizes(ImageFormat.JPEG)),
+ new CompareSizesByArea());
+
+ // Prepare an ImageReader in case the user wants to capture images
+ Log.i(TAG, "Capture size: " + largestSize);
+ mCaptureBuffer = ImageReader.newInstance(largestSize.getWidth(),
+ largestSize.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
+ mCaptureBuffer.setOnImageAvailableListener(
+ mImageCaptureListener, mBackgroundHandler);
+
+ // Danger, W.R.! Attempting to use too large a preview size could
+ // exceed the camera bus' bandwidth limitation, resulting in
+ // gorgeous previews but the storage of garbage capture data.
+ Log.i(TAG, "SurfaceView size: " +
+ mSurfaceView.getWidth() + 'x' + mSurfaceView.getHeight());
+ Size optimalSize = chooseBigEnoughSize(
+ info.getOutputSizes(SurfaceHolder.class), width, height);
+
+ // Set the SurfaceHolder to use the camera's largest supported size
+ Log.i(TAG, "Preview size: " + optimalSize);
+ SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
+ surfaceHolder.setFixedSize(optimalSize.getWidth(),
+ optimalSize.getHeight());
+
+ mCameraId = cameraId;
+ return;
+
+ // Control flow continues with this method one more time
+ // (since we just changed our own size)
+ }
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Unable to list cameras", ex);
+ }
+
+ Log.e(TAG, "Didn't find any back-facing cameras");
+ // This is the second time the method is being invoked: our size change is complete
+ } else if (!mGotSecondCallback) {
+ if (mCamera != null) {
+ Log.e(TAG, "Aborting camera open because it hadn't been closed");
+ return;
+ }
+
+ // Open the camera device
+ try {
+ mCameraManager.openCamera(mCameraId, mCameraStateListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to configure output surface", ex);
+ }
+ mGotSecondCallback = true;
+
+ // Control flow continues in mCameraStateListener.onOpened()
+ }
+ }};
+
+ /**
+ * Calledbacks invoked upon state changes in our {@code CameraDevice}. <p>These are run on
+ * {@code mBackgroundThread}.</p>
+ */
+ final CameraDevice.StateListener mCameraStateListener =
+ new CameraDevice.StateListener() {
+ @Override
+ public void onOpened(CameraDevice camera) {
+ Log.i(TAG, "Successfully opened camera");
+ mCamera = camera;
+ try {
+ List<Surface> outputs = Arrays.asList(
+ mSurfaceView.getHolder().getSurface(), mCaptureBuffer.getSurface());
+ camera.createCaptureSession(outputs, mCaptureSessionListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to create a capture session", ex);
+ }
+
+ // Control flow continues in mCaptureSessionListener.onConfigured()
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice camera) {
+ Log.e(TAG, "Camera was disconnected");
+ }
+
+ @Override
+ public void onError(CameraDevice camera, int error) {
+ Log.e(TAG, "State error on device '" + camera.getId() + "': code " + error);
+ }};
+
+ /**
+ * Callbacks invoked upon state changes in our {@code CameraCaptureSession}. <p>These are run on
+ * {@code mBackgroundThread}.</p>
+ */
+ final CameraCaptureSession.StateListener mCaptureSessionListener =
+ new CameraCaptureSession.StateListener() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ Log.i(TAG, "Finished configuring camera outputs");
+ mCaptureSession = session;
+
+ SurfaceHolder holder = mSurfaceView.getHolder();
+ if (holder != null) {
+ try {
+ // Build a request for preview footage
+ CaptureRequest.Builder requestBuilder =
+ mCamera.createCaptureRequest(mCamera.TEMPLATE_PREVIEW);
+ requestBuilder.addTarget(holder.getSurface());
+ CaptureRequest previewRequest = requestBuilder.build();
+
+ // Start displaying preview images
+ try {
+ session.setRepeatingRequest(previewRequest, /*listener*/null,
+ /*handler*/null);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to make repeating preview request", ex);
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to build preview request", ex);
+ }
+ }
+ else {
+ Log.e(TAG, "Holder didn't exist when trying to formulate preview request");
+ }
+ }
+
+ @Override
+ public void onClosed(CameraCaptureSession session) {
+ mCaptureSession = null;
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ Log.e(TAG, "Configuration error on device '" + mCamera.getId());
+ }};
+
+ /**
+ * Callback invoked when we've received a JPEG image from the camera.
+ */
+ final ImageReader.OnImageAvailableListener mImageCaptureListener =
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ // Save the image once we get a chance
+ mBackgroundHandler.post(new CapturedImageSaver(reader.acquireNextImage()));
+
+ // Control flow continues in CapturedImageSaver#run()
+ }};
+
+ /**
+ * Deferred processor responsible for saving snapshots to disk. <p>This is run on
+ * {@code mBackgroundThread}.</p>
+ */
+ static class CapturedImageSaver implements Runnable {
+ /** The image to save. */
+ private Image mCapture;
+
+ public CapturedImageSaver(Image capture) {
+ mCapture = capture;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // Choose an unused filename under the Pictures/ directory
+ File file = File.createTempFile(CAPTURE_FILENAME_PREFIX, ".jpg",
+ Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES));
+ try (FileOutputStream ostream = new FileOutputStream(file)) {
+ Log.i(TAG, "Retrieved image is" +
+ (mCapture.getFormat() == ImageFormat.JPEG ? "" : "n't") + " a JPEG");
+ ByteBuffer buffer = mCapture.getPlanes()[0].getBuffer();
+ Log.i(TAG, "Captured image size: " +
+ mCapture.getWidth() + 'x' + mCapture.getHeight());
+
+ // Write the image out to the chosen file
+ byte[] jpeg = new byte[buffer.remaining()];
+ buffer.get(jpeg);
+ ostream.write(jpeg);
+ } catch (FileNotFoundException ex) {
+ Log.e(TAG, "Unable to open output file for writing", ex);
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to write the image to the output file", ex);
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Unable to create a new output file", ex);
+ } finally {
+ mCapture.close();
+ }
+ }
+ }
+}
diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk
new file mode 100644
index 0000000..0b58243
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraTooTests
+LOCAL_INSTRUMENTATION_FOR := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
new file mode 100644
index 0000000..30210ba
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.camera2.cameratoo.tests">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:label="CameraToo">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.example.android.camera2.cameratoo"
+ android:label="CameraToo tests" />
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
new file mode 100644
index 0000000..3acca5a
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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 com.example.android.camera2.cameratoo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.Image;
+import android.os.Environment;
+import android.util.Size;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.example.android.camera2.cameratoo.CameraTooActivity;
+import org.junit.Test;
+
+public class CameraTooTest {
+ private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) {
+ assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0);
+ assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs),
+ rel.compare(rhs, lhs), 0);
+ }
+
+ private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) {
+ assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0);
+ assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs),
+ rel.compare(rhs, lhs) > 0);
+ }
+
+ @Test
+ public void compareSizesByArea() {
+ Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+ Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+ Size largeSquare = new Size(5, 5);
+ Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea();
+
+ assertComparatorEq(empty, fatAndFlat, rel);
+ assertComparatorEq(empty, tallAndThin, rel);
+ assertComparatorEq(fatAndFlat, empty, rel);
+ assertComparatorEq(fatAndFlat, tallAndThin, rel);
+ assertComparatorEq(tallAndThin, empty, rel);
+ assertComparatorEq(tallAndThin, fatAndFlat, rel);
+
+ assertComparatorEq(smallSquare, horizRect, rel);
+ assertComparatorEq(smallSquare, vertRect, rel);
+ assertComparatorEq(horizRect, smallSquare, rel);
+ assertComparatorEq(horizRect, vertRect, rel);
+ assertComparatorEq(vertRect, smallSquare, rel);
+ assertComparatorEq(vertRect, horizRect, rel);
+
+ assertComparatorLt(empty, smallSquare, rel);
+ assertComparatorLt(empty, horizRect, rel);
+ assertComparatorLt(empty, vertRect, rel);
+
+ assertComparatorLt(fatAndFlat, smallSquare, rel);
+ assertComparatorLt(fatAndFlat, horizRect, rel);
+ assertComparatorLt(fatAndFlat, vertRect, rel);
+
+ assertComparatorLt(tallAndThin, smallSquare, rel);
+ assertComparatorLt(tallAndThin, horizRect, rel);
+ assertComparatorLt(tallAndThin, vertRect, rel);
+
+ assertComparatorLt(empty, largeSquare, rel);
+ assertComparatorLt(fatAndFlat, largeSquare, rel);
+ assertComparatorLt(tallAndThin, largeSquare, rel);
+ assertComparatorLt(smallSquare, largeSquare, rel);
+ assertComparatorLt(horizRect, largeSquare, rel);
+ assertComparatorLt(vertRect, largeSquare, rel);
+ }
+
+ private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) {
+ Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight);
+ assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict),
+ verdict, expected);
+ }
+
+ @Test
+ public void chooseBigEnoughSize() {
+ Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+ Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+ Size largeSquare = new Size(5, 5);
+ Size[] siz =
+ { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare };
+
+ assertOptimalSize(siz, 0, 0, empty);
+
+ assertOptimalSize(siz, 1, 0, fatAndFlat);
+ assertOptimalSize(siz, 0, 1, tallAndThin);
+
+ assertOptimalSize(siz, 4, 4, smallSquare);
+ assertOptimalSize(siz, 1, 1, smallSquare);
+ assertOptimalSize(siz, 2, 1, smallSquare);
+ assertOptimalSize(siz, 1, 2, smallSquare);
+ assertOptimalSize(siz, 3, 4, smallSquare);
+ assertOptimalSize(siz, 4, 3, smallSquare);
+
+ assertOptimalSize(siz, 8, 2, horizRect);
+ assertOptimalSize(siz, 5, 1, horizRect);
+ assertOptimalSize(siz, 5, 2, horizRect);
+
+ assertOptimalSize(siz, 2, 8, vertRect);
+ assertOptimalSize(siz, 1, 5, vertRect);
+ assertOptimalSize(siz, 2, 5, vertRect);
+
+ assertOptimalSize(siz, 5, 5, largeSquare);
+ assertOptimalSize(siz, 3, 5, largeSquare);
+ assertOptimalSize(siz, 5, 3, largeSquare);
+ }
+
+ private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String filename) {
+ return filename.indexOf("cameratoo") == 0 &&
+ filename.indexOf(".jpg") == filename.length() - ".jpg".length();
+ }};
+
+ private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) {
+ Set<T> result = new HashSet<T>(after);
+ result.removeAll(before);
+ return result;
+ }
+
+ @Test
+ public void capturedImageSaver() throws FileNotFoundException, IOException {
+ ByteBuffer buf = ByteBuffer.allocate(25);
+ for(int index = 0; index < buf.capacity(); ++index)
+ buf.put(index, (byte) index);
+
+ Image.Plane plane = mock(Image.Plane.class);
+ when(plane.getBuffer()).thenReturn(buf);
+ when(plane.getPixelStride()).thenReturn(1);
+ when(plane.getRowStride()).thenReturn(5);
+
+ Image.Plane[] onlyPlaneThatMatters = { plane };
+ Image image = mock(Image.class);
+ when(image.getPlanes()).thenReturn(onlyPlaneThatMatters);
+ when(image.getWidth()).thenReturn(5);
+ when(image.getHeight()).thenReturn(5);
+
+ File picturesFolder =
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ Set<File> preListing =
+ new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+
+ CameraTooActivity.CapturedImageSaver saver =
+ new CameraTooActivity.CapturedImageSaver(image);
+ saver.run();
+
+ Set<File> postListing =
+ new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+ Set<File> newFiles = newlyAddedElements(preListing, postListing);
+
+ assertEquals(newFiles.size(), 1);
+
+ File picture = newFiles.iterator().next();
+ FileInputStream istream = new FileInputStream(picture);
+
+ for(int count = 0; count < buf.capacity(); ++count) {
+ assertEquals(istream.read(), buf.get(count));
+ }
+ assertEquals(istream.read(), -1);
+ assertTrue(picture.delete());
+ }
+}
diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk
new file mode 100644
index 0000000..2ab3d02
--- /dev/null
+++ b/tests/VoiceEnrollment/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := VoiceEnrollment
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml
new file mode 100644
index 0000000..6321222
--- /dev/null
+++ b/tests/VoiceEnrollment/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.voiceenrollment">
+
+ <application
+ android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
+ <activity android:name="TestEnrollmentActivity" android:label="Voice Enrollment Application"
+ android:theme="@android:style/Theme.Material.Light.Voice">
+ <intent-filter>
+ <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <meta-data android:name="android.voice_enrollment"
+ android:resource="@xml/enrollment_application"/>
+ </application>
+</manifest>
diff --git a/tests/VoiceEnrollment/res/xml/enrollment_application.xml b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
new file mode 100644
index 0000000..710a0ac
--- /dev/null
+++ b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+
+<voice-enrollment-application xmlns:android="http://schemas.android.com/apk/res/android"
+ android:searchKeyphraseId="101"
+ android:searchKeyphrase="Hello There"
+ android:searchKeyphraseSupportedLocales="en-US,en-GB,fr-FR,de-DE" />
diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
new file mode 100644
index 0000000..7fbd965
--- /dev/null
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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 com.android.test.voiceenrollment;
+
+import android.app.Activity;
+
+public class TestEnrollmentActivity extends Activity {
+ // TODO(sansid): Add a test enrollment flow here.
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index d40b05f..00c2c64 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -21,6 +21,8 @@ import android.os.Bundle;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
+import java.util.Arrays;
+
public class MainInteractionService extends VoiceInteractionService {
static final String TAG = "MainInteractionService";
@@ -28,6 +30,9 @@ public class MainInteractionService extends VoiceInteractionService {
public void onCreate() {
super.onCreate();
Log.i(TAG, "Creating " + this);
+ Log.i(TAG, "Keyphrase enrollment error? " + getKeyphraseEnrollmentInfo().getParseError());
+ Log.i(TAG, "Keyphrase enrollment meta-data: "
+ + Arrays.toString(getKeyphraseEnrollmentInfo().getKeyphrases()));
}
@Override
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 99151c3..8191edd 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -89,6 +89,21 @@ public class ScanResult implements Parcelable {
* {@hide}
*/
public final static int UNSPECIFIED = -1;
+ /**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public boolean is24GHz() {
+ return frequency > 2400 && frequency < 2500;
+ }
+
+ /**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public boolean is5GHz() {
+ return frequency > 4900 && frequency < 5900;
+ }
/** information element from beacon
* @hide
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 192cba6..48396d5 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -405,6 +405,10 @@ public class WifiConfiguration implements Parcelable {
/** @hide **/
public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70;
+ /** @hide
+ * 5GHz band is prefered over 2.4 if the 5GHz RSSI is higher than this threshold **/
+ public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65;
+
/**
* @hide
* A summary of the RSSI and Band status for that configuration
@@ -481,11 +485,11 @@ public class WifiConfiguration implements Parcelable {
if (result.seen == 0)
continue;
- if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ if (result.is5GHz()) {
//strictly speaking: [4915, 5825]
//number of known BSSID on 5GHz band
status.num5 = status.num5 + 1;
- } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ } else if (result.is24GHz()) {
//strictly speaking: [2412, 2482]
//number of known BSSID on 2.4Ghz band
status.num24 = status.num24 + 1;
@@ -493,12 +497,12 @@ public class WifiConfiguration implements Parcelable {
if ((now_ms - result.seen) > age) continue;
- if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ if (result.is5GHz()) {
if (result.level > status.rssi5) {
status.rssi5 = result.level;
status.age5 = result.seen;
}
- } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ } else if (result.is24GHz()) {
if (result.level > status.rssi24) {
status.rssi24 = result.level;
status.age24 = result.seen;
@@ -547,6 +551,17 @@ public class WifiConfiguration implements Parcelable {
*/
public long blackListTimestamp;
+ /**
+ * @hide
+ * last time the system was connected to this configuration.
+ */
+ public long lastConnected;
+
+ /**
+ * @hide
+ * last time the system was disconnected to this configuration.
+ */
+ public long lastDisconnected;
/**
* Set if the configuration was self added by the framework
@@ -658,7 +673,20 @@ public class WifiConfiguration implements Parcelable {
// TODO: Add more checks
return true;
+ }
+ /**
+ * Helper function, identify if a configuration is linked
+ * @hide
+ */
+ public boolean isLinked(WifiConfiguration config) {
+ if (config.linkedConfigurations != null && linkedConfigurations != null) {
+ if (config.linkedConfigurations.get(configKey()) != null
+ && linkedConfigurations.get(config.configKey()) != null) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -688,6 +716,7 @@ public class WifiConfiguration implements Parcelable {
/** @hide **/
public void setAutoJoinStatus(int status) {
+ if (status < 0) status = 0;
if (status == 0) {
blackListTimestamp = 0;
} else if (status > autoJoinStatus) {
@@ -1079,6 +1108,8 @@ public class WifiConfiguration implements Parcelable {
creatorUid = source.creatorUid;
peerWifiConfiguration = source.peerWifiConfiguration;
blackListTimestamp = source.blackListTimestamp;
+ lastConnected = source.lastConnected;
+ lastDisconnected = source.lastDisconnected;
}
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index f6a94d0..6760c56 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -62,6 +62,17 @@ public class WifiInfo implements Parcelable {
private String mBSSID;
private WifiSsid mWifiSsid;
private int mNetworkId;
+
+ /** @hide **/
+ public static final int INVALID_RSSI = -127;
+
+ /** @hide **/
+ public static final int MIN_RSSI = -126;
+
+ /** @hide **/
+ public static final int MAX_RSSI = 200;
+
+
/**
* Received Signal Strength Indicator
*/
@@ -131,7 +142,8 @@ public class WifiInfo implements Parcelable {
public int score;
/**
- * @hide *
+ * TODO: get actual timestamp and calculate true rates
+ * @hide
*/
public void updatePacketRates(WifiLinkLayerStats stats) {
if (stats != null) {
@@ -156,17 +168,42 @@ public class WifiInfo implements Parcelable {
rxSuccess = rxgood;
txRetries = txretries;
} else {
- txBadRate = 0;
+ txBad = 0;
txSuccess = 0;
rxSuccess = 0;
txRetries = 0;
+ txBadRate = 0;
+ txSuccessRate = 0;
+ rxSuccessRate = 0;
+ txRetriesRate = 0;
}
}
+
/**
- * Flag indicating that AP has hinted that upstream connection is metered,
- * and sensitive to heavy data transfers.
+ * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
+ * at the Wifi HAL
+ * @hide
*/
+ public void updatePacketRates(long txPackets, long rxPackets) {
+ //paranoia
+ txBad = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txRetriesRate = 0;
+
+ txSuccessRate = (txSuccessRate * 0.5)
+ + ((double) (txPackets - txSuccess) * 0.5);
+ rxSuccessRate = (rxSuccessRate * 0.5)
+ + ((double) (rxPackets - rxSuccess) * 0.5);
+ txSuccess = txPackets;
+ rxSuccess = rxPackets;
+ }
+
+ /**
+ * Flag indicating that AP has hinted that upstream connection is metered,
+ * and sensitive to heavy data transfers.
+ */
private boolean mMeteredHint;
/** @hide */
@@ -175,9 +212,32 @@ public class WifiInfo implements Parcelable {
mBSSID = null;
mNetworkId = -1;
mSupplicantState = SupplicantState.UNINITIALIZED;
- mRssi = -9999;
+ mRssi = INVALID_RSSI;
mLinkSpeed = -1;
mFrequency = -1;
+ txBad = 0;
+ }
+
+ /** @hide */
+ public void reset() {
+ setInetAddress(null);
+ setBSSID(null);
+ setSSID(null);
+ setNetworkId(-1);
+ setRssi(INVALID_RSSI);
+ setLinkSpeed(-1);
+ setFrequency(-1);
+ setMeteredHint(false);
+ txSuccess = 0;
+ rxSuccess = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txSuccessRate = 0;
+ rxSuccessRate = 0;
+ txRetriesRate = 0;
+ lowRssiCount = 0;
+ badRssiCount = 0;
+ score = 0;
}
/**
@@ -256,7 +316,7 @@ public class WifiInfo implements Parcelable {
/**
* Returns the received signal strength indicator of the current 802.11
* network, in dBm.
- * @return the RSSI, in the range -110 to 10
+ * @return the RSSI, in the range -127 to 200
*/
public int getRssi() {
return mRssi;
@@ -264,6 +324,10 @@ public class WifiInfo implements Parcelable {
/** @hide */
public void setRssi(int rssi) {
+ if (rssi < INVALID_RSSI)
+ rssi = INVALID_RSSI;
+ if (rssi > MAX_RSSI)
+ rssi = MAX_RSSI;
mRssi = rssi;
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 3b65ca8..21b700d 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -153,12 +153,17 @@ public class WifiScanner {
dest.writeInt(band);
dest.writeInt(periodInMs);
dest.writeInt(reportEvents);
- dest.writeInt(channels.length);
- for (int i = 0; i < channels.length; i++) {
- dest.writeInt(channels[i].frequency);
- dest.writeInt(channels[i].dwellTimeMS);
- dest.writeInt(channels[i].passive ? 1 : 0);
+ if (channels != null) {
+ dest.writeInt(channels.length);
+
+ for (int i = 0; i < channels.length; i++) {
+ dest.writeInt(channels[i].frequency);
+ dest.writeInt(channels[i].dwellTimeMS);
+ dest.writeInt(channels[i].passive ? 1 : 0);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -211,10 +216,14 @@ public class WifiScanner {
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mResults.length);
- for (int i = 0; i < mResults.length; i++) {
- ScanResult result = mResults[i];
- result.writeToParcel(dest, flags);
+ if (mResults != null) {
+ dest.writeInt(mResults.length);
+ for (int i = 0; i < mResults.length; i++) {
+ ScanResult result = mResults[i];
+ result.writeToParcel(dest, flags);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -324,13 +333,17 @@ public class WifiScanner {
dest.writeInt(unchangedSampleSize);
dest.writeInt(minApsBreachingThreshold);
dest.writeInt(periodInMs);
- dest.writeInt(hotspotInfos.length);
- for (int i = 0; i < hotspotInfos.length; i++) {
- HotspotInfo info = hotspotInfos[i];
- dest.writeString(info.bssid);
- dest.writeInt(info.low);
- dest.writeInt(info.high);
- dest.writeInt(info.frequencyHint);
+ if (hotspotInfos != null) {
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ dest.writeInt(info.frequencyHint);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -456,13 +469,18 @@ public class WifiScanner {
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(apLostThreshold);
- dest.writeInt(hotspotInfos.length);
- for (int i = 0; i < hotspotInfos.length; i++) {
- HotspotInfo info = hotspotInfos[i];
- dest.writeString(info.bssid);
- dest.writeInt(info.low);
- dest.writeInt(info.high);
- dest.writeInt(info.frequencyHint);
+
+ if (hotspotInfos != null) {
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ dest.writeInt(info.frequencyHint);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -680,6 +698,42 @@ public class WifiScanner {
}
}
+ /** @hide */
+ public static class OperationResult implements Parcelable {
+ public int reason;
+ public String description;
+
+ public OperationResult(int reason, String description) {
+ this.reason = reason;
+ this.description = description;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(reason);
+ dest.writeString(description);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<OperationResult> CREATOR =
+ new Creator<OperationResult>() {
+ public OperationResult createFromParcel(Parcel in) {
+ int reason = in.readInt();
+ String description = in.readString();
+ return new OperationResult(reason, description);
+ }
+
+ public OperationResult[] newArray(int size) {
+ return new OperationResult[size];
+ }
+ };
+ }
+
private static class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
@@ -717,9 +771,11 @@ public class WifiScanner {
case CMD_OP_SUCCEEDED :
((ActionListener) listener).onSuccess();
break;
- case CMD_OP_FAILED :
- ((ActionListener) listener).onFailure(msg.arg1, (String)msg.obj);
- removeListener(msg.arg2);
+ case CMD_OP_FAILED : {
+ OperationResult result = (OperationResult)msg.obj;
+ ((ActionListener) listener).onFailure(result.reason, result.description);
+ removeListener(msg.arg2);
+ }
break;
case CMD_SCAN_RESULT :
((ScanListener) listener).onResults(