summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt49
-rw-r--r--cmds/bootanimation/BootAnimation.cpp103
-rw-r--r--cmds/bootanimation/BootAnimation.h3
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/PendingIntent.java28
-rw-r--r--core/java/android/bluetooth/package.html16
-rw-r--r--core/java/android/content/pm/PackageParser.java30
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java339
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java414
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java605
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java672
-rw-r--r--core/java/android/net/NetworkIdentity.java8
-rw-r--r--core/java/android/net/NetworkPolicy.java8
-rw-r--r--core/java/android/net/NetworkStats.java6
-rw-r--r--core/java/android/net/NetworkTemplate.java13
-rw-r--r--core/java/android/net/http/X509TrustManagerExtensions.java14
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl2
-rw-r--r--core/java/android/nfc/INfcUnlockSettings.aidl70
-rw-r--r--core/java/android/nfc/NfcAdapter.java24
-rw-r--r--core/java/android/nfc/NfcUnlock.java255
-rw-r--r--core/java/android/nfc/Tag.java8
-rw-r--r--core/java/android/os/storage/StorageVolume.java2
-rw-r--r--core/java/android/provider/CallLog.java45
-rw-r--r--core/java/android/provider/ContactsContract.java77
-rw-r--r--core/java/android/provider/Settings.java15
-rw-r--r--core/java/android/view/DisplayAdjustments.java6
-rw-r--r--core/java/android/view/DisplayList.java18
-rw-r--r--core/java/android/view/GLES20DisplayList.java27
-rw-r--r--core/java/android/view/View.java43
-rw-r--r--core/java/android/view/ViewOverlay.java5
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java27
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfoCache.java12
-rw-r--r--core/java/android/view/accessibility/CaptioningManager.java28
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java6
-rw-r--r--core/java/com/android/internal/util/Objects.java62
-rw-r--r--core/jni/Android.mk4
-rw-r--r--core/jni/android_net_wifi_WifiNative.cpp2
-rw-r--r--core/jni/android_util_Binder.cpp15
-rw-r--r--core/jni/android_view_GLES20DisplayList.cpp13
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp32
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp2
-rw-r--r--core/res/AndroidManifest.xml11
-rw-r--r--docs/html/google/play/billing/v2/api.jd15
-rw-r--r--docs/html/guide/components/intents-common.jd1312
-rw-r--r--docs/html/guide/components/intents-filters.jd1640
-rw-r--r--docs/html/guide/components/services.jd54
-rw-r--r--docs/html/guide/guide_toc.cs13
-rw-r--r--docs/html/guide/topics/manifest/category-element.jd8
-rw-r--r--docs/html/guide/topics/manifest/data-element.jd147
-rw-r--r--docs/html/guide/topics/providers/document-provider.jd2
-rw-r--r--docs/html/images/components/intent-filters@2x.pngbin0 -> 43968 bytes
-rw-r--r--docs/html/training/basics/intents/filters.jd4
-rw-r--r--docs/html/training/basics/intents/sending.jd8
-rw-r--r--docs/html/training/sharing/send.jd14
-rw-r--r--docs/html/training/system-ui/navigation.jd3
-rw-r--r--libs/hwui/AmbientShadow.cpp306
-rw-r--r--libs/hwui/AmbientShadow.h57
-rw-r--r--libs/hwui/Android.mk2
-rw-r--r--libs/hwui/Caches.cpp4
-rw-r--r--libs/hwui/Caches.h8
-rw-r--r--libs/hwui/Debug.h6
-rw-r--r--libs/hwui/DeferredDisplayList.h4
-rw-r--r--libs/hwui/DisplayList.cpp264
-rw-r--r--libs/hwui/DisplayList.h131
-rw-r--r--libs/hwui/DisplayListOp.h66
-rw-r--r--libs/hwui/DisplayListRenderer.cpp9
-rw-r--r--libs/hwui/DisplayListRenderer.h1
-rw-r--r--libs/hwui/FontRenderer.cpp4
-rw-r--r--libs/hwui/Layer.cpp9
-rw-r--r--libs/hwui/Matrix.cpp95
-rw-r--r--libs/hwui/Matrix.h14
-rw-r--r--libs/hwui/OpenGLRenderer.cpp62
-rw-r--r--libs/hwui/OpenGLRenderer.h13
-rw-r--r--libs/hwui/PathTessellator.h75
-rw-r--r--libs/hwui/ShadowTessellator.cpp73
-rw-r--r--libs/hwui/ShadowTessellator.h37
-rw-r--r--libs/hwui/Vector.h15
-rw-r--r--libs/hwui/VertexBuffer.h102
-rw-r--r--media/java/android/media/MediaRouter.java7
-rw-r--r--media/java/android/media/WebVttRenderer.java4
-rw-r--r--media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java8
-rw-r--r--opengl/java/android/opengl/EGLLogWrapper.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java4
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java7
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java28
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java6
-rw-r--r--preloaded-classes2
-rw-r--r--services/java/Android.mk14
-rw-r--r--services/java/com/android/server/AlarmManagerService.java575
-rw-r--r--services/java/com/android/server/BatteryService.java33
-rw-r--r--services/java/com/android/server/BootReceiver.java7
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java2
-rw-r--r--services/java/com/android/server/LocalServices.java58
-rw-r--r--services/java/com/android/server/SystemServer.java98
-rw-r--r--services/java/com/android/server/SystemService.java151
-rw-r--r--services/java/com/android/server/SystemServiceManager.java141
-rw-r--r--services/java/com/android/server/UiModeManagerService.java286
-rw-r--r--services/java/com/android/server/Watchdog.java10
-rw-r--r--services/java/com/android/server/am/ActivityStack.java19
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java9
-rw-r--r--services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java329
-rw-r--r--services/java/com/android/server/lights/Light.java41
-rw-r--r--services/java/com/android/server/lights/LightsManager.java31
-rw-r--r--services/java/com/android/server/lights/LightsService.java (renamed from services/java/com/android/server/LightsService.java)94
-rw-r--r--services/java/com/android/server/media/MediaRouterService.java8
-rw-r--r--services/java/com/android/server/media/RemoteDisplayProviderProxy.java7
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java6
-rw-r--r--services/java/com/android/server/net/NetworkStatsCollection.java6
-rw-r--r--services/java/com/android/server/notification/NotificationDelegate.java27
-rw-r--r--services/java/com/android/server/notification/NotificationManagerInternal.java8
-rw-r--r--services/java/com/android/server/notification/NotificationManagerService.java (renamed from services/java/com/android/server/NotificationManagerService.java)1231
-rwxr-xr-xservices/java/com/android/server/pm/PackageManagerService.java55
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java18
-rw-r--r--services/java/com/android/server/power/DisplayPowerState.java6
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java29
-rw-r--r--services/java/com/android/server/statusbar/StatusBarManagerInternal.java29
-rw-r--r--services/java/com/android/server/statusbar/StatusBarManagerService.java (renamed from services/java/com/android/server/StatusBarManagerService.java)236
-rw-r--r--services/java/com/android/server/storage/DeviceStorageMonitorInternal.java24
-rw-r--r--services/java/com/android/server/storage/DeviceStorageMonitorService.java (renamed from services/java/com/android/server/DeviceStorageMonitorService.java)226
-rw-r--r--services/java/com/android/server/twilight/TwilightListener.java21
-rw-r--r--services/java/com/android/server/twilight/TwilightManager.java24
-rw-r--r--services/java/com/android/server/twilight/TwilightService.java (renamed from services/java/com/android/server/TwilightService.java)249
-rw-r--r--services/java/com/android/server/twilight/TwilightState.java112
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java8
-rw-r--r--services/java/com/android/server/wifi/NetworkUpdateResult.java (renamed from wifi/java/android/net/wifi/NetworkUpdateResult.java)2
-rw-r--r--services/java/com/android/server/wifi/StateChangeResult.java (renamed from wifi/java/android/net/wifi/StateChangeResult.java)5
-rw-r--r--services/java/com/android/server/wifi/SupplicantStateTracker.java (renamed from wifi/java/android/net/wifi/SupplicantStateTracker.java)6
-rw-r--r--services/java/com/android/server/wifi/WifiApConfigStore.java (renamed from wifi/java/android/net/wifi/WifiApConfigStore.java)3
-rw-r--r--services/java/com/android/server/wifi/WifiConfigStore.java (renamed from wifi/java/android/net/wifi/WifiConfigStore.java)93
-rw-r--r--services/java/com/android/server/wifi/WifiController.java1
-rw-r--r--services/java/com/android/server/wifi/WifiMonitor.java (renamed from wifi/java/android/net/wifi/WifiMonitor.java)8
-rw-r--r--services/java/com/android/server/wifi/WifiNative.java (renamed from wifi/java/android/net/wifi/WifiNative.java)4
-rw-r--r--services/java/com/android/server/wifi/WifiNotificationController.java1
-rw-r--r--services/java/com/android/server/wifi/WifiService.java2
-rw-r--r--services/java/com/android/server/wifi/WifiStateMachine.java (renamed from wifi/java/android/net/wifi/WifiStateMachine.java)15
-rw-r--r--services/java/com/android/server/wifi/WifiWatchdogStateMachine.java (renamed from wifi/java/android/net/wifi/WifiWatchdogStateMachine.java)9
-rw-r--r--services/java/com/android/server/wifi/p2p/WifiP2pService.java (renamed from wifi/java/android/net/wifi/p2p/WifiP2pService.java)18
-rw-r--r--services/jni/Android.mk2
-rw-r--r--services/jni/com_android_server_lights_LightsService.cpp (renamed from services/jni/com_android_server_LightsService.cpp)2
-rw-r--r--wifi/java/android/net/wifi/SupplicantState.java6
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java2
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java134
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java27
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java3
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pConfig.java3
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pDevice.java4
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java6
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java27
150 files changed, 7616 insertions, 4770 deletions
diff --git a/Android.mk b/Android.mk
index 8fcac91..9b0ac27 100644
--- a/Android.mk
+++ b/Android.mk
@@ -152,6 +152,7 @@ LOCAL_SRC_FILES += \
core/java/android/nfc/INfcAdapterExtras.aidl \
core/java/android/nfc/INfcTag.aidl \
core/java/android/nfc/INfcCardEmulation.aidl \
+ core/java/android/nfc/INfcUnlockSettings.aidl \
core/java/android/os/IBatteryPropertiesListener.aidl \
core/java/android/os/IBatteryPropertiesRegistrar.aidl \
core/java/android/os/ICancellationSignal.aidl \
diff --git a/api/current.txt b/api/current.txt
index 203a8e9..80ad550 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14691,6 +14691,7 @@ package android.net.http {
public class X509TrustManagerExtensions {
ctor public X509TrustManagerExtensions(javax.net.ssl.X509TrustManager) throws java.lang.IllegalArgumentException;
method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.lang.String) throws java.security.cert.CertificateException;
+ method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
}
}
@@ -15542,6 +15543,11 @@ package android.nfc {
method public android.nfc.NfcAdapter getDefaultAdapter();
}
+ public class NfcUnlock {
+ method public static synchronized android.nfc.NfcUnlock getInstance(android.nfc.NfcAdapter);
+ method public boolean getNfcUnlockEnabled();
+ }
+
public final class Tag implements android.os.Parcelable {
method public int describeContents();
method public byte[] getId();
@@ -20068,16 +20074,24 @@ package android.provider {
public static class CallLog.Calls implements android.provider.BaseColumns {
ctor public CallLog.Calls();
method public static java.lang.String getLastOutgoingCall(android.content.Context);
+ field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
+ field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
+ field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
field public static final java.lang.String CACHED_NAME = "name";
+ field public static final java.lang.String CACHED_NORMALIZED_NUMBER = "normalized_number";
field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
+ field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
field public static final android.net.Uri CONTENT_URI;
+ field public static final android.net.Uri CONTENT_URI_WITH_VOICEMAIL;
+ field public static final java.lang.String COUNTRY_ISO = "countryiso";
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
field public static final java.lang.String DURATION = "duration";
+ field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
@@ -20092,6 +20106,8 @@ package android.provider {
field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
field public static final java.lang.String TYPE = "type";
+ field public static final int VOICEMAIL_TYPE = 4; // 0x4
+ field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
}
public deprecated class Contacts {
@@ -20398,6 +20414,8 @@ package android.provider {
field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
field public static final java.lang.String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
field public static final java.lang.String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
+ field public static final java.lang.String REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries";
+ field public static final java.lang.String STREQUENT_PHONE_ONLY = "strequent_phone_only";
}
public static final class ContactsContract.AggregationExceptions implements android.provider.BaseColumns {
@@ -20426,6 +20444,12 @@ package android.provider {
field public static final int TYPE_CUSTOM = 0; // 0x0
}
+ public static final class ContactsContract.CommonDataKinds.Callable implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
+ ctor public ContactsContract.CommonDataKinds.Callable();
+ field public static final android.net.Uri CONTENT_FILTER_URI;
+ field public static final android.net.Uri CONTENT_URI;
+ }
+
protected static abstract interface ContactsContract.CommonDataKinds.CommonColumns implements android.provider.ContactsContract.CommonDataKinds.BaseTypes {
field public static final java.lang.String DATA = "data1";
field public static final java.lang.String LABEL = "data3";
@@ -20604,6 +20628,7 @@ package android.provider {
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
field public static final java.lang.String DISPLAY_NAME = "data1";
field public static final java.lang.String FAMILY_NAME = "data3";
+ field public static final java.lang.String FULL_NAME_STYLE = "data10";
field public static final java.lang.String GIVEN_NAME = "data2";
field public static final java.lang.String MIDDLE_NAME = "data5";
field public static final java.lang.String PHONETIC_FAMILY_NAME = "data9";
@@ -20657,6 +20682,7 @@ package android.provider {
protected static abstract interface ContactsContract.ContactOptionsColumns {
field public static final java.lang.String CUSTOM_RINGTONE = "custom_ringtone";
field public static final java.lang.String LAST_TIME_CONTACTED = "last_time_contacted";
+ field public static final java.lang.String PINNED = "pinned";
field public static final java.lang.String SEND_TO_VOICEMAIL = "send_to_voicemail";
field public static final java.lang.String STARRED = "starred";
field public static final java.lang.String TIMES_CONTACTED = "times_contacted";
@@ -20683,6 +20709,7 @@ package android.provider {
field public static final android.net.Uri CONTENT_GROUP_URI;
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
field public static final android.net.Uri CONTENT_LOOKUP_URI;
+ field public static final android.net.Uri CONTENT_MULTI_VCARD_URI;
field public static final android.net.Uri CONTENT_STREQUENT_FILTER_URI;
field public static final android.net.Uri CONTENT_STREQUENT_URI;
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
@@ -20915,6 +20942,7 @@ package android.provider {
public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
field public static final android.net.Uri CONTENT_FILTER_URI;
+ field public static final java.lang.String QUERY_PARAMETER_SIP_ADDRESS = "sip";
}
protected static abstract interface ContactsContract.PhoneLookupColumns {
@@ -20931,6 +20959,25 @@ package android.provider {
field public static final int UNDEFINED = 0; // 0x0
}
+ public static final class ContactsContract.PinnedPositions {
+ ctor public ContactsContract.PinnedPositions();
+ field public static final int DEMOTED = -1; // 0xffffffff
+ field public static final java.lang.String STAR_WHEN_PINNING = "star_when_pinning";
+ field public static final java.lang.String UNDEMOTE = "undemote";
+ field public static final int UNPINNED = 2147483647; // 0x7fffffff
+ field public static final android.net.Uri UPDATE_URI;
+ }
+
+ public static final class ContactsContract.Preferences {
+ ctor public ContactsContract.Preferences();
+ field public static final java.lang.String DISPLAY_ORDER = "android.contacts.DISPLAY_ORDER";
+ field public static final int DISPLAY_ORDER_ALTERNATIVE = 2; // 0x2
+ field public static final int DISPLAY_ORDER_PRIMARY = 1; // 0x1
+ field public static final java.lang.String SORT_ORDER = "android.contacts.SORT_ORDER";
+ field public static final int SORT_ORDER_ALTERNATIVE = 2; // 0x2
+ field public static final int SORT_ORDER_PRIMARY = 1; // 0x1
+ }
+
public static final deprecated class ContactsContract.Presence extends android.provider.ContactsContract.StatusUpdates {
ctor public ContactsContract.Presence();
}
@@ -21698,6 +21745,7 @@ package android.provider {
field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
field public static final deprecated java.lang.String NETWORK_PREFERENCE = "network_preference";
+ field public static final java.lang.String NFC_UNLOCK_ENABLED = "nfc_unlock_enabled";
field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
field public static final java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
@@ -29918,6 +29966,7 @@ package android.view.accessibility {
field public final int edgeColor;
field public final int edgeType;
field public final int foregroundColor;
+ field public final int windowColor;
}
public static abstract class CaptioningManager.CaptioningChangeListener {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8c2931f..125bea6 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -52,7 +52,6 @@
#include "BootAnimation.h"
-#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
#define EXIT_PROP_NAME "service.bootanim.exit"
@@ -63,14 +62,19 @@ extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
namespace android {
+static const int ANIM_ENTRY_NAME_MAX = 256;
+
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation() : Thread(false)
+BootAnimation::BootAnimation() : Thread(false), mZip(NULL)
{
mSession = new SurfaceComposerClient();
}
BootAnimation::~BootAnimation() {
+ if (mZip != NULL) {
+ delete mZip;
+ }
}
void BootAnimation::onFirstRef() {
@@ -86,7 +90,7 @@ sp<SurfaceComposerClient> BootAnimation::session() const {
}
-void BootAnimation::binderDied(const wp<IBinder>& who)
+void BootAnimation::binderDied(const wp<IBinder>&)
{
// woah, surfaceflinger died!
ALOGD("SurfaceFlinger died, exiting...");
@@ -268,8 +272,6 @@ status_t BootAnimation::readyToRun() {
mFlingerSurfaceControl = control;
mFlingerSurface = s;
- mAndroidAnimation = true;
-
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
char decrypt[PROPERTY_VALUE_MAX];
@@ -277,16 +279,14 @@ status_t BootAnimation::readyToRun() {
bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
+ ZipFileRO* zipFile = NULL;
if ((encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
-
- ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
+ ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
- mAndroidAnimation = false;
+ ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
+ mZip = zipFile;
}
return NO_ERROR;
@@ -295,15 +295,14 @@ status_t BootAnimation::readyToRun() {
bool BootAnimation::threadLoop()
{
bool r;
- if (mAndroidAnimation) {
+ // We have no bootanimation file, so we use the stock android logo
+ // animation.
+ if (mZip == NULL) {
r = android();
} else {
r = movie();
}
- // No need to force exit anymore
- property_set(EXIT_PROP_NAME, "0");
-
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
@@ -392,11 +391,14 @@ void BootAnimation::checkExit() {
bool BootAnimation::movie()
{
- ZipFileRO& zip(mZip);
+ ZipEntryRO desc = mZip->findEntryByName("desc.txt");
+ ALOGE_IF(!desc, "couldn't find desc.txt");
+ if (!desc) {
+ return false;
+ }
- size_t numEntries = zip.getNumEntries();
- ZipEntryRO desc = zip.findEntryByName("desc.txt");
- FileMap* descMap = zip.createEntryFileMap(desc);
+ FileMap* descMap = mZip->createEntryFileMap(desc);
+ mZip->releaseEntry(desc);
ALOGE_IF(!descMap, "descMap is null");
if (!descMap) {
return false;
@@ -415,7 +417,7 @@ bool BootAnimation::movie()
String8 line(s, endl - s);
const char* l = line.string();
int fps, width, height, count, pause;
- char path[256];
+ char path[ANIM_ENTRY_NAME_MAX];
char pathType;
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
//LOGD("> w=%d, h=%d, fps=%d", width, height, fps);
@@ -438,28 +440,37 @@ bool BootAnimation::movie()
// read all the data structures
const size_t pcount = animation.parts.size();
- for (size_t i=0 ; i<numEntries ; i++) {
- char name[256];
- ZipEntryRO entry = zip.findEntryByIndex(i);
- if (zip.getEntryFileName(entry, name, 256) == 0) {
- const String8 entryName(name);
- const String8 path(entryName.getPathDir());
- const String8 leaf(entryName.getPathLeaf());
- if (leaf.size() > 0) {
- for (int j=0 ; j<pcount ; j++) {
- if (path == animation.parts[j].path) {
- int method;
- // supports only stored png files
- if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
- if (method == ZipFileRO::kCompressStored) {
- FileMap* map = zip.createEntryFileMap(entry);
- if (map) {
- Animation::Frame frame;
- frame.name = leaf;
- frame.map = map;
- Animation::Part& part(animation.parts.editItemAt(j));
- part.frames.add(frame);
- }
+ void *cookie = NULL;
+ if (!mZip->startIteration(&cookie)) {
+ return false;
+ }
+
+ ZipEntryRO entry;
+ char name[ANIM_ENTRY_NAME_MAX];
+ while ((entry = mZip->nextEntry(cookie)) != NULL) {
+ const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
+ if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
+ ALOGE("Error fetching entry file name");
+ continue;
+ }
+
+ const String8 entryName(name);
+ const String8 path(entryName.getPathDir());
+ const String8 leaf(entryName.getPathLeaf());
+ if (leaf.size() > 0) {
+ for (size_t j=0 ; j<pcount ; j++) {
+ if (path == animation.parts[j].path) {
+ int method;
+ // supports only stored png files
+ if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
+ if (method == ZipFileRO::kCompressStored) {
+ FileMap* map = mZip->createEntryFileMap(entry);
+ if (map) {
+ Animation::Frame frame;
+ frame.name = leaf;
+ frame.map = map;
+ Animation::Part& part(animation.parts.editItemAt(j));
+ part.frames.add(frame);
}
}
}
@@ -468,6 +479,8 @@ bool BootAnimation::movie()
}
}
+ mZip->endIteration(cookie);
+
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
@@ -494,7 +507,7 @@ bool BootAnimation::movie()
Region clearReg(Rect(mWidth, mHeight));
clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
- for (int i=0 ; i<pcount ; i++) {
+ for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
glBindTexture(GL_TEXTURE_2D, 0);
@@ -504,7 +517,7 @@ bool BootAnimation::movie()
if(exitPending() && !part.playUntilComplete)
break;
- for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
+ for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
@@ -564,7 +577,7 @@ bool BootAnimation::movie()
// free the textures for this part
if (part.count != 1) {
- for (int j=0 ; j<fcount ; j++) {
+ for (size_t j=0 ; j<fcount ; j++) {
const Animation::Frame& frame(part.frames[j]);
glDeleteTextures(1, &frame.tid);
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index fa908eb..22963c2 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -95,8 +95,7 @@ private:
EGLDisplay mSurface;
sp<SurfaceControl> mFlingerSurfaceControl;
sp<Surface> mFlingerSurface;
- bool mAndroidAnimation;
- ZipFileRO mZip;
+ ZipFileRO *mZip;
};
// ---------------------------------------------------------------------------
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d7a67f4..40899c0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -97,7 +97,6 @@ import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.Objects;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.google.android.collect.Lists;
@@ -113,6 +112,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.TimeZone;
import java.util.regex.Pattern;
@@ -226,7 +226,7 @@ public final class ActivityThread {
public boolean equals(Object o) {
if (o instanceof ProviderKey) {
final ProviderKey other = (ProviderKey) o;
- return Objects.equal(authority, other.authority) && userId == other.userId;
+ return Objects.equals(authority, other.authority) && userId == other.userId;
}
return false;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 29885e7..d3b0763 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -113,23 +113,25 @@ public final class PendingIntent implements Parcelable {
public @interface Flags {}
/**
- * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
- * {@link #getService}: this
- * PendingIntent can only be used once. If set, after
+ * Flag indicating that this PendingIntent can be used only once.
+ * For use with {@link #getActivity}, {@link #getBroadcast}, and
+ * {@link #getService}. <p>If set, after
* {@link #send()} is called on it, it will be automatically
* canceled for you and any future attempt to send through it will fail.
*/
public static final int FLAG_ONE_SHOT = 1<<30;
/**
- * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
- * {@link #getService}: if the described PendingIntent already exists,
- * then simply return null instead of creating it.
+ * Flag indicating that if the described PendingIntent already
+ * exists, then simply return null instead of creating it.
+ * For use with {@link #getActivity}, {@link #getBroadcast}, and
+ * {@link #getService}.
*/
public static final int FLAG_NO_CREATE = 1<<29;
/**
- * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
- * {@link #getService}: if the described PendingIntent already exists,
- * the current one is canceled before generating a new one. You can use
+ * Flag indicating that if the described PendingIntent already exists,
+ * the current one should be canceled before generating a new one.
+ * For use with {@link #getActivity}, {@link #getBroadcast}, and
+ * {@link #getService}. <p>You can use
* this to retrieve a new PendingIntent when you are only changing the
* extra data in the Intent; by canceling the previous pending intent,
* this ensures that only entities given the new data will be able to
@@ -138,10 +140,10 @@ public final class PendingIntent implements Parcelable {
*/
public static final int FLAG_CANCEL_CURRENT = 1<<28;
/**
- * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and
- * {@link #getService}: if the described PendingIntent already exists,
- * then keep it but its replace its extra data with what is in this new
- * Intent. This can be used if you are creating intents where only the
+ * Flag indicating that if the described PendingIntent already exists,
+ * then keep it but replace its extra data with what is in this new
+ * Intent. For use with {@link #getActivity}, {@link #getBroadcast}, and
+ * {@link #getService}. <p>This can be used if you are creating intents where only the
* extras change, and don't care that any entities that received your
* previous PendingIntent will be able to launch it with your new
* extras even if they are not explicitly given to it.
diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html
index 200a21b..d9ca4f1 100644
--- a/core/java/android/bluetooth/package.html
+++ b/core/java/android/bluetooth/package.html
@@ -8,17 +8,19 @@ The Bluetooth API supports both "Classic Bluetooth" and Bluetooth Low Energy.</p
<a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> guide.
For more information about Bluetooth Low Energy, see the
<a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">
-Bluetooth Low Energy</a> guide.</p>
+Bluetooth Low Energy</a> (BLE) guide.</p>
{@more}
<p>The Bluetooth APIs let applications:</p>
<ul>
- <li>Scan for other Bluetooth devices (including Bluetooth Low Energy
- devices)</li>
- <li>Query the local Bluetooth adapter for paired Bluetooth devices</li>
- <li>Establish RFCOMM channels/sockets</li>
- <li>Connect to specified sockets on other devices</li>
- <li>Transfer data to and from other devices</li>
+ <li>Scan for other Bluetooth devices (including BLE devices).</li>
+ <li>Query the local Bluetooth adapter for paired Bluetooth devices.</li>
+ <li>Establish RFCOMM channels/sockets.</li>
+ <li>Connect to specified sockets on other devices.</li>
+ <li>Transfer data to and from other devices.</li>
+ <li>Communicate with BLE devices, such as proximity sensors, heart rate
+ monitors, fitness devices, and so on.</li>
+ <li>Act as a GATT client or a GATT server (BLE).</li>
</ul>
<p>
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e6da288..4607902 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -58,7 +58,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import java.util.jar.StrictJarFile;
import java.util.zip.ZipEntry;
import com.android.internal.util.XmlUtils;
@@ -456,7 +456,7 @@ public class PackageParser {
return pi;
}
- private Certificate[] loadCertificates(JarFile jarFile, JarEntry je,
+ private Certificate[] loadCertificates(StrictJarFile jarFile, ZipEntry je,
byte[] readBuffer) {
try {
// We must read the stream for the JarEntry to retrieve
@@ -466,13 +466,11 @@ public class PackageParser {
// not using
}
is.close();
- return je != null ? je.getCertificates() : null;
+ return je != null ? jarFile.getCertificates(je) : null;
} catch (IOException e) {
- Slog.w(TAG, "Exception reading " + je.getName() + " in "
- + jarFile.getName(), e);
+ Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e);
} catch (RuntimeException e) {
- Slog.w(TAG, "Exception reading " + je.getName() + " in "
- + jarFile.getName(), e);
+ Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e);
}
return null;
}
@@ -591,9 +589,9 @@ public class PackageParser {
*/
public boolean collectManifestDigest(Package pkg) {
try {
- final JarFile jarFile = new JarFile(mArchiveSourcePath);
+ final StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath);
try {
- final ZipEntry je = jarFile.getEntry(ANDROID_MANIFEST_FILENAME);
+ final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
if (je != null) {
pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
}
@@ -624,7 +622,7 @@ public class PackageParser {
}
try {
- JarFile jarFile = new JarFile(mArchiveSourcePath);
+ StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath);
Certificate[] certs = null;
@@ -633,7 +631,7 @@ public class PackageParser {
// can trust it... we'll just use the AndroidManifest.xml
// to retrieve its signatures, not validating all of the
// files.
- JarEntry jarEntry = jarFile.getJarEntry(ANDROID_MANIFEST_FILENAME);
+ ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
certs = loadCertificates(jarFile, jarEntry, readBuffer);
if (certs == null) {
Slog.e(TAG, "Package " + pkg.packageName
@@ -656,9 +654,9 @@ public class PackageParser {
}
}
} else {
- Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- final JarEntry je = entries.nextElement();
+ Iterator<ZipEntry> entries = jarFile.iterator();
+ while (entries.hasNext()) {
+ final ZipEntry je = entries.next();
if (je.isDirectory()) continue;
final String name = je.getName();
@@ -744,6 +742,10 @@ public class PackageParser {
Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
return false;
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
+ return false;
} catch (RuntimeException e) {
Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e);
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a38beec..5f9c8c2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -127,74 +127,58 @@ public final class CameraCharacteristics extends CameraMetadata {
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
/**
- * <p>
- * Which set of antibanding modes are
- * supported
- * </p>
+ * <p>Which set of antibanding modes are
+ * supported</p>
*/
public static final Key<byte[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES =
new Key<byte[]>("android.control.aeAvailableAntibandingModes", byte[].class);
/**
- * <p>
- * List of frame rate ranges supported by the
- * AE algorithm/hardware
- * </p>
+ * <p>List of frame rate ranges supported by the
+ * AE algorithm/hardware</p>
*/
public static final Key<int[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =
new Key<int[]>("android.control.aeAvailableTargetFpsRanges", int[].class);
/**
- * <p>
- * Maximum and minimum exposure compensation
+ * <p>Maximum and minimum exposure compensation
* setting, in counts of
- * android.control.aeCompensationStepSize
- * </p>
+ * android.control.aeCompensationStepSize</p>
*/
public static final Key<int[]> CONTROL_AE_COMPENSATION_RANGE =
new Key<int[]>("android.control.aeCompensationRange", int[].class);
/**
- * <p>
- * Smallest step by which exposure compensation
- * can be changed
- * </p>
+ * <p>Smallest step by which exposure compensation
+ * can be changed</p>
*/
public static final Key<Rational> CONTROL_AE_COMPENSATION_STEP =
new Key<Rational>("android.control.aeCompensationStep", Rational.class);
/**
- * <p>
- * List of AF modes that can be
- * selected
- * </p>
+ * <p>List of AF modes that can be
+ * selected</p>
*/
public static final Key<byte[]> CONTROL_AF_AVAILABLE_MODES =
new Key<byte[]>("android.control.afAvailableModes", byte[].class);
/**
- * <p>
- * what subset of the full color effect enum
- * list is supported
- * </p>
+ * <p>what subset of the full color effect enum
+ * list is supported</p>
*/
public static final Key<byte[]> CONTROL_AVAILABLE_EFFECTS =
new Key<byte[]>("android.control.availableEffects", byte[].class);
/**
- * <p>
- * what subset of the scene mode enum list is
- * supported.
- * </p>
+ * <p>what subset of the scene mode enum list is
+ * supported.</p>
*/
public static final Key<byte[]> CONTROL_AVAILABLE_SCENE_MODES =
new Key<byte[]>("android.control.availableSceneModes", byte[].class);
/**
- * <p>
- * List of video stabilization modes that can
- * be supported
- * </p>
+ * <p>List of video stabilization modes that can
+ * be supported</p>
*/
public static final Key<byte[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES =
new Key<byte[]>("android.control.availableVideoStabilizationModes", byte[].class);
@@ -205,127 +189,93 @@ public final class CameraCharacteristics extends CameraMetadata {
new Key<byte[]>("android.control.awbAvailableModes", byte[].class);
/**
- * <p>
- * For AE, AWB, and AF, how many individual
- * regions can be listed for metering?
- * </p>
+ * <p>For AE, AWB, and AF, how many individual
+ * regions can be listed for metering?</p>
*/
public static final Key<Integer> CONTROL_MAX_REGIONS =
new Key<Integer>("android.control.maxRegions", int.class);
/**
- * <p>
- * Whether this camera has a
- * flash
- * </p>
- * <p>
- * If no flash, none of the flash controls do
- * anything. All other metadata should return 0
- * </p>
+ * <p>Whether this camera has a
+ * flash</p>
+ * <p>If no flash, none of the flash controls do
+ * anything. All other metadata should return 0</p>
*/
public static final Key<Byte> FLASH_INFO_AVAILABLE =
new Key<Byte>("android.flash.info.available", byte.class);
/**
- * <p>
- * Supported resolutions for the JPEG
- * thumbnail
- * </p>
+ * <p>Supported resolutions for the JPEG
+ * thumbnail</p>
*/
public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
/**
- * <p>
- * List of supported aperture
- * values
- * </p>
- * <p>
- * If variable aperture not available, only setting
- * should be for the fixed aperture
- * </p>
+ * <p>List of supported aperture
+ * values</p>
+ * <p>If variable aperture not available, only setting
+ * should be for the fixed aperture</p>
*/
public static final Key<float[]> LENS_INFO_AVAILABLE_APERTURES =
new Key<float[]>("android.lens.info.availableApertures", float[].class);
/**
- * <p>
- * List of supported ND filter
- * values
- * </p>
- * <p>
- * If not available, only setting is 0. Otherwise,
+ * <p>List of supported ND filter
+ * values</p>
+ * <p>If not available, only setting is 0. Otherwise,
* lists the available exposure index values for dimming
* (2 would mean the filter is set to reduce incoming
- * light by two stops)
- * </p>
+ * light by two stops)</p>
*/
public static final Key<float[]> LENS_INFO_AVAILABLE_FILTER_DENSITIES =
new Key<float[]>("android.lens.info.availableFilterDensities", float[].class);
/**
- * <p>
- * If fitted with optical zoom, what focal
+ * <p>If fitted with optical zoom, what focal
* lengths are available. If not, the static focal
- * length
- * </p>
- * <p>
- * If optical zoom not supported, only one value
- * should be reported
- * </p>
+ * length</p>
+ * <p>If optical zoom not supported, only one value
+ * should be reported</p>
*/
public static final Key<float[]> LENS_INFO_AVAILABLE_FOCAL_LENGTHS =
new Key<float[]>("android.lens.info.availableFocalLengths", float[].class);
/**
- * <p>
- * List of supported optical image
- * stabilization modes
- * </p>
+ * <p>List of supported optical image
+ * stabilization modes</p>
*/
public static final Key<byte[]> LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION =
new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class);
/**
- * <p>
- * Hyperfocal distance for this lens; set to
- * 0 if fixed focus
- * </p>
- * <p>
- * The hyperfocal distance is used for the old
- * API's 'fixed' setting
- * </p>
+ * <p>Hyperfocal distance for this lens; set to
+ * 0 if fixed focus</p>
+ * <p>The hyperfocal distance is used for the old
+ * API's 'fixed' setting</p>
*/
public static final Key<Float> LENS_INFO_HYPERFOCAL_DISTANCE =
new Key<Float>("android.lens.info.hyperfocalDistance", float.class);
/**
- * <p>
- * Shortest distance from frontmost surface
- * of the lens that can be focused correctly
- * </p>
- * <p>
- * If the lens is fixed-focus, this should be
- * 0
- * </p>
+ * <p>Shortest distance from frontmost surface
+ * of the lens that can be focused correctly</p>
+ * <p>If the lens is fixed-focus, this should be
+ * 0</p>
*/
public static final Key<Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE =
new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
/**
- * <p>
- * Dimensions of lens shading
- * map
- * </p>
+ * <p>Dimensions of lens shading
+ * map</p>
*/
public static final Key<android.hardware.camera2.Size> LENS_INFO_SHADING_MAP_SIZE =
new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
/**
- * <p>
- * Direction the camera faces relative to
- * device screen
- * </p>
+ * <p>Direction the camera faces relative to
+ * device screen</p>
* @see #LENS_FACING_FRONT
* @see #LENS_FACING_BACK
*/
@@ -333,18 +283,14 @@ public final class CameraCharacteristics extends CameraMetadata {
new Key<Integer>("android.lens.facing", int.class);
/**
- * <p>
- * If set to 1, the HAL will always split result
+ * <p>If set to 1, the HAL will always split result
* metadata for a single capture into multiple buffers,
- * returned using multiple process_capture_result calls.
- * </p>
- * <p>
- * Does not need to be listed in static
+ * returned using multiple process_capture_result calls.</p>
+ * <p>Does not need to be listed in static
* metadata. Support for partial results will be reworked in
* future versions of camera service. This quirk will stop
* working at that point; DO NOT USE without careful
- * consideration of future support.
- * </p>
+ * consideration of future support.</p>
*
* <b>Optional</b> - This value may be null on some devices.
*
@@ -354,160 +300,122 @@ public final class CameraCharacteristics extends CameraMetadata {
new Key<Byte>("android.quirks.usePartialResult", byte.class);
/**
- * <p>
- * How many output streams can be allocated at
- * the same time for each type of stream
- * </p>
- * <p>
- * Video snapshot with preview callbacks requires 3
+ * <p>How many output streams can be allocated at
+ * the same time for each type of stream</p>
+ * <p>Video snapshot with preview callbacks requires 3
* processed streams (preview, record, app callbacks) and
- * one JPEG stream (snapshot)
- * </p>
+ * one JPEG stream (snapshot)</p>
*/
public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
/**
- * <p>
- * List of app-visible formats
- * </p>
+ * <p>List of app-visible formats</p>
*/
public static final Key<int[]> SCALER_AVAILABLE_FORMATS =
new Key<int[]>("android.scaler.availableFormats", int[].class);
/**
- * <p>
- * The minimum frame duration that is supported
+ * <p>The minimum frame duration that is supported
* for each resolution in availableJpegSizes. Should
* correspond to the frame duration when only that JPEG
* stream is active and captured in a burst, with all
- * processing set to FAST
- * </p>
- * <p>
- * When multiple streams are configured, the minimum
- * frame duration will be >= max(individual stream min
- * durations)
- * </p>
+ * processing set to FAST</p>
+ * <p>When multiple streams are configured, the minimum
+ * frame duration will be &gt;= max(individual stream min
+ * durations)</p>
*/
public static final Key<long[]> SCALER_AVAILABLE_JPEG_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class);
/**
- * <p>
- * The resolutions available for output from
- * the JPEG block. Listed as width x height
- * </p>
+ * <p>The resolutions available for output from
+ * the JPEG block. Listed as width x height</p>
*/
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
/**
- * <p>
- * The maximum ratio between active area width
+ * <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>
+ * than width</p>
*/
public static final Key<Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM =
new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
/**
- * <p>
- * The minimum frame duration that is supported
+ * <p>The minimum frame duration that is supported
* for each resolution in availableProcessedSizes. Should
* correspond to the frame duration when only that processed
* stream is active, with all processing set to
- * FAST
- * </p>
- * <p>
- * When multiple streams are configured, the minimum
- * frame duration will be >= max(individual stream min
- * durations)
- * </p>
+ * FAST</p>
+ * <p>When multiple streams are configured, the minimum
+ * frame duration will be &gt;= max(individual stream min
+ * durations)</p>
*/
public static final Key<long[]> SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
/**
- * <p>
- * The resolutions available for use with
+ * <p>The resolutions available for use with
* processed output streams, such as YV12, NV12, and
* platform opaque YUV/RGB streams to the GPU or video
- * encoders. Listed as width, height
- * </p>
- * <p>
- * The actual supported resolution list may be limited by
+ * encoders. Listed as width, height</p>
+ * <p>The actual supported resolution list may be limited by
* consumer end points for different use cases. For example, for
* recording use case, the largest supported resolution may be
* limited by max supported size from encoder, for preview use
* case, the largest supported resolution may be limited by max
- * resolution SurfaceTexture/SurfaceView can support.
- * </p>
+ * resolution SurfaceTexture/SurfaceView can support.</p>
*/
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
/**
- * <p>
- * Area of raw data which corresponds to only
+ * <p>Area of raw data which corresponds to only
* active pixels; smaller or equal to
- * pixelArraySize.
- * </p>
+ * pixelArraySize.</p>
*/
public static final Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE =
new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
/**
- * <p>
- * Range of valid sensitivities
- * </p>
+ * <p>Range of valid sensitivities</p>
*/
public static final Key<int[]> SENSOR_INFO_SENSITIVITY_RANGE =
new Key<int[]>("android.sensor.info.sensitivityRange", int[].class);
/**
- * <p>
- * Range of valid exposure
- * times
- * </p>
+ * <p>Range of valid exposure
+ * times</p>
*/
public static final Key<long[]> SENSOR_INFO_EXPOSURE_TIME_RANGE =
new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
/**
- * <p>
- * Maximum possible frame duration (minimum frame
- * rate)
- * </p>
- * <p>
- * Minimum duration is a function of resolution,
+ * <p>Maximum possible frame duration (minimum frame
+ * rate)</p>
+ * <p>Minimum duration is a function of resolution,
* processing settings. See
* android.scaler.availableProcessedMinDurations
* android.scaler.availableJpegMinDurations
- * android.scaler.availableRawMinDurations
- * </p>
+ * android.scaler.availableRawMinDurations</p>
*/
public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
/**
- * <p>
- * The physical dimensions of the full pixel
- * array
- * </p>
- * <p>
- * Needed for FOV calculation for old API
- * </p>
+ * <p>The physical dimensions of the full pixel
+ * array</p>
+ * <p>Needed for FOV calculation for old API</p>
*/
public static final Key<float[]> SENSOR_INFO_PHYSICAL_SIZE =
new Key<float[]>("android.sensor.info.physicalSize", float[].class);
/**
- * <p>
- * Gain factor from electrons to raw units when
- * ISO=100
- * </p>
+ * <p>Gain factor from electrons to raw units when
+ * ISO=100</p>
*
* <b>Optional</b> - This value may be null on some devices.
*
@@ -519,16 +427,12 @@ public final class CameraCharacteristics extends CameraMetadata {
new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
/**
- * <p>
- * Maximum sensitivity that is implemented
- * purely through analog gain
- * </p>
- * <p>
- * For android.sensor.sensitivity values less than or
+ * <p>Maximum sensitivity that is implemented
+ * purely through analog gain</p>
+ * <p>For android.sensor.sensitivity values less than or
* equal to this, all applied gain must be analog. For
* values above this, it can be a mix of analog and
- * digital
- * </p>
+ * digital</p>
*
* <b>Optional</b> - This value may be null on some devices.
*
@@ -540,60 +444,46 @@ public final class CameraCharacteristics extends CameraMetadata {
new Key<Integer>("android.sensor.maxAnalogSensitivity", int.class);
/**
- * <p>
- * Clockwise angle through which the output
+ * <p>Clockwise angle through which the output
* image needs to be rotated to be upright on the device
* screen in its native orientation. Also defines the
* direction of rolling shutter readout, which is from top
- * to bottom in the sensor's coordinate system
- * </p>
+ * to bottom in the sensor's coordinate system</p>
*/
public static final Key<Integer> SENSOR_ORIENTATION =
new Key<Integer>("android.sensor.orientation", 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>
- * SIMPLE means the device supports the
+ * <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>SIMPLE means the device supports the
* android.statistics.faceRectangles and
- * android.statistics.faceScores outputs.
- * </p><p>
- * FULL means the device additionally supports the
+ * android.statistics.faceScores outputs.</p>
+ * <p>FULL means the device additionally supports the
* android.statistics.faceIds and
- * android.statistics.faceLandmarks outputs.
- * </p>
+ * android.statistics.faceLandmarks outputs.</p>
*/
public static final Key<byte[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
new Key<byte[]>("android.statistics.info.availableFaceDetectModes", byte[].class);
/**
- * <p>
- * Maximum number of simultaneously detectable
- * faces
- * </p>
+ * <p>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);
/**
- * <p>
- * Maximum number of supported points in the
- * tonemap curve
- * </p>
+ * <p>Maximum number of supported points in the
+ * tonemap curve</p>
*/
public static final Key<Integer> TONEMAP_MAX_CURVE_POINTS =
new Key<Integer>("android.tonemap.maxCurvePoints", int.class);
/**
- * <p>
- * A list of camera LEDs that are available on this system.
- * </p>
+ * <p>A list of camera LEDs that are available on this system.</p>
* @see #LED_AVAILABLE_LEDS_TRANSMIT
*
* @hide
@@ -602,17 +492,14 @@ public final class CameraCharacteristics extends CameraMetadata {
new Key<int[]>("android.led.availableLeds", int[].class);
/**
- * <p>
- * The camera 3 HAL device can implement one of two possible
+ * <p>The camera 3 HAL device can implement one of two possible
* operational modes; limited and full. Full support is
* expected from new higher-end devices. Limited mode has
* hardware requirements roughly in line with those for a
* camera HAL device v1 implementation, and is expected from
* older or inexpensive devices. Full is a strict superset of
- * limited, and they share the same essential operational flow.
- * </p><p>
- * For full details refer to "S3. Operational Modes" in camera3.h
- * </p>
+ * limited, and they share the same essential operational flow.</p>
+ * <p>For full details refer to "S3. Operational Modes" in camera3.h</p>
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
*/
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 5d0bb33..bd99711 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -224,9 +224,7 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * android.led.transmit control is used
- * </p>
+ * <p>android.led.transmit control is used</p>
* @see CameraCharacteristics#LED_AVAILABLE_LEDS
* @hide
*/
@@ -251,28 +249,22 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * Use the android.colorCorrection.transform matrix
- * and android.colorCorrection.gains to do color conversion
- * </p>
+ * <p>Use the android.colorCorrection.transform matrix
+ * and android.colorCorrection.gains to do color conversion</p>
* @see CaptureRequest#COLOR_CORRECTION_MODE
*/
public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0;
/**
- * <p>
- * Must not slow down frame rate relative to raw
- * bayer output
- * </p>
+ * <p>Must not slow down frame rate relative to raw
+ * bayer output</p>
* @see CaptureRequest#COLOR_CORRECTION_MODE
*/
public static final int COLOR_CORRECTION_MODE_FAST = 1;
/**
- * <p>
- * Frame rate may be reduced by high
- * quality
- * </p>
+ * <p>Frame rate may be reduced by high
+ * quality</p>
* @see CaptureRequest#COLOR_CORRECTION_MODE
*/
public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
@@ -306,52 +298,42 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * Autoexposure is disabled; sensor.exposureTime,
- * sensor.sensitivity and sensor.frameDuration are used
- * </p>
+ * <p>Autoexposure is disabled; sensor.exposureTime,
+ * sensor.sensitivity and sensor.frameDuration are used</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_OFF = 0;
/**
- * <p>
- * Autoexposure is active, no flash
- * control
- * </p>
+ * <p>Autoexposure is active, no flash
+ * control</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON = 1;
/**
- * <p>
- * if flash exists Autoexposure is active, auto
+ * <p>if flash exists Autoexposure is active, auto
* flash control; flash may be fired when precapture
* trigger is activated, and for captures for which
- * captureIntent = STILL_CAPTURE
- * </p>
+ * captureIntent = STILL_CAPTURE</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2;
/**
- * <p>
- * if flash exists Autoexposure is active, auto
+ * <p>if flash exists Autoexposure is active, auto
* flash control for precapture trigger and always flash
- * when captureIntent = STILL_CAPTURE
- * </p>
+ * when captureIntent = STILL_CAPTURE</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3;
/**
- * <p>
- * optional Automatic red eye reduction with flash.
+ * <p>optional Automatic red eye reduction with flash.
* If deemed necessary, red eye reduction sequence should
* fire when precapture trigger is activated, and final
* flash should fire when captureIntent =
- * STILL_CAPTURE
- * </p>
+ * STILL_CAPTURE</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
@@ -361,20 +343,16 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * The trigger is idle.
- * </p>
+ * <p>The trigger is idle.</p>
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
*/
public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0;
/**
- * <p>
- * The precapture metering sequence
+ * <p>The precapture metering sequence
* must be started. The exact effect of the precapture
* trigger depends on the current AE mode and
- * state.
- * </p>
+ * state.</p>
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
*/
public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
@@ -384,55 +362,44 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * The 3A routines do not control the lens;
+ * <p>The 3A routines do not control the lens;
* android.lens.focusDistance is controlled by the
- * application
- * </p>
+ * application</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
public static final int CONTROL_AF_MODE_OFF = 0;
/**
- * <p>
- * if lens is not fixed focus.
- * </p><p>
- * Use android.lens.minimumFocusDistance to determine if lens
+ * <p>If lens is not fixed focus.</p>
+ * <p>Use android.lens.minimumFocusDistance to determine if lens
* is fixed focus In this mode, the lens does not move unless
* the autofocus trigger action is called. When that trigger
* is activated, AF must transition to ACTIVE_SCAN, then to
* the outcome of the scan (FOCUSED or
- * NOT_FOCUSED).
- * </p><p>
- * Triggering cancel AF resets the lens position to default,
- * and sets the AF state to INACTIVE.
- * </p>
+ * NOT_FOCUSED).</p>
+ * <p>Triggering cancel AF resets the lens position to default,
+ * and sets the AF state to INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
public static final int CONTROL_AF_MODE_AUTO = 1;
/**
- * <p>
- * In this mode, the lens does not move unless the
- * autofocus trigger action is called.
- * </p><p>
- * When that trigger is activated, AF must transition to
+ * <p>In this mode, the lens does not move unless the
+ * autofocus trigger action is called.</p>
+ * <p>When that trigger is activated, AF must transition to
* ACTIVE_SCAN, then to the outcome of the scan (FOCUSED or
* NOT_FOCUSED). Triggering cancel AF resets the lens
* position to default, and sets the AF state to
- * INACTIVE.
- * </p>
+ * INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
public static final int CONTROL_AF_MODE_MACRO = 2;
/**
- * <p>
- * In this mode, the AF algorithm modifies the lens
+ * <p>In this mode, the AF algorithm modifies the lens
* position continually to attempt to provide a
- * constantly-in-focus image stream.
- * </p><p>
- * The focusing behavior should be suitable for good quality
+ * constantly-in-focus image stream.</p>
+ * <p>The focusing behavior should be suitable for good quality
* video recording; typically this means slower focus
* movement and no overshoots. When the AF trigger is not
* involved, the AF algorithm should start in INACTIVE state,
@@ -440,25 +407,21 @@ public abstract class CameraMetadata {
* states as appropriate. When the AF trigger is activated,
* the algorithm should immediately transition into
* AF_FOCUSED or AF_NOT_FOCUSED as appropriate, and lock the
- * lens position until a cancel AF trigger is received.
- * </p><p>
- * Once cancel is received, the algorithm should transition
+ * lens position until a cancel AF trigger is received.</p>
+ * <p>Once cancel is received, the algorithm should transition
* back to INACTIVE and resume passive scan. Note that this
* behavior is not identical to CONTINUOUS_PICTURE, since an
* ongoing PASSIVE_SCAN must immediately be
- * canceled.
- * </p>
+ * canceled.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
public static final int CONTROL_AF_MODE_CONTINUOUS_VIDEO = 3;
/**
- * <p>
- * In this mode, the AF algorithm modifies the lens
+ * <p>In this mode, the AF algorithm modifies the lens
* position continually to attempt to provide a
- * constantly-in-focus image stream.
- * </p><p>
- * The focusing behavior should be suitable for still image
+ * constantly-in-focus image stream.</p>
+ * <p>The focusing behavior should be suitable for still image
* capture; typically this means focusing as fast as
* possible. When the AF trigger is not involved, the AF
* algorithm should start in INACTIVE state, and then
@@ -467,22 +430,18 @@ public abstract class CameraMetadata {
* trigger is activated, the algorithm should finish its
* PASSIVE_SCAN if active, and then transition into
* AF_FOCUSED or AF_NOT_FOCUSED as appropriate, and lock the
- * lens position until a cancel AF trigger is received.
- * </p><p>
- * When the AF cancel trigger is activated, the algorithm
+ * lens position until a cancel AF trigger is received.</p>
+ * <p>When the AF cancel trigger is activated, the algorithm
* should transition back to INACTIVE and then act as if it
- * has just been started.
- * </p>
+ * has just been started.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
public static final int CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4;
/**
- * <p>
- * Extended depth of field (digital focus). AF
+ * <p>Extended depth of field (digital focus). AF
* trigger is ignored, AF state should always be
- * INACTIVE.
- * </p>
+ * INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
public static final int CONTROL_AF_MODE_EDOF = 5;
@@ -492,26 +451,20 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * The trigger is idle.
- * </p>
+ * <p>The trigger is idle.</p>
* @see CaptureRequest#CONTROL_AF_TRIGGER
*/
public static final int CONTROL_AF_TRIGGER_IDLE = 0;
/**
- * <p>
- * Autofocus must trigger now.
- * </p>
+ * <p>Autofocus must trigger now.</p>
* @see CaptureRequest#CONTROL_AF_TRIGGER
*/
public static final int CONTROL_AF_TRIGGER_START = 1;
/**
- * <p>
- * Autofocus must return to initial
- * state, and cancel any active trigger.
- * </p>
+ * <p>Autofocus must return to initial
+ * state, and cancel any active trigger.</p>
* @see CaptureRequest#CONTROL_AF_TRIGGER
*/
public static final int CONTROL_AF_TRIGGER_CANCEL = 2;
@@ -570,59 +523,47 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * This request doesn't fall into the other
+ * <p>This request doesn't fall into the other
* categories. Default to preview-like
- * behavior.
- * </p>
+ * 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
+ * <p>This request is for a preview-like usecase. The
* precapture trigger may be used to start off a metering
- * w/flash sequence
- * </p>
+ * 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>
+ * <p>This request is for a still capture-type
+ * usecase.</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>
+ * <p>This request is for a video recording
+ * usecase.</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>
+ * <p>This request is for a video snapshot (still
+ * image while recording video) usecase</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
/**
- * <p>
- * This request is for a ZSL usecase; the
+ * <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;
@@ -681,36 +622,30 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * Full application control of pipeline. All 3A
+ * <p>Full application control of pipeline. All 3A
* routines are disabled, no other settings in
- * android.control.* have any effect
- * </p>
+ * android.control.* have any effect</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF = 0;
/**
- * <p>
- * Use settings for each individual 3A routine.
+ * <p>Use settings for each individual 3A routine.
* 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
+ * <p>Use specific scene mode. Enabling this disables
* control.aeMode, control.awbMode and control.afMode
* controls; the HAL must 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 availableSceneModes !=
- * UNSUPPORTED
- * </p>
+ * UNSUPPORTED</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_USE_SCENE_MODE = 2;
@@ -725,18 +660,15 @@ public abstract class CameraMetadata {
public static final int CONTROL_SCENE_MODE_UNSUPPORTED = 0;
/**
- * <p>
- * if face detection support exists Use face
+ * <p>if face detection support exists Use face
* detection data to drive 3A routines. If face detection
* statistics are disabled, should still operate correctly
* (but not return face detection statistics to the
- * framework).
- * </p><p>
- * Unlike the other scene modes, aeMode, awbMode, and afMode
+ * framework).</p>
+ * <p>Unlike the other scene modes, aeMode, awbMode, and afMode
* remain active when FACE_PRIORITY is set. This is due to
* compatibility concerns with the old camera
- * API
- * </p>
+ * API</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1;
@@ -821,27 +753,21 @@ public abstract class CameraMetadata {
//
/**
- * <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 raw
- * bayer output
- * </p>
+ * <p>Must not slow down frame rate relative to raw
+ * bayer 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>Frame rate may be reduced by high
+ * quality</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_HIGH_QUALITY = 2;
@@ -851,30 +777,24 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * Do not fire the flash for this
- * capture
- * </p>
+ * <p>Do not fire the flash for this
+ * capture</p>
* @see CaptureRequest#FLASH_MODE
*/
public static final int FLASH_MODE_OFF = 0;
/**
- * <p>
- * if android.flash.available is true Fire flash
+ * <p>if android.flash.available is true Fire flash
* for this capture based on firingPower,
- * firingTime.
- * </p>
+ * firingTime.</p>
* @see CaptureRequest#FLASH_MODE
*/
public static final int FLASH_MODE_SINGLE = 1;
/**
- * <p>
- * if android.flash.available is true Flash
+ * <p>if android.flash.available is true Flash
* continuously on, power set by
- * firingPower
- * </p>
+ * firingPower</p>
* @see CaptureRequest#FLASH_MODE
*/
public static final int FLASH_MODE_TORCH = 2;
@@ -898,27 +818,21 @@ public abstract class CameraMetadata {
//
/**
- * <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 raw
- * bayer output
- * </p>
+ * <p>Must not slow down frame rate relative to raw
+ * bayer 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>May slow down frame rate to provide highest
+ * quality</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
@@ -933,19 +847,15 @@ public abstract class CameraMetadata {
public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0;
/**
- * <p>
- * Optional Return rectangle and confidence
- * only
- * </p>
+ * <p>Optional Return rectangle and confidence
+ * only</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>Optional Return all face
+ * metadata</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
@@ -969,28 +879,22 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * Use the tone mapping curve specified in
- * android.tonemap.curve
- * </p>
+ * <p>Use the tone mapping curve specified in
+ * android.tonemap.curve</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
/**
- * <p>
- * Must not slow down frame rate relative to raw
- * bayer output
- * </p>
+ * <p>Must not slow down frame rate relative to raw
+ * bayer output</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_FAST = 1;
/**
- * <p>
- * Frame rate may be reduced by high
- * quality
- * </p>
+ * <p>Frame rate may be reduced by high
+ * quality</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
@@ -1000,60 +904,48 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * AE is off. When a camera device is opened, it starts in
- * this state.
- * </p>
+ * <p>AE is off. When a camera device is opened, it starts in
+ * this state.</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_INACTIVE = 0;
/**
- * <p>
- * AE doesn't yet have a good set of control values
- * for the current scene
- * </p>
+ * <p>AE doesn't yet have a good set of control values
+ * for the current scene</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_SEARCHING = 1;
/**
- * <p>
- * AE has a good set of control values for the
- * current scene
- * </p>
+ * <p>AE has a good set of control values for the
+ * current scene</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_CONVERGED = 2;
/**
- * <p>
- * AE has been locked (aeMode =
- * LOCKED)
- * </p>
+ * <p>AE has been locked (aeMode =
+ * LOCKED)</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_LOCKED = 3;
/**
- * <p>
- * AE has a good set of control values, but flash
+ * <p>AE has a good set of control values, but flash
* needs to be fired for good quality still
- * capture
- * </p>
+ * capture</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_FLASH_REQUIRED = 4;
/**
- * <p>
- * AE has been asked to do a precapture sequence
+ * <p>AE has been asked to do a precapture sequence
* (through the
* trigger_action(CAMERA2_TRIGGER_PRECAPTURE_METERING)
* call), and is currently executing it. Once PRECAPTURE
* completes, AE will transition to CONVERGED or
- * FLASH_REQUIRED as appropriate
- * </p>
+ * FLASH_REQUIRED as appropriate</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_PRECAPTURE = 5;
@@ -1063,71 +955,57 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * AF off or has not yet tried to scan/been asked
+ * <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.
- * </p>
+ * this state.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_INACTIVE = 0;
/**
- * <p>
- * if CONTINUOUS_* modes are supported. AF is
+ * <p>if CONTINUOUS_* modes are supported. AF is
* currently doing an AF scan initiated by a continuous
- * autofocus mode
- * </p>
+ * autofocus mode</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1;
/**
- * <p>
- * if CONTINUOUS_* modes are supported. AF currently
+ * <p>if CONTINUOUS_* modes are supported. AF currently
* believes it is in focus, but may restart scanning at
- * any time.
- * </p>
+ * any time.</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
+ * <p>if AUTO or MACRO modes are supported. AF is doing
* an AF scan because it was triggered by AF
- * trigger
- * </p>
+ * trigger</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
+ * <p>if any AF mode besides OFF is supported. AF
* believes it is focused correctly and is
- * locked
- * </p>
+ * locked</p>
* @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
+ * <p>if any AF mode besides OFF is supported. AF has
* failed to focus successfully and is
- * locked
- * </p>
+ * locked</p>
* @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
+ * <p>if CONTINUOUS_* modes are supported. AF finished a
* passive scan without finding focus, and may restart
- * scanning at any time.
- * </p>
+ * scanning at any time.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_UNFOCUSED = 6;
@@ -1137,37 +1015,29 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * AWB is not in auto mode. When a camera device is opened, it
- * starts in this state.
- * </p>
+ * <p>AWB is not in auto mode. When a camera device is opened, it
+ * starts in this state.</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
- * </p>
+ * <p>AWB doesn't yet have a good set of control
+ * values for the current scene</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_SEARCHING = 1;
/**
- * <p>
- * AWB has a good set of control values for the
- * current scene
- * </p>
+ * <p>AWB has a good set of control values for the
+ * current scene</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_CONVERGED = 2;
/**
- * <p>
- * AE has been locked (aeMode =
- * LOCKED)
- * </p>
+ * <p>AE has been locked (aeMode =
+ * LOCKED)</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_LOCKED = 3;
@@ -1177,36 +1047,28 @@ public abstract class CameraMetadata {
//
/**
- * <p>
- * No flash on camera
- * </p>
+ * <p>No flash on camera</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_UNAVAILABLE = 0;
/**
- * <p>
- * if android.flash.available is true Flash is
- * charging and cannot be fired
- * </p>
+ * <p>if android.flash.available is true Flash is
+ * charging and cannot be fired</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_CHARGING = 1;
/**
- * <p>
- * if android.flash.available is true Flash is
- * ready to fire
- * </p>
+ * <p>if android.flash.available is true Flash is
+ * ready to fire</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_READY = 2;
/**
- * <p>
- * if android.flash.available is true Flash fired
- * for this capture
- * </p>
+ * <p>if android.flash.available is true Flash fired
+ * for this capture</p>
* @see CaptureResult#FLASH_STATE
*/
public static final int FLASH_STATE_FIRED = 3;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 00b02fa..9304cd0 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -318,10 +318,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
/**
- * <p>
- * When android.control.awbMode is not OFF, TRANSFORM_MATRIX
- * should be ignored.
- * </p>
+ * <p>When android.control.awbMode is not OFF, TRANSFORM_MATRIX
+ * should be ignored.</p>
* @see #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX
* @see #COLOR_CORRECTION_MODE_FAST
* @see #COLOR_CORRECTION_MODE_HIGH_QUALITY
@@ -330,55 +328,42 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.colorCorrection.mode", int.class);
/**
- * <p>
- * A color transform matrix to use to transform
- * from sensor RGB color space to output linear sRGB color space
- * </p>
- * <p>
- * This matrix is either set by HAL when the request
+ * <p>A color transform matrix to use to transform
+ * from sensor RGB color space to output linear sRGB color space</p>
+ * <p>This matrix is either set by HAL when the request
* android.colorCorrection.mode is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
- * android.colorCorrection.mode is TRANSFORM_MATRIX.
- * </p><p>
- * In the latter case, the HAL may round the matrix to account
+ * android.colorCorrection.mode is TRANSFORM_MATRIX.</p>
+ * <p>In the latter case, the HAL may round the matrix to account
* for precision issues; the final rounded matrix should be
- * reported back in this matrix result metadata.
- * </p>
+ * reported back in this matrix result metadata.</p>
*/
public static final Key<Rational[]> COLOR_CORRECTION_TRANSFORM =
new Key<Rational[]>("android.colorCorrection.transform", Rational[].class);
/**
- * <p>
- * Gains applying to Bayer color channels for
- * white-balance
- * </p>
- * <p>
- * The 4-channel white-balance gains are defined in
+ * <p>Gains applying to Bayer color channels for
+ * white-balance</p>
+ * <p>The 4-channel white-balance gains are defined in
* the order of [R G_even G_odd B], where G_even is the gain
* for green pixels on even rows of the output, and G_odd
* is the gain for greenpixels on the odd rows. if a HAL
* does not support a separate gain for even/odd green channels,
* it should use the G_even value,and write G_odd equal to
- * G_even in the output result metadata.
- * </p><p>
- * This array is either set by HAL when the request
+ * G_even in the output result metadata.</p>
+ * <p>This array is either set by HAL when the request
* android.colorCorrection.mode is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
- * android.colorCorrection.mode is TRANSFORM_MATRIX.
- * </p><p>
- * The ouput should be the gains actually applied by the HAL to
- * the current frame.
- * </p>
+ * android.colorCorrection.mode is TRANSFORM_MATRIX.</p>
+ * <p>The ouput should be the gains actually applied by the HAL to
+ * the current frame.</p>
*/
public static final Key<float[]> COLOR_CORRECTION_GAINS =
new Key<float[]>("android.colorCorrection.gains", float[].class);
/**
- * <p>
- * Enum for controlling
- * antibanding
- * </p>
+ * <p>Enum for controlling
+ * antibanding</p>
* @see #CONTROL_AE_ANTIBANDING_MODE_OFF
* @see #CONTROL_AE_ANTIBANDING_MODE_50HZ
* @see #CONTROL_AE_ANTIBANDING_MODE_60HZ
@@ -388,42 +373,30 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.aeAntibandingMode", int.class);
/**
- * <p>
- * Adjustment to AE target image
- * brightness
- * </p>
- * <p>
- * For example, if EV step is 0.333, '6' will mean an
+ * <p>Adjustment to AE target image
+ * brightness</p>
+ * <p>For example, if EV step is 0.333, '6' will mean an
* exposure compensation of +2 EV; -3 will mean an exposure
- * compensation of -1
- * </p>
+ * compensation of -1</p>
*/
public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
new Key<Integer>("android.control.aeExposureCompensation", int.class);
/**
- * <p>
- * Whether AE is currently locked to its latest
- * calculated values
- * </p>
- * <p>
- * Note that even when AE is locked, the flash may be
+ * <p>Whether AE is currently locked to its latest
+ * calculated values</p>
+ * <p>Note that even when AE is locked, the flash may be
* fired if the AE mode is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
- * ON_AUTO_FLASH_REDEYE.
- * </p>
+ * ON_AUTO_FLASH_REDEYE.</p>
*/
public static final Key<Boolean> CONTROL_AE_LOCK =
new Key<Boolean>("android.control.aeLock", boolean.class);
/**
- * <p>
- * Whether AE is currently updating the sensor
- * exposure and sensitivity fields
- * </p>
- * <p>
- * Only effective if android.control.mode =
- * AUTO
- * </p>
+ * <p>Whether AE is currently updating the sensor
+ * exposure and sensitivity fields</p>
+ * <p>Only effective if android.control.mode =
+ * AUTO</p>
* @see #CONTROL_AE_MODE_OFF
* @see #CONTROL_AE_MODE_ON
* @see #CONTROL_AE_MODE_ON_AUTO_FLASH
@@ -434,60 +407,45 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.aeMode", int.class);
/**
- * <p>
- * List of areas to use for
- * metering
- * </p>
- * <p>
- * Each area is a rectangle plus weight: xmin, ymin,
+ * <p>List of areas to use for
+ * metering</p>
+ * <p>Each area is a rectangle plus weight: xmin, ymin,
* xmax, ymax, weight. The rectangle is defined inclusive of the
- * specified coordinates.
- * </p><p>
- * The coordinate system is based on the active pixel array,
+ * specified coordinates.</p>
+ * <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* (android.sensor.info.activeArraySize.width - 1,
* android.sensor.info.activeArraySize.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
- * should be nonnegative.
- * </p><p>
- * If all regions have 0 weight, then no specific metering area
+ * should be nonnegative.</p>
+ * <p>If all regions have 0 weight, then no specific metering area
* needs to be used by the HAL. If the metering region is
* outside the current android.scaler.cropRegion, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata
- * </p>
+ * used sections in the frame metadata</p>
*/
public static final Key<int[]> CONTROL_AE_REGIONS =
new Key<int[]>("android.control.aeRegions", int[].class);
/**
- * <p>
- * Range over which fps can be adjusted to
- * maintain exposure
- * </p>
- * <p>
- * Only constrains AE algorithm, not manual control
- * of android.sensor.exposureTime
- * </p>
+ * <p>Range over which fps can be adjusted to
+ * maintain exposure</p>
+ * <p>Only constrains AE algorithm, not manual control
+ * of android.sensor.exposureTime</p>
*/
public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
/**
- * <p>
- * Whether the HAL must trigger precapture
- * metering.
- * </p>
- * <p>
- * This entry is normally set to IDLE, or is not
+ * <p>Whether the HAL must trigger precapture
+ * metering.</p>
+ * <p>This entry is normally set to IDLE, or is not
* included at all in the request settings. When included and
* set to START, the HAL must trigger the autoexposure
- * precapture metering sequence.
- * </p><p>
- * The effect of AE precapture trigger depends on the current
+ * precapture metering sequence.</p>
+ * <p>The effect of AE precapture trigger depends on the current
* AE mode and state; see the camera HAL device v3 header for
- * details.
- * </p>
+ * details.</p>
* @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
* @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
*/
@@ -495,10 +453,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
/**
- * <p>
- * Whether AF is currently enabled, and what
- * mode it is set to
- * </p>
+ * <p>Whether AF is currently enabled, and what
+ * mode it is set to</p>
* @see #CONTROL_AF_MODE_OFF
* @see #CONTROL_AF_MODE_AUTO
* @see #CONTROL_AF_MODE_MACRO
@@ -510,46 +466,35 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.afMode", int.class);
/**
- * <p>
- * List of areas to use for focus
- * estimation
- * </p>
- * <p>
- * Each area is a rectangle plus weight: xmin, ymin,
+ * <p>List of areas to use for focus
+ * estimation</p>
+ * <p>Each area is a rectangle plus weight: xmin, ymin,
* xmax, ymax, weight. The rectangle is defined inclusive of the
- * specified coordinates.
- * </p><p>
- * The coordinate system is based on the active pixel array,
+ * specified coordinates.</p>
+ * <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* (android.sensor.info.activeArraySize.width - 1,
* android.sensor.info.activeArraySize.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
- * should be nonnegative.
- * </p><p>
- * If all regions have 0 weight, then no specific focus area
+ * should be nonnegative.</p>
+ * <p>If all regions have 0 weight, then no specific focus area
* needs to be used by the HAL. If the focusing region is
* outside the current android.scaler.cropRegion, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata
- * </p>
+ * used sections in the frame metadata</p>
*/
public static final Key<int[]> CONTROL_AF_REGIONS =
new Key<int[]>("android.control.afRegions", int[].class);
/**
- * <p>
- * Whether the HAL must trigger autofocus.
- * </p>
- * <p>
- * This entry is normally set to IDLE, or is not
- * included at all in the request settings.
- * </p><p>
- * When included and set to START, the HAL must trigger the
+ * <p>Whether the HAL must trigger autofocus.</p>
+ * <p>This entry is normally set to IDLE, or is not
+ * included at all in the request settings.</p>
+ * <p>When included and set to START, the HAL must trigger the
* autofocus algorithm. The effect of AF trigger depends on the
* current AF mode and state; see the camera HAL device v3
* header for details. When set to CANCEL, the HAL must cancel
- * any active trigger, and return to initial AF state.
- * </p>
+ * any active trigger, and return to initial AF state.</p>
* @see #CONTROL_AF_TRIGGER_IDLE
* @see #CONTROL_AF_TRIGGER_START
* @see #CONTROL_AF_TRIGGER_CANCEL
@@ -558,28 +503,20 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.afTrigger", int.class);
/**
- * <p>
- * Whether AWB is currently locked to its
- * latest calculated values
- * </p>
- * <p>
- * Note that AWB lock is only meaningful for AUTO
+ * <p>Whether AWB is currently locked to its
+ * latest calculated values</p>
+ * <p>Note that AWB lock is only meaningful for AUTO
* mode; in other modes, AWB is already fixed to a specific
- * setting
- * </p>
+ * setting</p>
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
/**
- * <p>
- * Whether AWB is currently setting the color
+ * <p>Whether AWB is currently setting the color
* transform fields, and what its illumination target
- * is
- * </p>
- * <p>
- * [BC - AWB lock,AWB modes]
- * </p>
+ * is</p>
+ * <p>[BC - AWB lock,AWB modes]</p>
* @see #CONTROL_AWB_MODE_OFF
* @see #CONTROL_AWB_MODE_AUTO
* @see #CONTROL_AWB_MODE_INCANDESCENT
@@ -594,43 +531,32 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.awbMode", int.class);
/**
- * <p>
- * List of areas to use for illuminant
- * estimation
- * </p>
- * <p>
- * Only used in AUTO mode.
- * </p><p>
- * Each area is a rectangle plus weight: xmin, ymin,
+ * <p>List of areas to use for illuminant
+ * estimation</p>
+ * <p>Only used in AUTO mode.</p>
+ * <p>Each area is a rectangle plus weight: xmin, ymin,
* xmax, ymax, weight. The rectangle is defined inclusive of the
- * specified coordinates.
- * </p><p>
- * The coordinate system is based on the active pixel array,
+ * specified coordinates.</p>
+ * <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* (android.sensor.info.activeArraySize.width - 1,
* android.sensor.info.activeArraySize.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
- * should be nonnegative.
- * </p><p>
- * If all regions have 0 weight, then no specific metering area
+ * should be nonnegative.</p>
+ * <p>If all regions have 0 weight, then no specific metering area
* needs to be used by the HAL. If the metering region is
* outside the current android.scaler.cropRegion, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata
- * </p>
+ * used sections in the frame metadata</p>
*/
public static final Key<int[]> CONTROL_AWB_REGIONS =
new Key<int[]>("android.control.awbRegions", int[].class);
/**
- * <p>
- * Information to 3A routines about the purpose
+ * <p>Information to 3A routines about the purpose
* of this capture, to help decide optimal 3A
- * strategy
- * </p>
- * <p>
- * Only used if android.control.mode != OFF.
- * </p>
+ * strategy</p>
+ * <p>Only used if android.control.mode != OFF.</p>
* @see #CONTROL_CAPTURE_INTENT_CUSTOM
* @see #CONTROL_CAPTURE_INTENT_PREVIEW
* @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE
@@ -642,10 +568,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.captureIntent", int.class);
/**
- * <p>
- * Whether any special color effect is in use.
- * Only used if android.control.mode != OFF
- * </p>
+ * <p>Whether any special color effect is in use.
+ * Only used if android.control.mode != OFF</p>
* @see #CONTROL_EFFECT_MODE_OFF
* @see #CONTROL_EFFECT_MODE_MONO
* @see #CONTROL_EFFECT_MODE_NEGATIVE
@@ -660,10 +584,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.effectMode", int.class);
/**
- * <p>
- * Overall mode of 3A control
- * routines
- * </p>
+ * <p>Overall mode of 3A control
+ * routines</p>
* @see #CONTROL_MODE_OFF
* @see #CONTROL_MODE_AUTO
* @see #CONTROL_MODE_USE_SCENE_MODE
@@ -672,10 +594,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.mode", int.class);
/**
- * <p>
- * Which scene mode is active when
- * android.control.mode = SCENE_MODE
- * </p>
+ * <p>Which scene mode is active when
+ * android.control.mode = SCENE_MODE</p>
* @see #CONTROL_SCENE_MODE_UNSUPPORTED
* @see #CONTROL_SCENE_MODE_FACE_PRIORITY
* @see #CONTROL_SCENE_MODE_ACTION
@@ -698,24 +618,18 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.control.sceneMode", int.class);
/**
- * <p>
- * Whether video stabilization is
- * active
- * </p>
- * <p>
- * If enabled, video stabilization can modify the
+ * <p>Whether video stabilization is
+ * active</p>
+ * <p>If enabled, video stabilization can modify the
* android.scaler.cropRegion to keep the video stream
- * stabilized
- * </p>
+ * stabilized</p>
*/
public static final Key<Boolean> CONTROL_VIDEO_STABILIZATION_MODE =
new Key<Boolean>("android.control.videoStabilizationMode", boolean.class);
/**
- * <p>
- * Operation mode for edge
- * enhancement
- * </p>
+ * <p>Operation mode for edge
+ * enhancement</p>
* @see #EDGE_MODE_OFF
* @see #EDGE_MODE_FAST
* @see #EDGE_MODE_HIGH_QUALITY
@@ -724,9 +638,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.edge.mode", int.class);
/**
- * <p>
- * Select flash operation mode
- * </p>
+ * <p>Select flash operation mode</p>
* @see #FLASH_MODE_OFF
* @see #FLASH_MODE_SINGLE
* @see #FLASH_MODE_TORCH
@@ -735,128 +647,92 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.flash.mode", int.class);
/**
- * <p>
- * GPS coordinates to include in output JPEG
- * EXIF
- * </p>
+ * <p>GPS coordinates to include in output JPEG
+ * EXIF</p>
*/
public static final Key<double[]> JPEG_GPS_COORDINATES =
new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
/**
- * <p>
- * 32 characters describing GPS algorithm to
- * include in EXIF
- * </p>
+ * <p>32 characters describing GPS algorithm to
+ * include in EXIF</p>
*/
public static final Key<String> JPEG_GPS_PROCESSING_METHOD =
new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
/**
- * <p>
- * Time GPS fix was made to include in
- * EXIF
- * </p>
+ * <p>Time GPS fix was made to include in
+ * EXIF</p>
*/
public static final Key<Long> JPEG_GPS_TIMESTAMP =
new Key<Long>("android.jpeg.gpsTimestamp", long.class);
/**
- * <p>
- * Orientation of JPEG image to
- * write
- * </p>
+ * <p>Orientation of JPEG image to
+ * write</p>
*/
public static final Key<Integer> JPEG_ORIENTATION =
new Key<Integer>("android.jpeg.orientation", int.class);
/**
- * <p>
- * Compression quality of the final JPEG
- * image
- * </p>
- * <p>
- * 85-95 is typical usage range
- * </p>
+ * <p>Compression quality of the final JPEG
+ * image</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>
+ * <p>Compression quality of JPEG
+ * thumbnail</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
/**
- * <p>
- * Resolution of embedded JPEG
- * thumbnail
- * </p>
+ * <p>Resolution of embedded JPEG
+ * thumbnail</p>
*/
public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
/**
- * <p>
- * Size of the lens aperture
- * </p>
- * <p>
- * Will not be supported on most devices. Can only
- * pick from supported list
- * </p>
+ * <p>Size of the lens aperture</p>
+ * <p>Will not be supported on most devices. Can only
+ * pick from supported list</p>
*/
public static final Key<Float> LENS_APERTURE =
new Key<Float>("android.lens.aperture", float.class);
/**
- * <p>
- * State of lens neutral density
- * filter(s)
- * </p>
- * <p>
- * Will not be supported on most devices. Can only
- * pick from supported list
- * </p>
+ * <p>State of lens neutral density
+ * filter(s)</p>
+ * <p>Will not be supported on most devices. Can only
+ * pick from supported list</p>
*/
public static final Key<Float> LENS_FILTER_DENSITY =
new Key<Float>("android.lens.filterDensity", float.class);
/**
- * <p>
- * Lens optical zoom setting
- * </p>
- * <p>
- * Will not be supported on most devices.
- * </p>
+ * <p>Lens optical zoom setting</p>
+ * <p>Will not be supported on most devices.</p>
*/
public static final Key<Float> LENS_FOCAL_LENGTH =
new Key<Float>("android.lens.focalLength", float.class);
/**
- * <p>
- * Distance to plane of sharpest focus,
- * measured from frontmost surface of the lens
- * </p>
- * <p>
- * 0 = infinity focus. Used value should be clamped
- * to (0,minimum focus distance)
- * </p>
+ * <p>Distance to plane of sharpest focus,
+ * measured from frontmost surface of the lens</p>
+ * <p>0 = infinity focus. Used value should be clamped
+ * to (0,minimum focus distance)</p>
*/
public static final Key<Float> LENS_FOCUS_DISTANCE =
new Key<Float>("android.lens.focusDistance", float.class);
/**
- * <p>
- * Whether optical image stabilization is
- * enabled.
- * </p>
- * <p>
- * Will not be supported on most devices.
- * </p>
+ * <p>Whether optical image stabilization is
+ * enabled.</p>
+ * <p>Will not be supported on most devices.</p>
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -864,10 +740,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
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>
* @see #NOISE_REDUCTION_MODE_OFF
* @see #NOISE_REDUCTION_MODE_FAST
* @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
@@ -876,11 +750,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.noiseReduction.mode", int.class);
/**
- * <p>
- * An application-specified ID for the current
+ * <p>An application-specified ID for the current
* request. Must be maintained unchanged in output
- * frame
- * </p>
+ * frame</p>
*
* @hide
*/
@@ -888,32 +760,24 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.request.id", int.class);
/**
- * <p>
- * (x, y, width, height).
- * </p><p>
- * A rectangle with the top-level corner of (x,y) and size
+ * <p>(x, y, width, height).</p>
+ * <p>A rectangle with the top-level corner of (x,y) and size
* (width, height). The region of the sensor that is used for
* output. Each stream must use this rectangle to produce its
* output, cropping to a smaller region if necessary to
- * maintain the stream's aspect ratio.
- * </p><p>
- * HAL2.x uses only (x, y, width)
- * </p>
- * <p>
- * Any additional per-stream cropping must be done to
- * maximize the final pixel area of the stream.
- * </p><p>
- * For example, if the crop region is set to a 4:3 aspect
+ * maintain the stream's aspect ratio.</p>
+ * <p>HAL2.x uses only (x, y, width)</p>
+ * <p>Any additional per-stream cropping must be done to
+ * maximize the final pixel area of the stream.</p>
+ * <p>For example, if the crop region is set to a 4:3 aspect
* ratio, then 4:3 streams should use the exact crop
* region. 16:9 streams should further crop vertically
- * (letterbox).
- * </p><p>
- * Conversely, if the crop region is set to a 16:9, then 4:3
+ * (letterbox).</p>
+ * <p>Conversely, if the crop region is set to a 16:9, then 4:3
* outputs should crop horizontally (pillarbox), and 16:9
* streams should match exactly. These additional crops must
- * be centered within the crop region.
- * </p><p>
- * The output streams must maintain square pixels at all
+ * be centered within the crop region.</p>
+ * <p>The output streams must maintain square pixels at all
* times, no matter what the relative aspect ratios of the
* crop region and the stream are. Negative values for
* corner are allowed for raw output if full pixel array is
@@ -924,67 +788,48 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* be set to be smaller than floor( activeArraySize.width /
* android.scaler.maxDigitalZoom ) and floor(
* activeArraySize.height / android.scaler.maxDigitalZoom),
- * respectively.
- * </p>
+ * respectively.</p>
*/
public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
/**
- * <p>
- * Duration each pixel is exposed to
- * light.
- * </p><p>
- * If the sensor can't expose this exact duration, it should shorten the
- * duration exposed to the nearest possible value (rather than expose longer).
- * </p>
- * <p>
- * 1/10000 - 30 sec range. No bulb mode
- * </p>
+ * <p>Duration each pixel is exposed to
+ * light.</p>
+ * <p>If the sensor can't expose this exact duration, it should shorten the
+ * duration exposed to the nearest possible value (rather than expose longer).</p>
+ * <p>1/10000 - 30 sec range. No bulb mode</p>
*/
public static final Key<Long> SENSOR_EXPOSURE_TIME =
new Key<Long>("android.sensor.exposureTime", long.class);
/**
- * <p>
- * Duration from start of frame exposure to
- * start of next frame exposure
- * </p>
- * <p>
- * Exposure time has priority, so duration is set to
- * max(duration, exposure time + overhead)
- * </p>
+ * <p>Duration from start of frame exposure to
+ * start of next frame exposure</p>
+ * <p>Exposure time has priority, so duration is set to
+ * max(duration, exposure time + overhead)</p>
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
/**
- * <p>
- * Gain applied to image data. Must be
+ * <p>Gain applied to image data. Must be
* implemented through analog gain only if set to values
- * below 'maximum analog sensitivity'.
- * </p><p>
- * If the sensor can't apply this exact gain, it should lessen the
- * gain to the nearest possible value (rather than gain more).
- * </p>
- * <p>
- * ISO 12232:2006 REI method
- * </p>
+ * below 'maximum analog sensitivity'.</p>
+ * <p>If the sensor can't apply this exact gain, it should lessen the
+ * gain to the nearest possible value (rather than gain more).</p>
+ * <p>ISO 12232:2006 REI method</p>
*/
public static final Key<Integer> SENSOR_SENSITIVITY =
new Key<Integer>("android.sensor.sensitivity", int.class);
/**
- * <p>
- * State of the face detector
- * unit
- * </p>
- * <p>
- * Whether face detection is enabled, and whether it
+ * <p>State of 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
* fields. Value must be one of the
- * android.statistics.info.availableFaceDetectModes.
- * </p>
+ * android.statistics.info.availableFaceDetectModes.</p>
* @see #STATISTICS_FACE_DETECT_MODE_OFF
* @see #STATISTICS_FACE_DETECT_MODE_SIMPLE
* @see #STATISTICS_FACE_DETECT_MODE_FULL
@@ -993,15 +838,11 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.statistics.faceDetectMode", int.class);
/**
- * <p>
- * Whether the HAL needs to output the lens
- * shading map in output result metadata
- * </p>
- * <p>
- * When set to ON,
+ * <p>Whether the HAL needs to output the lens
+ * shading map in output result metadata</p>
+ * <p>When set to ON,
* android.statistics.lensShadingMap must be provided in
- * the output result metdata.
- * </p>
+ * the output result metdata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
*/
@@ -1009,56 +850,40 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
/**
- * <p>
- * Table mapping blue input values to output
- * values
- * </p>
- * <p>
- * Tonemapping / contrast / gamma curve for the blue
- * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
- * </p><p>
- * See android.tonemap.curveRed for more details.
- * </p>
+ * <p>Table mapping blue input values to output
+ * values</p>
+ * <p>Tonemapping / contrast / gamma curve for the blue
+ * channel, to use when android.tonemap.mode is CONTRAST_CURVE.</p>
+ * <p>See android.tonemap.curveRed for more details.</p>
*/
public static final Key<float[]> TONEMAP_CURVE_BLUE =
new Key<float[]>("android.tonemap.curveBlue", float[].class);
/**
- * <p>
- * Table mapping green input values to output
- * values
- * </p>
- * <p>
- * Tonemapping / contrast / gamma curve for the green
- * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
- * </p><p>
- * See android.tonemap.curveRed for more details.
- * </p>
+ * <p>Table mapping green input values to output
+ * values</p>
+ * <p>Tonemapping / contrast / gamma curve for the green
+ * channel, to use when android.tonemap.mode is CONTRAST_CURVE.</p>
+ * <p>See android.tonemap.curveRed for more details.</p>
*/
public static final Key<float[]> TONEMAP_CURVE_GREEN =
new Key<float[]>("android.tonemap.curveGreen", float[].class);
/**
- * <p>
- * Table mapping red input values to output
- * values
- * </p>
- * <p>
- * Tonemapping / contrast / gamma curve for the red
- * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
- * </p><p>
- * Since the input and output ranges may vary depending on
+ * <p>Table mapping red input values to output
+ * values</p>
+ * <p>Tonemapping / contrast / gamma curve for the red
+ * channel, to use when android.tonemap.mode is CONTRAST_CURVE.</p>
+ * <p>Since the input and output ranges may vary depending on
* the camera pipeline, the input and output pixel values
* are represented by normalized floating-point values
- * between 0 and 1, with 0 == black and 1 == white.
- * </p><p>
- * The curve should be linearly interpolated between the
+ * between 0 and 1, with 0 == black and 1 == white.</p>
+ * <p>The curve should be linearly interpolated between the
* defined points. The points will be listed in increasing
* order of P_IN. For example, if the array is: [0.0, 0.0,
- * 0.3, 0.5, 1.0, 1.0], then the input->output mapping
- * for a few sample points would be: 0 -> 0, 0.15 ->
- * 0.25, 0.3 -> 0.5, 0.5 -> 0.64
- * </p>
+ * 0.3, 0.5, 1.0, 1.0], then the input-&gt;output mapping
+ * for a few sample points would be: 0 -&gt; 0, 0.15 -&gt;
+ * 0.25, 0.3 -&gt; 0.5, 0.5 -&gt; 0.64</p>
*/
public static final Key<float[]> TONEMAP_CURVE_RED =
new Key<float[]>("android.tonemap.curveRed", float[].class);
@@ -1072,20 +897,16 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Integer>("android.tonemap.mode", int.class);
/**
- * <p>
- * This LED is nominally used to indicate to the user
+ * <p>This LED is nominally used to indicate to the user
* that the camera is powered on and may be streaming images back to the
* Application Processor. In certain rare circumstances, the OS may
* disable this when video is processed locally and not transmitted to
- * any untrusted applications.
- * </p><p>
- * In particular, the LED *must* always be on when the data could be
- * transmitted off the device. The LED *should* always be on whenever
- * data is stored locally on the device.
- * </p><p>
- * The LED *may* be off if a trusted application is using the data that
- * doesn't violate the above rules.
- * </p>
+ * any untrusted applications.</p>
+ * <p>In particular, the LED <em>must</em> always be on when the data could be
+ * transmitted off the device. The LED <em>should</em> always be on whenever
+ * data is stored locally on the device.</p>
+ * <p>The LED <em>may</em> be off if a trusted application is using the data that
+ * doesn't violate the above rules.</p>
*
* @hide
*/
@@ -1093,28 +914,44 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
new Key<Boolean>("android.led.transmit", boolean.class);
/**
- * <p>
- * Whether black-level compensation is locked
- * to its current values, or is free to vary
- * </p>
- * <p>
- * When set to ON, the values used for black-level
+ * <p>Whether black-level compensation is locked
+ * to its current values, or is free to vary</p>
+ * <p>When set to ON, the values used for black-level
* compensation must not change until the lock is set to
- * OFF
- * </p><p>
- * Since changes to certain capture parameters (such as
+ * OFF</p>
+ * <p>Since changes to certain capture parameters (such as
* exposure time) may require resetting of black level
* compensation, the HAL must report whether setting the
* black level lock was successful in the output result
- * metadata.
- * </p><p>
- * The black level locking must happen at the sensor, and not at the ISP.
+ * metadata.</p>
+ * <p>For example, if a sequence of requests is as follows:</p>
+ * <ul>
+ * <li>Request 1: Exposure = 10ms, Black level lock = OFF</li>
+ * <li>Request 2: Exposure = 10ms, Black level lock = ON</li>
+ * <li>Request 3: Exposure = 10ms, Black level lock = ON</li>
+ * <li>Request 4: Exposure = 20ms, Black level lock = ON</li>
+ * <li>Request 5: Exposure = 20ms, Black level lock = ON</li>
+ * <li>Request 6: Exposure = 20ms, Black level lock = ON</li>
+ * </ul>
+ * <p>And the exposure change in Request 4 requires resetting the black
+ * level offsets, then the output result metadata is expected to be:</p>
+ * <ul>
+ * <li>Result 1: Exposure = 10ms, Black level lock = OFF</li>
+ * <li>Result 2: Exposure = 10ms, Black level lock = ON</li>
+ * <li>Result 3: Exposure = 10ms, Black level lock = ON</li>
+ * <li>Result 4: Exposure = 20ms, Black level lock = OFF</li>
+ * <li>Result 5: Exposure = 20ms, Black level lock = ON</li>
+ * <li>Result 6: Exposure = 20ms, Black level lock = ON</li>
+ * </ul>
+ * <p>This indicates to the application that on frame 4, black levels were
+ * reset due to exposure value changes, and pixel values may not be
+ * consistent across captures.</p>
+ * <p>The black level locking must happen at the sensor, and not at the ISP.
* If for some reason black level locking is no longer legal (for example,
* the analog gain has changed, which forces black levels to be
* recalculated), then the HAL is free to override this request (and it
* must report 'OFF' when this does happen) until the next time locking
- * is legal again.
- * </p>
+ * is legal again.</p>
*/
public static final Key<Boolean> BLACK_LEVEL_LOCK =
new Key<Boolean>("android.blackLevel.lock", boolean.class);
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 7224577..2d686f9 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -123,61 +123,46 @@ public final class CaptureResult extends CameraMetadata {
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
/**
- * <p>
- * A color transform matrix to use to transform
- * from sensor RGB color space to output linear sRGB color space
- * </p>
- * <p>
- * This matrix is either set by HAL when the request
+ * <p>A color transform matrix to use to transform
+ * from sensor RGB color space to output linear sRGB color space</p>
+ * <p>This matrix is either set by HAL when the request
* android.colorCorrection.mode is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
- * android.colorCorrection.mode is TRANSFORM_MATRIX.
- * </p><p>
- * In the latter case, the HAL may round the matrix to account
+ * android.colorCorrection.mode is TRANSFORM_MATRIX.</p>
+ * <p>In the latter case, the HAL may round the matrix to account
* for precision issues; the final rounded matrix should be
- * reported back in this matrix result metadata.
- * </p>
+ * reported back in this matrix result metadata.</p>
*/
public static final Key<Rational[]> COLOR_CORRECTION_TRANSFORM =
new Key<Rational[]>("android.colorCorrection.transform", Rational[].class);
/**
- * <p>
- * Gains applying to Bayer color channels for
- * white-balance
- * </p>
- * <p>
- * The 4-channel white-balance gains are defined in
+ * <p>Gains applying to Bayer color channels for
+ * white-balance</p>
+ * <p>The 4-channel white-balance gains are defined in
* the order of [R G_even G_odd B], where G_even is the gain
* for green pixels on even rows of the output, and G_odd
* is the gain for greenpixels on the odd rows. if a HAL
* does not support a separate gain for even/odd green channels,
* it should use the G_even value,and write G_odd equal to
- * G_even in the output result metadata.
- * </p><p>
- * This array is either set by HAL when the request
+ * G_even in the output result metadata.</p>
+ * <p>This array is either set by HAL when the request
* android.colorCorrection.mode is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
- * android.colorCorrection.mode is TRANSFORM_MATRIX.
- * </p><p>
- * The ouput should be the gains actually applied by the HAL to
- * the current frame.
- * </p>
+ * android.colorCorrection.mode is TRANSFORM_MATRIX.</p>
+ * <p>The ouput should be the gains actually applied by the HAL to
+ * the current frame.</p>
*/
public static final Key<float[]> COLOR_CORRECTION_GAINS =
new Key<float[]>("android.colorCorrection.gains", float[].class);
/**
- * <p>
- * The ID sent with the latest
- * CAMERA2_TRIGGER_PRECAPTURE_METERING call
- * </p>
- * <p>
- * Must be 0 if no
+ * <p>The ID sent with the latest
+ * CAMERA2_TRIGGER_PRECAPTURE_METERING call</p>
+ * <p>Must be 0 if no
* CAMERA2_TRIGGER_PRECAPTURE_METERING trigger received yet
* by HAL. Always updated even if AE algorithm ignores the
- * trigger
- * </p>
+ * trigger</p>
*
* @hide
*/
@@ -185,41 +170,31 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.aePrecaptureId", int.class);
/**
- * <p>
- * List of areas to use for
- * metering
- * </p>
- * <p>
- * Each area is a rectangle plus weight: xmin, ymin,
+ * <p>List of areas to use for
+ * metering</p>
+ * <p>Each area is a rectangle plus weight: xmin, ymin,
* xmax, ymax, weight. The rectangle is defined inclusive of the
- * specified coordinates.
- * </p><p>
- * The coordinate system is based on the active pixel array,
+ * specified coordinates.</p>
+ * <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* (android.sensor.info.activeArraySize.width - 1,
* android.sensor.info.activeArraySize.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
- * should be nonnegative.
- * </p><p>
- * If all regions have 0 weight, then no specific metering area
+ * should be nonnegative.</p>
+ * <p>If all regions have 0 weight, then no specific metering area
* needs to be used by the HAL. If the metering region is
* outside the current android.scaler.cropRegion, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata
- * </p>
+ * used sections in the frame metadata</p>
*/
public static final Key<int[]> CONTROL_AE_REGIONS =
new Key<int[]>("android.control.aeRegions", int[].class);
/**
- * <p>
- * Current state of AE algorithm
- * </p>
- * <p>
- * Whenever the AE algorithm state changes, a
+ * <p>Current state of AE algorithm</p>
+ * <p>Whenever the AE algorithm state changes, a
* MSG_AUTOEXPOSURE notification must be send if a
- * notification callback is registered.
- * </p>
+ * notification callback is registered.</p>
* @see #CONTROL_AE_STATE_INACTIVE
* @see #CONTROL_AE_STATE_SEARCHING
* @see #CONTROL_AE_STATE_CONVERGED
@@ -231,10 +206,8 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.aeState", int.class);
/**
- * <p>
- * Whether AF is currently enabled, and what
- * mode it is set to
- * </p>
+ * <p>Whether AF is currently enabled, and what
+ * mode it is set to</p>
* @see #CONTROL_AF_MODE_OFF
* @see #CONTROL_AF_MODE_AUTO
* @see #CONTROL_AF_MODE_MACRO
@@ -246,41 +219,31 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.afMode", int.class);
/**
- * <p>
- * List of areas to use for focus
- * estimation
- * </p>
- * <p>
- * Each area is a rectangle plus weight: xmin, ymin,
+ * <p>List of areas to use for focus
+ * estimation</p>
+ * <p>Each area is a rectangle plus weight: xmin, ymin,
* xmax, ymax, weight. The rectangle is defined inclusive of the
- * specified coordinates.
- * </p><p>
- * The coordinate system is based on the active pixel array,
+ * specified coordinates.</p>
+ * <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* (android.sensor.info.activeArraySize.width - 1,
* android.sensor.info.activeArraySize.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
- * should be nonnegative.
- * </p><p>
- * If all regions have 0 weight, then no specific focus area
+ * should be nonnegative.</p>
+ * <p>If all regions have 0 weight, then no specific focus area
* needs to be used by the HAL. If the focusing region is
* outside the current android.scaler.cropRegion, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata
- * </p>
+ * used sections in the frame metadata</p>
*/
public static final Key<int[]> CONTROL_AF_REGIONS =
new Key<int[]>("android.control.afRegions", int[].class);
/**
- * <p>
- * Current state of AF algorithm
- * </p>
- * <p>
- * Whenever the AF algorithm state changes, a
+ * <p>Current state of AF algorithm</p>
+ * <p>Whenever the AF algorithm state changes, a
* MSG_AUTOFOCUS notification must be send if a notification
- * callback is registered.
- * </p>
+ * callback is registered.</p>
* @see #CONTROL_AF_STATE_INACTIVE
* @see #CONTROL_AF_STATE_PASSIVE_SCAN
* @see #CONTROL_AF_STATE_PASSIVE_FOCUSED
@@ -293,15 +256,11 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.afState", int.class);
/**
- * <p>
- * The ID sent with the latest
- * CAMERA2_TRIGGER_AUTOFOCUS call
- * </p>
- * <p>
- * Must be 0 if no CAMERA2_TRIGGER_AUTOFOCUS trigger
+ * <p>The ID sent with the latest
+ * CAMERA2_TRIGGER_AUTOFOCUS call</p>
+ * <p>Must be 0 if no CAMERA2_TRIGGER_AUTOFOCUS trigger
* received yet by HAL. Always updated even if AF algorithm
- * ignores the trigger
- * </p>
+ * ignores the trigger</p>
*
* @hide
*/
@@ -309,14 +268,10 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.afTriggerId", int.class);
/**
- * <p>
- * Whether AWB is currently setting the color
+ * <p>Whether AWB is currently setting the color
* transform fields, and what its illumination target
- * is
- * </p>
- * <p>
- * [BC - AWB lock,AWB modes]
- * </p>
+ * is</p>
+ * <p>[BC - AWB lock,AWB modes]</p>
* @see #CONTROL_AWB_MODE_OFF
* @see #CONTROL_AWB_MODE_AUTO
* @see #CONTROL_AWB_MODE_INCANDESCENT
@@ -331,43 +286,32 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.awbMode", int.class);
/**
- * <p>
- * List of areas to use for illuminant
- * estimation
- * </p>
- * <p>
- * Only used in AUTO mode.
- * </p><p>
- * Each area is a rectangle plus weight: xmin, ymin,
+ * <p>List of areas to use for illuminant
+ * estimation</p>
+ * <p>Only used in AUTO mode.</p>
+ * <p>Each area is a rectangle plus weight: xmin, ymin,
* xmax, ymax, weight. The rectangle is defined inclusive of the
- * specified coordinates.
- * </p><p>
- * The coordinate system is based on the active pixel array,
+ * specified coordinates.</p>
+ * <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* (android.sensor.info.activeArraySize.width - 1,
* android.sensor.info.activeArraySize.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
- * should be nonnegative.
- * </p><p>
- * If all regions have 0 weight, then no specific metering area
+ * should be nonnegative.</p>
+ * <p>If all regions have 0 weight, then no specific metering area
* needs to be used by the HAL. If the metering region is
* outside the current android.scaler.cropRegion, the HAL
* should ignore the sections outside the region and output the
- * used sections in the frame metadata
- * </p>
+ * used sections in the frame metadata</p>
*/
public static final Key<int[]> CONTROL_AWB_REGIONS =
new Key<int[]>("android.control.awbRegions", int[].class);
/**
- * <p>
- * Current state of AWB algorithm
- * </p>
- * <p>
- * Whenever the AWB algorithm state changes, a
+ * <p>Current state of AWB algorithm</p>
+ * <p>Whenever the AWB algorithm state changes, a
* MSG_AUTOWHITEBALANCE notification must be send if a
- * notification callback is registered.
- * </p>
+ * notification callback is registered.</p>
* @see #CONTROL_AWB_STATE_INACTIVE
* @see #CONTROL_AWB_STATE_SEARCHING
* @see #CONTROL_AWB_STATE_CONVERGED
@@ -377,10 +321,8 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.awbState", int.class);
/**
- * <p>
- * Overall mode of 3A control
- * routines
- * </p>
+ * <p>Overall mode of 3A control
+ * routines</p>
* @see #CONTROL_MODE_OFF
* @see #CONTROL_MODE_AUTO
* @see #CONTROL_MODE_USE_SCENE_MODE
@@ -389,10 +331,8 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.control.mode", int.class);
/**
- * <p>
- * Operation mode for edge
- * enhancement
- * </p>
+ * <p>Operation mode for edge
+ * enhancement</p>
* @see #EDGE_MODE_OFF
* @see #EDGE_MODE_FAST
* @see #EDGE_MODE_HIGH_QUALITY
@@ -401,9 +341,7 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.edge.mode", int.class);
/**
- * <p>
- * Select flash operation mode
- * </p>
+ * <p>Select flash operation mode</p>
* @see #FLASH_MODE_OFF
* @see #FLASH_MODE_SINGLE
* @see #FLASH_MODE_TORCH
@@ -412,10 +350,8 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.flash.mode", int.class);
/**
- * <p>
- * Current state of the flash
- * unit
- * </p>
+ * <p>Current state of the flash
+ * unit</p>
* @see #FLASH_STATE_UNAVAILABLE
* @see #FLASH_STATE_CHARGING
* @see #FLASH_STATE_READY
@@ -425,140 +361,100 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.flash.state", int.class);
/**
- * <p>
- * GPS coordinates to include in output JPEG
- * EXIF
- * </p>
+ * <p>GPS coordinates to include in output JPEG
+ * EXIF</p>
*/
public static final Key<double[]> JPEG_GPS_COORDINATES =
new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
/**
- * <p>
- * 32 characters describing GPS algorithm to
- * include in EXIF
- * </p>
+ * <p>32 characters describing GPS algorithm to
+ * include in EXIF</p>
*/
public static final Key<String> JPEG_GPS_PROCESSING_METHOD =
new Key<String>("android.jpeg.gpsProcessingMethod", String.class);
/**
- * <p>
- * Time GPS fix was made to include in
- * EXIF
- * </p>
+ * <p>Time GPS fix was made to include in
+ * EXIF</p>
*/
public static final Key<Long> JPEG_GPS_TIMESTAMP =
new Key<Long>("android.jpeg.gpsTimestamp", long.class);
/**
- * <p>
- * Orientation of JPEG image to
- * write
- * </p>
+ * <p>Orientation of JPEG image to
+ * write</p>
*/
public static final Key<Integer> JPEG_ORIENTATION =
new Key<Integer>("android.jpeg.orientation", int.class);
/**
- * <p>
- * Compression quality of the final JPEG
- * image
- * </p>
- * <p>
- * 85-95 is typical usage range
- * </p>
+ * <p>Compression quality of the final JPEG
+ * image</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>
+ * <p>Compression quality of JPEG
+ * thumbnail</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
/**
- * <p>
- * Resolution of embedded JPEG
- * thumbnail
- * </p>
+ * <p>Resolution of embedded JPEG
+ * thumbnail</p>
*/
public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
/**
- * <p>
- * Size of the lens aperture
- * </p>
- * <p>
- * Will not be supported on most devices. Can only
- * pick from supported list
- * </p>
+ * <p>Size of the lens aperture</p>
+ * <p>Will not be supported on most devices. Can only
+ * pick from supported list</p>
*/
public static final Key<Float> LENS_APERTURE =
new Key<Float>("android.lens.aperture", float.class);
/**
- * <p>
- * State of lens neutral density
- * filter(s)
- * </p>
- * <p>
- * Will not be supported on most devices. Can only
- * pick from supported list
- * </p>
+ * <p>State of lens neutral density
+ * filter(s)</p>
+ * <p>Will not be supported on most devices. Can only
+ * pick from supported list</p>
*/
public static final Key<Float> LENS_FILTER_DENSITY =
new Key<Float>("android.lens.filterDensity", float.class);
/**
- * <p>
- * Lens optical zoom setting
- * </p>
- * <p>
- * Will not be supported on most devices.
- * </p>
+ * <p>Lens optical zoom setting</p>
+ * <p>Will not be supported on most devices.</p>
*/
public static final Key<Float> LENS_FOCAL_LENGTH =
new Key<Float>("android.lens.focalLength", float.class);
/**
- * <p>
- * Distance to plane of sharpest focus,
- * measured from frontmost surface of the lens
- * </p>
- * <p>
- * Should be zero for fixed-focus cameras
- * </p>
+ * <p>Distance to plane of sharpest focus,
+ * measured from frontmost surface of the lens</p>
+ * <p>Should be zero for fixed-focus cameras</p>
*/
public static final Key<Float> LENS_FOCUS_DISTANCE =
new Key<Float>("android.lens.focusDistance", float.class);
/**
- * <p>
- * The range of scene distances that are in
- * sharp focus (depth of field)
- * </p>
- * <p>
- * If variable focus not supported, can still report
- * fixed depth of field range
- * </p>
+ * <p>The range of scene distances that are in
+ * sharp focus (depth of field)</p>
+ * <p>If variable focus not supported, can still report
+ * fixed depth of field range</p>
*/
public static final Key<float[]> LENS_FOCUS_RANGE =
new Key<float[]>("android.lens.focusRange", float[].class);
/**
- * <p>
- * Whether optical image stabilization is
- * enabled.
- * </p>
- * <p>
- * Will not be supported on most devices.
- * </p>
+ * <p>Whether optical image stabilization is
+ * enabled.</p>
+ * <p>Will not be supported on most devices.</p>
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -566,9 +462,7 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
/**
- * <p>
- * Current lens status
- * </p>
+ * <p>Current lens status</p>
* @see #LENS_STATE_STATIONARY
* @see #LENS_STATE_MOVING
*/
@@ -576,10 +470,8 @@ public final class CaptureResult extends CameraMetadata {
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>
* @see #NOISE_REDUCTION_MODE_OFF
* @see #NOISE_REDUCTION_MODE_FAST
* @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
@@ -588,14 +480,11 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.noiseReduction.mode", int.class);
/**
- * <p>
- * Whether a result given to the framework is the
+ * <p>Whether a result given to the framework is the
* final one for the capture, or only a partial that contains a
* subset of the full set of dynamic metadata
- * values.
- * </p>
- * <p>
- * The entries in the result metadata buffers for a
+ * values.</p>
+ * <p>The entries in the result metadata buffers for a
* single capture may not overlap, except for this entry. The
* FINAL buffers must retain FIFO ordering relative to the
* requests that generate them, so the FINAL buffer for frame 3 must
@@ -603,8 +492,7 @@ public final class CaptureResult extends CameraMetadata {
* before the FINAL buffer for frame 4. PARTIAL buffers may be returned
* in any order relative to other frames, but all PARTIAL buffers for a given
* capture must arrive before the FINAL buffer for that capture. This entry may
- * only be used by the HAL if quirks.usePartialResult is set to 1.
- * </p>
+ * only be used by the HAL if quirks.usePartialResult is set to 1.</p>
*
* <b>Optional</b> - This value may be null on some devices.
*
@@ -614,24 +502,18 @@ public final class CaptureResult extends CameraMetadata {
new Key<Boolean>("android.quirks.partialResult", boolean.class);
/**
- * <p>
- * A frame counter set by the framework. This value monotonically
+ * <p>A frame counter set by the framework. This value monotonically
* increases with every new result (that is, each new result has a unique
- * frameCount value).
- * </p>
- * <p>
- * Reset on release()
- * </p>
+ * frameCount value).</p>
+ * <p>Reset on release()</p>
*/
public static final Key<Integer> REQUEST_FRAME_COUNT =
new Key<Integer>("android.request.frameCount", int.class);
/**
- * <p>
- * An application-specified ID for the current
+ * <p>An application-specified ID for the current
* request. Must be maintained unchanged in output
- * frame
- * </p>
+ * frame</p>
*
* @hide
*/
@@ -639,32 +521,24 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.request.id", int.class);
/**
- * <p>
- * (x, y, width, height).
- * </p><p>
- * A rectangle with the top-level corner of (x,y) and size
+ * <p>(x, y, width, height).</p>
+ * <p>A rectangle with the top-level corner of (x,y) and size
* (width, height). The region of the sensor that is used for
* output. Each stream must use this rectangle to produce its
* output, cropping to a smaller region if necessary to
- * maintain the stream's aspect ratio.
- * </p><p>
- * HAL2.x uses only (x, y, width)
- * </p>
- * <p>
- * Any additional per-stream cropping must be done to
- * maximize the final pixel area of the stream.
- * </p><p>
- * For example, if the crop region is set to a 4:3 aspect
+ * maintain the stream's aspect ratio.</p>
+ * <p>HAL2.x uses only (x, y, width)</p>
+ * <p>Any additional per-stream cropping must be done to
+ * maximize the final pixel area of the stream.</p>
+ * <p>For example, if the crop region is set to a 4:3 aspect
* ratio, then 4:3 streams should use the exact crop
* region. 16:9 streams should further crop vertically
- * (letterbox).
- * </p><p>
- * Conversely, if the crop region is set to a 16:9, then 4:3
+ * (letterbox).</p>
+ * <p>Conversely, if the crop region is set to a 16:9, then 4:3
* outputs should crop horizontally (pillarbox), and 16:9
* streams should match exactly. These additional crops must
- * be centered within the crop region.
- * </p><p>
- * The output streams must maintain square pixels at all
+ * be centered within the crop region.</p>
+ * <p>The output streams must maintain square pixels at all
* times, no matter what the relative aspect ratios of the
* crop region and the stream are. Negative values for
* corner are allowed for raw output if full pixel array is
@@ -675,77 +549,55 @@ public final class CaptureResult extends CameraMetadata {
* be set to be smaller than floor( activeArraySize.width /
* android.scaler.maxDigitalZoom ) and floor(
* activeArraySize.height / android.scaler.maxDigitalZoom),
- * respectively.
- * </p>
+ * respectively.</p>
*/
public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
/**
- * <p>
- * Duration each pixel is exposed to
- * light.
- * </p><p>
- * If the sensor can't expose this exact duration, it should shorten the
- * duration exposed to the nearest possible value (rather than expose longer).
- * </p>
- * <p>
- * 1/10000 - 30 sec range. No bulb mode
- * </p>
+ * <p>Duration each pixel is exposed to
+ * light.</p>
+ * <p>If the sensor can't expose this exact duration, it should shorten the
+ * duration exposed to the nearest possible value (rather than expose longer).</p>
+ * <p>1/10000 - 30 sec range. No bulb mode</p>
*/
public static final Key<Long> SENSOR_EXPOSURE_TIME =
new Key<Long>("android.sensor.exposureTime", long.class);
/**
- * <p>
- * Duration from start of frame exposure to
- * start of next frame exposure
- * </p>
- * <p>
- * Exposure time has priority, so duration is set to
- * max(duration, exposure time + overhead)
- * </p>
+ * <p>Duration from start of frame exposure to
+ * start of next frame exposure</p>
+ * <p>Exposure time has priority, so duration is set to
+ * max(duration, exposure time + overhead)</p>
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
/**
- * <p>
- * Gain applied to image data. Must be
+ * <p>Gain applied to image data. Must be
* implemented through analog gain only if set to values
- * below 'maximum analog sensitivity'.
- * </p><p>
- * If the sensor can't apply this exact gain, it should lessen the
- * gain to the nearest possible value (rather than gain more).
- * </p>
- * <p>
- * ISO 12232:2006 REI method
- * </p>
+ * below 'maximum analog sensitivity'.</p>
+ * <p>If the sensor can't apply this exact gain, it should lessen the
+ * gain to the nearest possible value (rather than gain more).</p>
+ * <p>ISO 12232:2006 REI method</p>
*/
public static final Key<Integer> SENSOR_SENSITIVITY =
new Key<Integer>("android.sensor.sensitivity", int.class);
/**
- * <p>
- * Time at start of exposure of first
- * row
- * </p>
- * <p>
- * Monotonic, should be synced to other timestamps in
- * system
- * </p>
+ * <p>Time at start of exposure of first
+ * row</p>
+ * <p>Monotonic, should be synced to other timestamps in
+ * system</p>
*/
public static final Key<Long> SENSOR_TIMESTAMP =
new Key<Long>("android.sensor.timestamp", long.class);
/**
- * <p>
- * The temperature of the sensor, sampled at the time
- * exposure began for this frame.
- * </p><p>
- * The thermal diode being queried should be inside the sensor PCB, or
- * somewhere close to it.
- * </p>
+ * <p>The temperature of the sensor, sampled at the time
+ * exposure began for this frame.</p>
+ * <p>The thermal diode being queried should be inside the sensor PCB, or
+ * somewhere close to it.</p>
*
* <b>Optional</b> - This value may be null on some devices.
*
@@ -757,16 +609,12 @@ public final class CaptureResult extends CameraMetadata {
new Key<Float>("android.sensor.temperature", float.class);
/**
- * <p>
- * State of the face detector
- * unit
- * </p>
- * <p>
- * Whether face detection is enabled, and whether it
+ * <p>State of 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
* fields. Value must be one of the
- * android.statistics.info.availableFaceDetectModes.
- * </p>
+ * android.statistics.info.availableFaceDetectModes.</p>
* @see #STATISTICS_FACE_DETECT_MODE_OFF
* @see #STATISTICS_FACE_DETECT_MODE_SIMPLE
* @see #STATISTICS_FACE_DETECT_MODE_FULL
@@ -775,13 +623,9 @@ public final class CaptureResult extends CameraMetadata {
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>Only available if faceDetectMode == FULL</p>
*
* @hide
*/
@@ -789,13 +633,9 @@ public final class CaptureResult extends CameraMetadata {
new Key<int[]>("android.statistics.faceIds", int[].class);
/**
- * <p>
- * List of landmarks for detected
- * faces
- * </p>
- * <p>
- * Only available if faceDetectMode == FULL
- * </p>
+ * <p>List of landmarks for detected
+ * faces</p>
+ * <p>Only available if faceDetectMode == FULL</p>
*
* @hide
*/
@@ -803,13 +643,9 @@ public final class CaptureResult extends CameraMetadata {
new Key<int[]>("android.statistics.faceLandmarks", int[].class);
/**
- * <p>
- * List of the bounding rectangles for detected
- * faces
- * </p>
- * <p>
- * Only available if faceDetectMode != OFF
- * </p>
+ * <p>List of the bounding rectangles for detected
+ * faces</p>
+ * <p>Only available if faceDetectMode != OFF</p>
*
* @hide
*/
@@ -817,14 +653,10 @@ public final class CaptureResult extends CameraMetadata {
new Key<android.graphics.Rect[]>("android.statistics.faceRectangles", android.graphics.Rect[].class);
/**
- * <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>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>
*
* @hide
*/
@@ -832,80 +664,59 @@ public final class CaptureResult extends CameraMetadata {
new Key<byte[]>("android.statistics.faceScores", byte[].class);
/**
- * <p>
- * A low-resolution map of lens shading, per
- * color channel
- * </p>
- * <p>
- * Assume bilinear interpolation of map. The least
+ * <p>A low-resolution map of lens shading, per
+ * color channel</p>
+ * <p>Assume bilinear interpolation of map. The least
* shaded section of the image should have a gain factor
* of 1; all other sections should have gains above 1.
* the map should be on the order of 30-40 rows, and
- * must be smaller than 64x64.
- * </p><p>
- * When android.colorCorrection.mode = TRANSFORM_MATRIX, the map
- * must take into account the colorCorrection settings.
- * </p>
+ * must be smaller than 64x64.</p>
+ * <p>When android.colorCorrection.mode = TRANSFORM_MATRIX, the map
+ * must take into account the colorCorrection settings.</p>
*/
public static final Key<float[]> STATISTICS_LENS_SHADING_MAP =
new Key<float[]>("android.statistics.lensShadingMap", float[].class);
/**
- * <p>
- * The best-fit color channel gains calculated
- * by the HAL's statistics units for the current output frame
- * </p>
- * <p>
- * This may be different than the gains used for this frame,
+ * <p>The best-fit color channel gains calculated
+ * by the HAL's statistics units for the current output frame</p>
+ * <p>This may be different than the gains used for this frame,
* since statistics processing on data from a new frame
* typically completes after the transform has already been
- * applied to that frame.
- * </p><p>
- * The 4 channel gains are defined in Bayer domain,
- * see android.colorCorrection.gains for details.
- * </p><p>
- * This value should always be calculated by the AWB block,
- * regardless of the android.control.* current values.
- * </p>
+ * applied to that frame.</p>
+ * <p>The 4 channel gains are defined in Bayer domain,
+ * see android.colorCorrection.gains for details.</p>
+ * <p>This value should always be calculated by the AWB block,
+ * regardless of the android.control.* current values.</p>
*/
public static final Key<float[]> STATISTICS_PREDICTED_COLOR_GAINS =
new Key<float[]>("android.statistics.predictedColorGains", float[].class);
/**
- * <p>
- * The best-fit color transform matrix estimate
+ * <p>The best-fit color transform matrix estimate
* calculated by the HAL's statistics units for the current
- * output frame
- * </p>
- * <p>
- * The HAL must provide the estimate from its
+ * output frame</p>
+ * <p>The HAL must provide the estimate from its
* statistics unit on the white balance transforms to use
* for the next frame. These are the values the HAL believes
* are the best fit for the current output frame. This may
* be different than the transform used for this frame, since
* statistics processing on data from a new frame typically
* completes after the transform has already been applied to
- * that frame.
- * </p><p>
- * These estimates must be provided for all frames, even if
- * capture settings and color transforms are set by the application.
- * </p><p>
- * This value should always be calculated by the AWB block,
- * regardless of the android.control.* current values.
- * </p>
+ * that frame.</p>
+ * <p>These estimates must be provided for all frames, even if
+ * capture settings and color transforms are set by the application.</p>
+ * <p>This value should always be calculated by the AWB block,
+ * regardless of the android.control.* current values.</p>
*/
public static final Key<Rational[]> STATISTICS_PREDICTED_COLOR_TRANSFORM =
new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class);
/**
- * <p>
- * The HAL estimated scene illumination lighting
- * frequency
- * </p>
- * <p>
- * Report NONE if there doesn't appear to be flickering
- * illumination
- * </p>
+ * <p>The HAL estimated scene illumination lighting
+ * frequency</p>
+ * <p>Report NONE if there doesn't appear to be flickering
+ * illumination</p>
* @see #STATISTICS_SCENE_FLICKER_NONE
* @see #STATISTICS_SCENE_FLICKER_50HZ
* @see #STATISTICS_SCENE_FLICKER_60HZ
@@ -914,56 +725,40 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.statistics.sceneFlicker", int.class);
/**
- * <p>
- * Table mapping blue input values to output
- * values
- * </p>
- * <p>
- * Tonemapping / contrast / gamma curve for the blue
- * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
- * </p><p>
- * See android.tonemap.curveRed for more details.
- * </p>
+ * <p>Table mapping blue input values to output
+ * values</p>
+ * <p>Tonemapping / contrast / gamma curve for the blue
+ * channel, to use when android.tonemap.mode is CONTRAST_CURVE.</p>
+ * <p>See android.tonemap.curveRed for more details.</p>
*/
public static final Key<float[]> TONEMAP_CURVE_BLUE =
new Key<float[]>("android.tonemap.curveBlue", float[].class);
/**
- * <p>
- * Table mapping green input values to output
- * values
- * </p>
- * <p>
- * Tonemapping / contrast / gamma curve for the green
- * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
- * </p><p>
- * See android.tonemap.curveRed for more details.
- * </p>
+ * <p>Table mapping green input values to output
+ * values</p>
+ * <p>Tonemapping / contrast / gamma curve for the green
+ * channel, to use when android.tonemap.mode is CONTRAST_CURVE.</p>
+ * <p>See android.tonemap.curveRed for more details.</p>
*/
public static final Key<float[]> TONEMAP_CURVE_GREEN =
new Key<float[]>("android.tonemap.curveGreen", float[].class);
/**
- * <p>
- * Table mapping red input values to output
- * values
- * </p>
- * <p>
- * Tonemapping / contrast / gamma curve for the red
- * channel, to use when android.tonemap.mode is CONTRAST_CURVE.
- * </p><p>
- * Since the input and output ranges may vary depending on
+ * <p>Table mapping red input values to output
+ * values</p>
+ * <p>Tonemapping / contrast / gamma curve for the red
+ * channel, to use when android.tonemap.mode is CONTRAST_CURVE.</p>
+ * <p>Since the input and output ranges may vary depending on
* the camera pipeline, the input and output pixel values
* are represented by normalized floating-point values
- * between 0 and 1, with 0 == black and 1 == white.
- * </p><p>
- * The curve should be linearly interpolated between the
+ * between 0 and 1, with 0 == black and 1 == white.</p>
+ * <p>The curve should be linearly interpolated between the
* defined points. The points will be listed in increasing
* order of P_IN. For example, if the array is: [0.0, 0.0,
- * 0.3, 0.5, 1.0, 1.0], then the input->output mapping
- * for a few sample points would be: 0 -> 0, 0.15 ->
- * 0.25, 0.3 -> 0.5, 0.5 -> 0.64
- * </p>
+ * 0.3, 0.5, 1.0, 1.0], then the input-&gt;output mapping
+ * for a few sample points would be: 0 -&gt; 0, 0.15 -&gt;
+ * 0.25, 0.3 -&gt; 0.5, 0.5 -&gt; 0.64</p>
*/
public static final Key<float[]> TONEMAP_CURVE_RED =
new Key<float[]>("android.tonemap.curveRed", float[].class);
@@ -977,20 +772,16 @@ public final class CaptureResult extends CameraMetadata {
new Key<Integer>("android.tonemap.mode", int.class);
/**
- * <p>
- * This LED is nominally used to indicate to the user
+ * <p>This LED is nominally used to indicate to the user
* that the camera is powered on and may be streaming images back to the
* Application Processor. In certain rare circumstances, the OS may
* disable this when video is processed locally and not transmitted to
- * any untrusted applications.
- * </p><p>
- * In particular, the LED *must* always be on when the data could be
- * transmitted off the device. The LED *should* always be on whenever
- * data is stored locally on the device.
- * </p><p>
- * The LED *may* be off if a trusted application is using the data that
- * doesn't violate the above rules.
- * </p>
+ * any untrusted applications.</p>
+ * <p>In particular, the LED <em>must</em> always be on when the data could be
+ * transmitted off the device. The LED <em>should</em> always be on whenever
+ * data is stored locally on the device.</p>
+ * <p>The LED <em>may</em> be off if a trusted application is using the data that
+ * doesn't violate the above rules.</p>
*
* @hide
*/
@@ -998,28 +789,11 @@ public final class CaptureResult extends CameraMetadata {
new Key<Boolean>("android.led.transmit", boolean.class);
/**
- * <p>
- * Whether black-level compensation is locked
- * to its current values, or is free to vary
- * </p>
- * <p>
- * When set to ON, the values used for black-level
- * compensation must not change until the lock is set to
- * OFF
- * </p><p>
- * Since changes to certain capture parameters (such as
- * exposure time) may require resetting of black level
- * compensation, the HAL must report whether setting the
- * black level lock was successful in the output result
- * metadata.
- * </p><p>
- * The black level locking must happen at the sensor, and not at the ISP.
- * If for some reason black level locking is no longer legal (for example,
- * the analog gain has changed, which forces black levels to be
- * recalculated), then the HAL is free to override this request (and it
- * must report 'OFF' when this does happen) until the next time locking
- * is legal again.
- * </p>
+ * <p>Whether black-level compensation is locked
+ * to its current values, or is free to vary</p>
+ * <p>Whether the black level offset was locked for this frame.
+ * Should be ON if android.blackLevel.lock was ON in the capture request,
+ * unless a change in capture settings forced a black level reset.</p>
*/
public static final Key<Boolean> BLACK_LEVEL_LOCK =
new Key<Boolean>("android.blackLevel.lock", boolean.class);
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 3c67bf9..36dd2fdfb 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -26,7 +26,7 @@ import android.net.wifi.WifiManager;
import android.os.Build;
import android.telephony.TelephonyManager;
-import com.android.internal.util.Objects;
+import java.util.Objects;
/**
* Network definition that includes strong identity. Analogous to combining
@@ -60,7 +60,7 @@ public class NetworkIdentity {
@Override
public int hashCode() {
- return Objects.hashCode(mType, mSubType, mSubscriberId, mNetworkId, mRoaming);
+ return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming);
}
@Override
@@ -68,8 +68,8 @@ public class NetworkIdentity {
if (obj instanceof NetworkIdentity) {
final NetworkIdentity ident = (NetworkIdentity) obj;
return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
- && Objects.equal(mSubscriberId, ident.mSubscriberId)
- && Objects.equal(mNetworkId, ident.mNetworkId);
+ && Objects.equals(mSubscriberId, ident.mSubscriberId)
+ && Objects.equals(mNetworkId, ident.mNetworkId);
}
return false;
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 441db7a..10c686b 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -21,7 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Objects;
+import java.util.Objects;
/**
* Policy for networks matching a {@link NetworkTemplate}, including usage cycle
@@ -146,7 +146,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
@Override
public int hashCode() {
- return Objects.hashCode(template, cycleDay, cycleTimezone, warningBytes, limitBytes,
+ return Objects.hash(template, cycleDay, cycleTimezone, warningBytes, limitBytes,
lastWarningSnooze, lastLimitSnooze, metered, inferred);
}
@@ -159,8 +159,8 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
&& lastWarningSnooze == other.lastWarningSnooze
&& lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
&& inferred == other.inferred
- && Objects.equal(cycleTimezone, other.cycleTimezone)
- && Objects.equal(template, other.template);
+ && Objects.equals(cycleTimezone, other.cycleTimezone)
+ && Objects.equals(template, other.template);
}
return false;
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 9cb904d..a7aae2a 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -23,12 +23,12 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Objects;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Objects;
/**
* Collection of active network statistics. Can contain summary details across
@@ -337,7 +337,7 @@ public class NetworkStats implements Parcelable {
public int findIndex(String iface, int uid, int set, int tag) {
for (int i = 0; i < size; i++) {
if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
- && Objects.equal(iface, this.iface[i])) {
+ && Objects.equals(iface, this.iface[i])) {
return i;
}
}
@@ -362,7 +362,7 @@ public class NetworkStats implements Parcelable {
}
if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
- && Objects.equal(iface, this.iface[i])) {
+ && Objects.equals(iface, this.iface[i])) {
return i;
}
}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index c189ba4..27197cc 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -34,8 +34,9 @@ import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Objects;
/**
* Template definition used to generically match {@link NetworkIdentity},
@@ -176,7 +177,7 @@ public class NetworkTemplate implements Parcelable {
@Override
public int hashCode() {
- return Objects.hashCode(mMatchRule, mSubscriberId, mNetworkId);
+ return Objects.hash(mMatchRule, mSubscriberId, mNetworkId);
}
@Override
@@ -184,8 +185,8 @@ public class NetworkTemplate implements Parcelable {
if (obj instanceof NetworkTemplate) {
final NetworkTemplate other = (NetworkTemplate) obj;
return mMatchRule == other.mMatchRule
- && Objects.equal(mSubscriberId, other.mSubscriberId)
- && Objects.equal(mNetworkId, other.mNetworkId);
+ && Objects.equals(mSubscriberId, other.mSubscriberId)
+ && Objects.equals(mNetworkId, other.mNetworkId);
}
return false;
}
@@ -235,7 +236,7 @@ public class NetworkTemplate implements Parcelable {
return true;
} else {
return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType))
- && Objects.equal(mSubscriberId, ident.mSubscriberId));
+ && Objects.equals(mSubscriberId, ident.mSubscriberId));
}
}
@@ -280,7 +281,7 @@ public class NetworkTemplate implements Parcelable {
private boolean matchesWifi(NetworkIdentity ident) {
switch (ident.mType) {
case TYPE_WIFI:
- return Objects.equal(
+ return Objects.equals(
removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId));
default:
return false;
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index cfe5f27..db71279 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -63,4 +63,18 @@ public class X509TrustManagerExtensions {
String host) throws CertificateException {
return mDelegate.checkServerTrusted(chain, authType, host);
}
+
+ /**
+ * Checks whether a CA certificate is added by an user.
+ *
+ * <p>Since {@link X509TrustManager#checkServerTrusted} allows its parameter {@code chain} to
+ * chain up to user-added CA certificates, this method can be used to perform additional
+ * policies for user-added CA certificates.
+ *
+ * @return {@code true} to indicate that the certificate was added by the user, {@code false}
+ * otherwise.
+ */
+ public boolean isUserAddedCertificate(X509Certificate cert) {
+ return mDelegate.isUserAddedCertificate(cert);
+ }
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 8414738..10988c6 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -25,6 +25,7 @@ import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
+import android.nfc.INfcUnlockSettings;
import android.os.Bundle;
/**
@@ -35,6 +36,7 @@ interface INfcAdapter
INfcTag getNfcTagInterface();
INfcCardEmulation getNfcCardEmulationInterface();
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
+ INfcUnlockSettings getNfcUnlockSettingsInterface();
int getState();
boolean disable(boolean saveState);
diff --git a/core/java/android/nfc/INfcUnlockSettings.aidl b/core/java/android/nfc/INfcUnlockSettings.aidl
new file mode 100644
index 0000000..649eeed
--- /dev/null
+++ b/core/java/android/nfc/INfcUnlockSettings.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.nfc.Tag;
+import java.util.List;
+
+/**
+ * Interface to NFC unlock functionality.
+ *
+ * @hide
+ */
+interface INfcUnlockSettings {
+
+ /**
+ * Checks the validity of the tag and attempts to unlock the screen.
+ *
+ * @return true if the screen was successfuly unlocked.
+ */
+ boolean tryUnlock(int userId, in Tag tag);
+
+ /**
+ * Registers the given tag as an unlock tag. Subsequent calls to {@code tryUnlock}
+ * with the same {@code tag} should succeed.
+ *
+ * @return true if the tag was successfully registered.
+ */
+ boolean registerTag(int userId, in Tag tag);
+
+ /**
+ * Deregisters the tag with the corresponding timestamp.
+ * Subsequent calls to {@code tryUnlock} with the same tag should fail.
+ *
+ * @return true if the tag was successfully deleted.
+ */
+ boolean deregisterTag(int userId, long timestamp);
+
+ /**
+ * Used for user-visible rendering of registered tags.
+ *
+ * @return a list of the times in millis since epoch when the registered tags were paired.
+ */
+ long[] getTagRegistryTimes(int userId);
+
+ /**
+ * Determines the state of the NFC unlock feature.
+ *
+ * @return true if NFC unlock is enabled.
+ */
+ boolean getNfcUnlockEnabled(int userId);
+
+ /**
+ * Sets the state [ON | OFF] of the NFC unlock feature.
+ */
+ void setNfcUnlockEnabled(int userId, boolean enabled);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 6743c6c..e8b7437 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -292,6 +292,7 @@ public final class NfcAdapter {
static INfcAdapter sService;
static INfcTag sTagService;
static INfcCardEmulation sCardEmulationService;
+ static INfcUnlockSettings sNfcUnlockSettingsService;
/**
* The NfcAdapter object for each application context.
@@ -432,6 +433,13 @@ public final class NfcAdapter {
throw new UnsupportedOperationException();
}
+ try {
+ sNfcUnlockSettingsService = sService.getNfcUnlockSettingsInterface();
+ } catch (RemoteException e) {
+ Log.e(TAG, "could not retrieve NFC unlock settings service");
+ sNfcUnlockSettingsService = null;
+ }
+
sIsInitialized = true;
}
if (context == null) {
@@ -549,6 +557,22 @@ public final class NfcAdapter {
}
/**
+ * Returns the binder interface to the NFC unlock service.
+ *
+ * @throws UnsupportedOperationException if the service is not available.
+ * @hide
+ */
+ public INfcUnlockSettings getNfcUnlockSettingsService() throws UnsupportedOperationException {
+ isEnabled();
+
+ if (sNfcUnlockSettingsService == null) {
+ throw new UnsupportedOperationException("NfcUnlockSettingsService not available");
+ }
+
+ return sNfcUnlockSettingsService;
+ }
+
+ /**
* NFC service dead - attempt best effort recovery
* @hide
*/
diff --git a/core/java/android/nfc/NfcUnlock.java b/core/java/android/nfc/NfcUnlock.java
new file mode 100644
index 0000000..82dcd96
--- /dev/null
+++ b/core/java/android/nfc/NfcUnlock.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * Provides an interface to read and update NFC unlock settings.
+ * <p/>
+ * Allows system services (currently exclusively LockSettingsService) to
+ * register NFC tags to be used to unlock the device, as well as the ability
+ * to enable/disable the service entirely.
+ *
+ */
+public class NfcUnlock {
+
+ /**
+ * Action to unlock the device.
+ *
+ * @hide
+ */
+ public static final String ACTION_NFC_UNLOCK = "android.nfc.ACTION_NFC_UNLOCK";
+ /**
+ * Permission to unlock the device.
+ *
+ * @hide
+ */
+ public static final String NFC_UNLOCK_PERMISSION = "android.permission.NFC_UNLOCK";
+
+ /**
+ * Property to enable NFC Unlock
+ *
+ * @hide
+ */
+ public static final String PROPERTY = "ro.com.android.nfc.unlock";
+
+ private static final String TAG = "NfcUnlock";
+ private static HashMap<Context, NfcUnlock> sNfcUnlocks = new HashMap<Context, NfcUnlock>();
+
+ private final Context mContext;
+ private final boolean mEnabled;
+ private INfcUnlockSettings sService;
+
+ private NfcUnlock(Context context, INfcUnlockSettings service) {
+ this.mContext = checkNotNull(context);
+ this.sService = checkNotNull(service);
+ this.mEnabled = getPropertyEnabled();
+ }
+
+ /**
+ * Returns an instance of {@link NfcUnlock}.
+ */
+ public static synchronized NfcUnlock getInstance(NfcAdapter nfcAdapter) {
+ Context context = nfcAdapter.getContext();
+ if (context == null) {
+ Log.e(TAG, "NfcAdapter context is null");
+ throw new UnsupportedOperationException();
+ }
+
+ NfcUnlock manager = sNfcUnlocks.get(context);
+ if (manager == null) {
+ INfcUnlockSettings service = nfcAdapter.getNfcUnlockSettingsService();
+ manager = new NfcUnlock(context, service);
+ sNfcUnlocks.put(context, manager);
+ }
+
+ return manager;
+ }
+
+ /**
+ * Registers the given {@code tag} as an unlock tag.
+ *
+ * @return true if the tag was successfully registered.
+ * @hide
+ */
+ public boolean registerTag(Tag tag) {
+ enforcePropertyEnabled();
+
+ int currentUser = ActivityManager.getCurrentUser();
+
+ try {
+ return sService.registerTag(currentUser, tag);
+ } catch (RemoteException e) {
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NfcUnlockSettingsService");
+ return false;
+ }
+
+ try {
+ return sService.registerTag(currentUser, tag);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach NfcUnlockSettingsService", ee);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Deregisters the given {@code tag} as an unlock tag.
+ *
+ * @return true if the tag was successfully deregistered.
+ * @hide
+ */
+ public boolean deregisterTag(long timestamp) {
+ enforcePropertyEnabled();
+ int currentUser = ActivityManager.getCurrentUser();
+
+ try {
+ return sService.deregisterTag(currentUser, timestamp);
+ } catch (RemoteException e) {
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NfcUnlockSettingsService");
+ return false;
+ }
+
+ try {
+ return sService.deregisterTag(currentUser, timestamp);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach NfcUnlockSettingsService", ee);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Determines the enable state of the NFC unlock feature.
+ *
+ * @return true if NFC unlock is enabled.
+ */
+ public boolean getNfcUnlockEnabled() {
+ enforcePropertyEnabled();
+ int currentUser = ActivityManager.getCurrentUser();
+
+ try {
+ return sService.getNfcUnlockEnabled(currentUser);
+ } catch (RemoteException e) {
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NfcUnlockSettingsService");
+ return false;
+ }
+
+ try {
+ return sService.getNfcUnlockEnabled(currentUser);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach NfcUnlockSettingsService", ee);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Set the enable state of the NFC unlock feature.
+ *
+ * @return true if the setting was successfully persisted.
+ * @hide
+ */
+ public boolean setNfcUnlockEnabled(boolean enabled) {
+ enforcePropertyEnabled();
+ int currentUser = ActivityManager.getCurrentUser();
+
+ try {
+ sService.setNfcUnlockEnabled(currentUser, enabled);
+ return true;
+ } catch (RemoteException e) {
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NfcUnlockSettingsService");
+ return false;
+ }
+
+ try {
+ sService.setNfcUnlockEnabled(currentUser, enabled);
+ return true;
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach NfcUnlockSettingsService", ee);
+ return false;
+ }
+
+ }
+ }
+
+ /**
+ * Returns a list of times (in millis since epoch) corresponding to when
+ * unlock tags were registered.
+ *
+ * @hide
+ */
+ @Nullable
+ public long[] getTagRegistryTimes() {
+ enforcePropertyEnabled();
+ int currentUser = ActivityManager.getCurrentUser();
+
+ try {
+ return sService.getTagRegistryTimes(currentUser);
+ } catch (RemoteException e) {
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NfcUnlockSettingsService");
+ return null;
+ }
+
+ try {
+ return sService.getTagRegistryTimes(currentUser);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach NfcUnlockSettingsService", ee);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static boolean getPropertyEnabled() {
+ return SystemProperties.get(PROPERTY).equals("ON");
+ }
+
+ private void recoverService() {
+ NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+ sService = adapter.getNfcUnlockSettingsService();
+ }
+
+
+ private void enforcePropertyEnabled() {
+ if (!mEnabled) {
+ throw new UnsupportedOperationException("NFC Unlock property is not enabled");
+ }
+ }
+}
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index f2cd232..0d261d1 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -204,6 +204,14 @@ public final class Tag implements Parcelable {
}
/**
+ * For use by NfcService only.
+ * @hide
+ */
+ public int[] getTechCodeList() {
+ return mTechList;
+ }
+
+ /**
* Get the Tag Identifier (if it has one).
* <p>The tag identifier is a low level serial number, used for anti-collision
* and identification.
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 0285cb9..06565f1 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -216,7 +216,7 @@ public class StorageVolume implements Parcelable {
return -1;
}
try {
- return Integer.parseInt(mUuid.replace("-", ""), 16);
+ return (int)Long.parseLong(mUuid.replace("-", ""), 16);
} catch (NumberFormatException e) {
return -1;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index a6f23a8..3b0d7ff 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -86,10 +86,8 @@ public class CallLog {
public static final String ALLOW_VOICEMAILS_PARAM_KEY = "allow_voicemails";
/**
- * Content uri with {@link #ALLOW_VOICEMAILS_PARAM_KEY} set. This can directly be used to
- * access call log entries that includes voicemail records.
- *
- * @hide
+ * Content uri used to access call log entries, including voicemail records. You must have
+ * the READ_CALL_LOG and WRITE_CALL_LOG permissions to read and write to the call log.
*/
public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon()
.appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true")
@@ -124,10 +122,7 @@ public class CallLog {
public static final int OUTGOING_TYPE = 2;
/** Call log type for missed calls. */
public static final int MISSED_TYPE = 3;
- /**
- * Call log type for voicemails.
- * @hide
- */
+ /** Call log type for voicemails. */
public static final int VOICEMAIL_TYPE = 4;
/**
@@ -168,8 +163,6 @@ public class CallLog {
* <P>
* Type: TEXT
* </P>
- *
- * @hide
*/
public static final String COUNTRY_ISO = "countryiso";
@@ -220,7 +213,6 @@ public class CallLog {
/**
* URI of the voicemail entry. Populated only for {@link #VOICEMAIL_TYPE}.
* <P>Type: TEXT</P>
- * @hide
*/
public static final String VOICEMAIL_URI = "voicemail_uri";
@@ -238,51 +230,48 @@ public class CallLog {
* <p>
* The string represents a city, state, or country associated with the number.
* <P>Type: TEXT</P>
- * @hide
*/
public static final String GEOCODED_LOCATION = "geocoded_location";
/**
* The cached URI to look up the contact associated with the phone number, if it exists.
- * This value is not guaranteed to be current, if the contact information
- * associated with this number has changed.
+ * This value may not be current if the contact information associated with this number
+ * has changed.
* <P>Type: TEXT</P>
- * @hide
*/
public static final String CACHED_LOOKUP_URI = "lookup_uri";
/**
* The cached phone number of the contact which matches this entry, if it exists.
- * This value is not guaranteed to be current, if the contact information
- * associated with this number has changed.
+ * This value may not be current if the contact information associated with this number
+ * has changed.
* <P>Type: TEXT</P>
- * @hide
*/
public static final String CACHED_MATCHED_NUMBER = "matched_number";
/**
- * The cached normalized version of the phone number, if it exists.
- * This value is not guaranteed to be current, if the contact information
- * associated with this number has changed.
+ * The cached normalized(E164) version of the phone number, if it exists.
+ * This value may not be current if the contact information associated with this number
+ * has changed.
* <P>Type: TEXT</P>
- * @hide
*/
public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
/**
* The cached photo id of the picture associated with the phone number, if it exists.
- * This value is not guaranteed to be current, if the contact information
- * associated with this number has changed.
+ * This value may not be current if the contact information associated with this number
+ * has changed.
* <P>Type: INTEGER (long)</P>
- * @hide
*/
public static final String CACHED_PHOTO_ID = "photo_id";
/**
- * The cached formatted phone number.
- * This value is not guaranteed to be present.
+ * The cached phone number, formatted with formatting rules based on the country the
+ * user was in when the call was made or received.
+ * This value is not guaranteed to be present, and may not be current if the contact
+ * information associated with this number
+ * has changed.
* <P>Type: TEXT</P>
- * @hide
*/
public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index f29161f..1b5cc68 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -164,8 +164,6 @@ public final class ContactsContract {
* {@link Contacts#CONTENT_STREQUENT_FILTER_URI}, which requires the ContactsProvider to
* return only phone-related results. For example, frequently contacted person list should
* include persons contacted via phone (not email, sms, etc.)
- *
- * @hide
*/
public static final String STREQUENT_PHONE_ONLY = "strequent_phone_only";
@@ -190,8 +188,6 @@ public final class ContactsContract {
* {@link CommonDataKinds.Email#CONTENT_URI}, and
* {@link CommonDataKinds.StructuredPostal#CONTENT_URI}.
* This enables a content provider to remove duplicate entries in results.
- *
- * @hide
*/
public static final String REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries";
@@ -248,30 +244,21 @@ public final class ContactsContract {
public static final String KEY_AUTHORIZED_URI = "authorized_uri";
}
- /**
- * @hide
- */
public static final class Preferences {
/**
* A key in the {@link android.provider.Settings android.provider.Settings} provider
* that stores the preferred sorting order for contacts (by given name vs. by family name).
- *
- * @hide
*/
public static final String SORT_ORDER = "android.contacts.SORT_ORDER";
/**
* The value for the SORT_ORDER key corresponding to sorting by given name first.
- *
- * @hide
*/
public static final int SORT_ORDER_PRIMARY = 1;
/**
* The value for the SORT_ORDER key corresponding to sorting by family name first.
- *
- * @hide
*/
public static final int SORT_ORDER_ALTERNATIVE = 2;
@@ -279,22 +266,16 @@ public final class ContactsContract {
* A key in the {@link android.provider.Settings android.provider.Settings} provider
* that stores the preferred display order for contacts (given name first vs. family
* name first).
- *
- * @hide
*/
public static final String DISPLAY_ORDER = "android.contacts.DISPLAY_ORDER";
/**
* The value for the DISPLAY_ORDER key corresponding to showing the given name first.
- *
- * @hide
*/
public static final int DISPLAY_ORDER_PRIMARY = 1;
/**
* The value for the DISPLAY_ORDER key corresponding to showing the family name first.
- *
- * @hide
*/
public static final int DISPLAY_ORDER_ALTERNATIVE = 2;
}
@@ -824,10 +805,9 @@ public final class ContactsContract {
public static final String STARRED = "starred";
/**
- * The position at which the contact is pinned. If {@link PinnedPositions.UNPINNED},
+ * The position at which the contact is pinned. If {@link PinnedPositions#UNPINNED},
* the contact is not pinned. Also see {@link PinnedPositions}.
* <P>Type: INTEGER </P>
- * @hide
*/
public static final String PINNED = "pinned";
@@ -1467,17 +1447,43 @@ public final class ContactsContract {
* Base {@link Uri} for referencing multiple {@link Contacts} entry,
* created by appending {@link #LOOKUP_KEY} using
* {@link Uri#withAppendedPath(Uri, String)}. The lookup keys have to be
- * encoded and joined with the colon (":") separator. The resulting string
- * has to be encoded again. Provides
- * {@link OpenableColumns} columns when queried, or returns the
+ * joined with the colon (":") separator, and the resulting string encoded.
+ *
+ * Provides {@link OpenableColumns} columns when queried, or returns the
* referenced contact formatted as a vCard when opened through
* {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
*
- * This is private API because we do not have a well-defined way to
- * specify several entities yet. The format of this Uri might change in the future
- * or the Uri might be completely removed.
+ * <p>
+ * Usage example:
+ * <dl>
+ * <dt>The following code snippet creates a multi-vcard URI that references all the
+ * contacts in a user's database.</dt>
+ * <dd>
+ *
+ * <pre>
+ * public Uri getAllContactsVcardUri() {
+ * Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
+ * new String[] {Contacts.LOOKUP_KEY}, null, null, null);
+ * if (cursor == null) {
+ * return null;
+ * }
+ * try {
+ * StringBuilder uriListBuilder = new StringBuilder();
+ * int index = 0;
+ * while (cursor.moveToNext()) {
+ * if (index != 0) uriListBuilder.append(':');
+ * uriListBuilder.append(cursor.getString(0));
+ * index++;
+ * }
+ * return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI,
+ * Uri.encode(uriListBuilder.toString()));
+ * } finally {
+ * cursor.close();
+ * }
+ * }
+ * </pre>
*
- * @hide
+ * </p>
*/
public static final Uri CONTENT_MULTI_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
"as_multi_vcard");
@@ -4791,11 +4797,11 @@ public final class ContactsContract {
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_lookup";
- /**
- * Boolean parameter that is used to look up a SIP address.
- *
- * @hide
- */
+ /**
+ * If this boolean parameter is set to true, then the appended query is treated as a
+ * SIP address and the lookup will be performed against SIP addresses in the user's
+ * contacts.
+ */
public static final String QUERY_PARAMETER_SIP_ADDRESS = "sip";
}
@@ -5304,8 +5310,6 @@ public final class ContactsContract {
/**
* The style used for combining given/middle/family name into a full name.
* See {@link ContactsContract.FullNameStyle}.
- *
- * @hide
*/
public static final String FULL_NAME_STYLE = DATA10;
@@ -6897,8 +6901,6 @@ public final class ContactsContract {
* each column. For example the meaning for {@link Phone}'s type is different than
* {@link SipAddress}'s.
* </p>
- *
- * @hide
*/
public static final class Callable implements DataColumnsWithJoins, CommonColumns {
/**
@@ -7756,7 +7758,6 @@ public final class ContactsContract {
* {@link PinnedPositions#STAR_WHEN_PINNING} to true to force all pinned and unpinned
* contacts to be automatically starred and unstarred.
* </p>
- * @hide
*/
public static final class PinnedPositions {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0dffc17..843a468 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3407,6 +3407,11 @@ public final class Settings {
public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
/**
+ * Whether the NFC unlock feature is enabled (0 = false, 1 = true)
+ */
+ public static final String NFC_UNLOCK_ENABLED = "nfc_unlock_enabled";
+
+ /**
* Whether lock pattern will vibrate as user enters (0 = false, 1 =
* true)
*
@@ -3741,6 +3746,16 @@ public final class Settings {
"accessibility_captioning_edge_color";
/**
+ * Integer property that specifes the window color for captions as a
+ * packed 32-bit color.
+ *
+ * @see android.graphics.Color#argb
+ * @hide
+ */
+ public static final String ACCESSIBILITY_CAPTIONING_WINDOW_COLOR =
+ "accessibility_captioning_window_color";
+
+ /**
* String property that specifies the typeface for captions, one of:
* <ul>
* <li>DEFAULT
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index 041d9e0..35fb504 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -19,7 +19,7 @@ package android.view;
import android.content.res.CompatibilityInfo;
import android.os.IBinder;
-import com.android.internal.util.Objects;
+import java.util.Objects;
/** @hide */
public class DisplayAdjustments {
@@ -91,7 +91,7 @@ public class DisplayAdjustments {
return false;
}
DisplayAdjustments daj = (DisplayAdjustments)o;
- return Objects.equal(daj.mCompatInfo, mCompatInfo) &&
- Objects.equal(daj.mActivityToken, mActivityToken);
+ return Objects.equals(daj.mCompatInfo, mCompatInfo) &&
+ Objects.equals(daj.mActivityToken, mActivityToken);
}
}
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 2829215..e53ce8b 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -438,6 +438,21 @@ public abstract class DisplayList {
public abstract float getTranslationY();
/**
+ * Sets the translation value for the display list on the Z axis
+ *
+ * @see View#setTranslationZ(float)
+ * @see #getTranslationZ()
+ */
+ public abstract void setTranslationZ(float translationZ);
+
+ /**
+ * Returns the translation value for this display list on the Z axis.
+ *
+ * @see #setTranslationZ(float)
+ */
+ public abstract float getTranslationZ();
+
+ /**
* Sets the rotation value for the display list around the Z axis
*
* @param rotation The rotation value of the display list, in degrees
@@ -536,7 +551,8 @@ public abstract class DisplayList {
*
* @hide
*/
- public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
+ public abstract void setTransformationInfo(float alpha,
+ float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
/**
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 574b7bb..7944e66 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -231,6 +231,21 @@ class GLES20DisplayList extends DisplayList {
}
@Override
+ public void setTranslationZ(float translationZ) {
+ if (hasNativeDisplayList()) {
+ nSetTranslationZ(mFinalizer.mNativeDisplayList, translationZ);
+ }
+ }
+
+ @Override
+ public float getTranslationZ() {
+ if (hasNativeDisplayList()) {
+ return nGetTranslationZ(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setRotation(float rotation) {
if (hasNativeDisplayList()) {
nSetRotation(mFinalizer.mNativeDisplayList, rotation);
@@ -306,10 +321,12 @@ class GLES20DisplayList extends DisplayList {
}
@Override
- public void setTransformationInfo(float alpha, float translationX, float translationY,
+ public void setTransformationInfo(float alpha,
+ float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
if (hasNativeDisplayList()) {
- nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha, translationX, translationY,
+ nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha,
+ translationX, translationY, translationZ,
rotation, rotationX, rotationY, scaleX, scaleY);
}
}
@@ -466,14 +483,15 @@ class GLES20DisplayList extends DisplayList {
boolean hasOverlappingRendering);
private static native void nSetTranslationX(int displayList, float translationX);
private static native void nSetTranslationY(int displayList, float translationY);
+ private static native void nSetTranslationZ(int displayList, float translationZ);
private static native void nSetRotation(int displayList, float rotation);
private static native void nSetRotationX(int displayList, float rotationX);
private static native void nSetRotationY(int displayList, float rotationY);
private static native void nSetScaleX(int displayList, float scaleX);
private static native void nSetScaleY(int displayList, float scaleY);
private static native void nSetTransformationInfo(int displayList, float alpha,
- float translationX, float translationY, float rotation, float rotationX,
- float rotationY, float scaleX, float scaleY);
+ float translationX, float translationY, float translationZ,
+ float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
@@ -489,6 +507,7 @@ class GLES20DisplayList extends DisplayList {
private static native float nGetScaleY(int displayList);
private static native float nGetTranslationX(int displayList);
private static native float nGetTranslationY(int displayList);
+ private static native float nGetTranslationZ(int displayList);
private static native float nGetRotation(int displayList);
private static native float nGetRotationX(int displayList);
private static native float nGetRotationY(int displayList);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a693ed4..a0e6924 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2981,6 +2981,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.ExportedProperty
float mTranslationY = 0f;
+ @ViewDebug.ExportedProperty
+ float mTranslationZ = 0f;
+
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
@@ -5022,7 +5025,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param text The announcement text.
*/
public void announceForAccessibility(CharSequence text) {
- if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null
+ && isImportantForAccessibility()) {
AccessibilityEvent event = AccessibilityEvent.obtain(
AccessibilityEvent.TYPE_ANNOUNCEMENT);
onInitializeAccessibilityEvent(event);
@@ -5072,7 +5076,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Note: Called from the default {@link AccessibilityDelegate}.
*/
void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
- if (!isShown()) {
+ if (!isShown() || !isImportantForAccessibility()) {
return;
}
onInitializeAccessibilityEvent(event);
@@ -7372,9 +7376,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param children The list of children for accessibility.
*/
public void addChildrenForAccessibility(ArrayList<View> children) {
- if (includeForAccessibility()) {
- children.add(this);
- }
+
}
/**
@@ -7388,7 +7390,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public boolean includeForAccessibility() {
- //noinspection SimplifiableIfStatement
if (mAttachInfo != null) {
return (mAttachInfo.mAccessibilityFetchFlags
& AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
@@ -10510,6 +10511,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @hide
+ */
+ @ViewDebug.ExportedProperty(category = "drawing")
+ public float getTranslationZ() {
+ return mTransformationInfo != null ? mTransformationInfo.mTranslationZ : 0;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTranslationZ(float translationZ) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mTranslationZ != translationZ) {
+ invalidateViewProperty(true, false);
+ info.mTranslationZ = translationZ;
+ info.mMatrixDirty = true;
+ invalidateViewProperty(false, true);
+ if (mDisplayList != null) {
+ mDisplayList.setTranslationZ(translationZ);
+ }
+ if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
+ // View was rejected last time it was drawn by its parent; this may have changed
+ invalidateParentIfNeeded();
+ }
+ }
+ }
+
+ /**
* Hit rectangle in parent's coordinates
*
* @param outRect The hit rectangle of the view.
@@ -14175,6 +14205,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
displayList.setTransformationInfo(alpha,
mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
+ mTransformationInfo.mTranslationZ,
mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
mTransformationInfo.mScaleY);
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 975931a..47de780 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -155,6 +155,11 @@ public class ViewOverlay {
}
}
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || (mDrawables != null && mDrawables.contains(who));
+ }
+
public void add(View child) {
if (child.getParent() instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) child.getParent();
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 67a94be..391b345 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -144,9 +144,10 @@ public class ViewPropertyAnimator {
private static final int X = 0x0080;
private static final int Y = 0x0100;
private static final int ALPHA = 0x0200;
+ private static final int TRANSLATION_Z = 0x0400;
- private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
- ROTATION | ROTATION_X | ROTATION_Y | X | Y;
+ private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
+ SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y;
/**
* The mechanism by which the user can request several properties that are then animated
@@ -573,6 +574,22 @@ public class ViewPropertyAnimator {
}
/**
+ * @hide
+ */
+ public ViewPropertyAnimator translationZ(float value) {
+ animateProperty(TRANSLATION_Z, value);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public ViewPropertyAnimator translationZBy(float value) {
+ animatePropertyBy(TRANSLATION_Z, value);
+ return this;
+ }
+
+ /**
* This method will cause the View's <code>translationY</code> property to be animated to the
* specified value. Animations already running on the property will be canceled.
*
@@ -909,6 +926,10 @@ public class ViewPropertyAnimator {
info.mTranslationY = value;
if (displayList != null) displayList.setTranslationY(value);
break;
+ case TRANSLATION_Z:
+ info.mTranslationZ = value;
+ if (displayList != null) displayList.setTranslationZ(value);
+ break;
case ROTATION:
info.mRotation = value;
if (displayList != null) displayList.setRotation(value);
@@ -957,6 +978,8 @@ public class ViewPropertyAnimator {
return info.mTranslationX;
case TRANSLATION_Y:
return info.mTranslationY;
+ case TRANSLATION_Z:
+ return info.mTranslationZ;
case ROTATION:
return info.mRotation;
case ROTATION_X:
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index 3f79b47..97db84b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -174,11 +174,13 @@ public class AccessibilityNodeInfoCache {
// subtrees in the cache.
// TODO: Runs in O(n^2), could optimize to O(n + n log n)
final LongArray newChildrenIds = info.getChildNodeIds();
- final int oldChildCount = oldInfo.getChildCount();
- for (int i = 0; i < oldChildCount; i++) {
- final long oldChildId = oldInfo.getChildId(i);
- if (newChildrenIds.indexOf(oldChildId) < 0) {
- clearSubTreeLocked(oldChildId);
+ if (newChildrenIds != null) {
+ final int oldChildCount = oldInfo.getChildCount();
+ for (int i = 0; i < oldChildCount; i++) {
+ final long oldChildId = oldInfo.getChildId(i);
+ if (newChildrenIds.indexOf(oldChildId) < 0) {
+ clearSubTreeLocked(oldChildId);
+ }
}
}
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index 557239f..02929ed 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -293,6 +293,9 @@ public class CaptioningManager {
*/
public final int edgeColor;
+ /** The preferred window color for video captions. */
+ public final int windowColor;
+
/**
* @hide
*/
@@ -301,11 +304,12 @@ public class CaptioningManager {
private Typeface mParsedTypeface;
private CaptionStyle(int foregroundColor, int backgroundColor, int edgeType, int edgeColor,
- String rawTypeface) {
+ int windowColor, String rawTypeface) {
this.foregroundColor = foregroundColor;
this.backgroundColor = backgroundColor;
this.edgeType = edgeType;
this.edgeColor = edgeColor;
+ this.windowColor = windowColor;
mRawTypeface = rawTypeface;
}
@@ -334,25 +338,27 @@ public class CaptioningManager {
cr, Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE, defStyle.edgeType);
final int edgeColor = Secure.getInt(
cr, Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR, defStyle.edgeColor);
+ final int windowColor = Secure.getInt(
+ cr, Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR, defStyle.windowColor);
String rawTypeface = Secure.getString(cr, Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE);
if (rawTypeface == null) {
rawTypeface = defStyle.mRawTypeface;
}
- return new CaptionStyle(
- foregroundColor, backgroundColor, edgeType, edgeColor, rawTypeface);
+ return new CaptionStyle(foregroundColor, backgroundColor, edgeType, edgeColor,
+ windowColor, rawTypeface);
}
static {
- WHITE_ON_BLACK = new CaptionStyle(
- Color.WHITE, Color.BLACK, EDGE_TYPE_NONE, Color.BLACK, null);
- BLACK_ON_WHITE = new CaptionStyle(
- Color.BLACK, Color.WHITE, EDGE_TYPE_NONE, Color.BLACK, null);
- YELLOW_ON_BLACK = new CaptionStyle(
- Color.YELLOW, Color.BLACK, EDGE_TYPE_NONE, Color.BLACK, null);
- YELLOW_ON_BLUE = new CaptionStyle(
- Color.YELLOW, Color.BLUE, EDGE_TYPE_NONE, Color.BLACK, null);
+ WHITE_ON_BLACK = new CaptionStyle(Color.WHITE, Color.BLACK, EDGE_TYPE_NONE,
+ Color.BLACK, Color.TRANSPARENT, null);
+ BLACK_ON_WHITE = new CaptionStyle(Color.BLACK, Color.WHITE, EDGE_TYPE_NONE,
+ Color.BLACK, Color.TRANSPARENT, null);
+ YELLOW_ON_BLACK = new CaptionStyle(Color.YELLOW, Color.BLACK, EDGE_TYPE_NONE,
+ Color.BLACK, Color.TRANSPARENT, null);
+ YELLOW_ON_BLUE = new CaptionStyle(Color.YELLOW, Color.BLUE, EDGE_TYPE_NONE,
+ Color.BLACK, Color.TRANSPARENT, null);
PRESETS = new CaptionStyle[] {
WHITE_ON_BLACK, BLACK_ON_WHITE, YELLOW_ON_BLACK, YELLOW_ON_BLUE
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 48092f6..9dc9116 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -192,10 +192,16 @@ public class ZygoteInit {
static void closeServerSocket() {
try {
if (sServerSocket != null) {
+ FileDescriptor fd = sServerSocket.getFileDescriptor();
sServerSocket.close();
+ if (fd != null) {
+ Libcore.os.close(fd);
+ }
}
} catch (IOException ex) {
Log.e(TAG, "Zygote: error closing sockets", ex);
+ } catch (libcore.io.ErrnoException ex) {
+ Log.e(TAG, "Zygote: error closing descriptor", ex);
}
sServerSocket = null;
diff --git a/core/java/com/android/internal/util/Objects.java b/core/java/com/android/internal/util/Objects.java
deleted file mode 100644
index 2664182..0000000
--- a/core/java/com/android/internal/util/Objects.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.util;
-
-import java.util.Arrays;
-
-/**
- * Object utility methods.
- */
-public class Objects {
-
- /**
- * Determines whether two possibly-null objects are equal. Returns:
- *
- * <ul>
- * <li>{@code true} if {@code a} and {@code b} are both null.
- * <li>{@code true} if {@code a} and {@code b} are both non-null and they are
- * equal according to {@link Object#equals(Object)}.
- * <li>{@code false} in all other situations.
- * </ul>
- *
- * <p>This assumes that any non-null objects passed to this function conform
- * to the {@code equals()} contract.
- */
- public static boolean equal(Object a, Object b) {
- return a == b || (a != null && a.equals(b));
- }
-
- /**
- * Generates a hash code for multiple values. The hash code is generated by
- * calling {@link Arrays#hashCode(Object[])}.
- *
- * <p>This is useful for implementing {@link Object#hashCode()}. For example,
- * in an object that has three properties, {@code x}, {@code y}, and
- * {@code z}, one could write:
- * <pre>
- * public int hashCode() {
- * return Objects.hashCode(getX(), getY(), getZ());
- * }</pre>
- *
- * <b>Warning</b>: When a single object is supplied, the returned hash code
- * does not equal the hash code of that object.
- */
- public static int hashCode(Object... objects) {
- return Arrays.hashCode(objects);
- }
-
-}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a558909..329331a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -4,7 +4,9 @@ include $(CLEAR_VARS)
LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
+LOCAL_CPPFLAGS += -Wno-conversion-null
ifeq ($(TARGET_ARCH), arm)
LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
diff --git a/core/jni/android_net_wifi_WifiNative.cpp b/core/jni/android_net_wifi_WifiNative.cpp
index 6e11192..4becfb6 100644
--- a/core/jni/android_net_wifi_WifiNative.cpp
+++ b/core/jni/android_net_wifi_WifiNative.cpp
@@ -167,7 +167,7 @@ static JNINativeMethod gWifiMethods[] = {
int register_android_net_wifi_WifiNative(JNIEnv* env) {
return AndroidRuntime::registerNativeMethods(env,
- "android/net/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
+ "com/android/server/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
}
}; // namespace android
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 3ac2225..259d030 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -943,13 +943,20 @@ static jboolean android_os_BinderProxy_isBinderAlive(JNIEnv* env, jobject obj)
}
static int getprocname(pid_t pid, char *buf, size_t len) {
- char filename[20];
+ char filename[32];
FILE *f;
- sprintf(filename, "/proc/%d/cmdline", pid);
+ snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
f = fopen(filename, "r");
- if (!f) { *buf = '\0'; return 1; }
- if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
+ if (!f) {
+ *buf = '\0';
+ return 1;
+ }
+ if (!fgets(buf, len, f)) {
+ *buf = '\0';
+ fclose(f);
+ return 2;
+ }
fclose(f);
return 0;
}
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index d63a410..d6cddb2 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -114,6 +114,11 @@ static void android_view_GLES20DisplayList_setTranslationY(JNIEnv* env,
displayList->setTranslationY(ty);
}
+static void android_view_GLES20DisplayList_setTranslationZ(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float tz) {
+ displayList->setTranslationZ(tz);
+}
+
static void android_view_GLES20DisplayList_setRotation(JNIEnv* env,
jobject clazz, DisplayList* displayList, float rotation) {
displayList->setRotation(rotation);
@@ -141,11 +146,12 @@ static void android_view_GLES20DisplayList_setScaleY(JNIEnv* env,
static void android_view_GLES20DisplayList_setTransformationInfo(JNIEnv* env,
jobject clazz, DisplayList* displayList, float alpha,
- float translationX, float translationY, float rotation, float rotationX, float rotationY,
- float scaleX, float scaleY) {
+ float translationX, float translationY, float translationZ,
+ float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
displayList->setAlpha(alpha);
displayList->setTranslationX(translationX);
displayList->setTranslationY(translationY);
+ displayList->setTranslationZ(translationZ);
displayList->setRotation(rotation);
displayList->setRotationX(rotationX);
displayList->setRotationY(rotationY);
@@ -320,12 +326,13 @@ static JNINativeMethod gMethods[] = {
(void*) android_view_GLES20DisplayList_setHasOverlappingRendering },
{ "nSetTranslationX", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationX },
{ "nSetTranslationY", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationY },
+ { "nSetTranslationZ", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationZ },
{ "nSetRotation", "(IF)V", (void*) android_view_GLES20DisplayList_setRotation },
{ "nSetRotationX", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationX },
{ "nSetRotationY", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationY },
{ "nSetScaleX", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleX },
{ "nSetScaleY", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleY },
- { "nSetTransformationInfo","(IFFFFFFFF)V",
+ { "nSetTransformationInfo","(IFFFFFFFFF)V",
(void*) android_view_GLES20DisplayList_setTransformationInfo },
{ "nSetPivotX", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotX },
{ "nSetPivotY", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotY },
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index bf5accd..00da0f7 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -21,7 +21,9 @@
#include <utils/Log.h>
#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
#include <ScopedUtfChars.h>
+#include <UniquePtr.h>
#include <zlib.h>
@@ -143,7 +145,7 @@ isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime,
}
static install_status_t
-sumFiles(JNIEnv* env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
+sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*)
{
size_t* total = (size_t*) arg;
size_t uncompLen;
@@ -178,7 +180,7 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
return INSTALL_FAILED_INVALID_APK;
} else {
struct tm t;
- ZipFileRO::zipTimeToTimespec(when, &t);
+ ZipUtils::zipTimeToTimespec(when, &t);
modTime = mktime(&t);
}
@@ -273,26 +275,25 @@ iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, js
ScopedUtfChars cpuAbi(env, javaCpuAbi);
ScopedUtfChars cpuAbi2(env, javaCpuAbi2);
- ZipFileRO zipFile;
-
- if (zipFile.open(filePath.c_str()) != NO_ERROR) {
+ UniquePtr<ZipFileRO> zipFile(ZipFileRO::open(filePath.c_str()));
+ if (zipFile.get() == NULL) {
ALOGI("Couldn't open APK %s\n", filePath.c_str());
return INSTALL_FAILED_INVALID_APK;
}
- const int N = zipFile.getNumEntries();
-
char fileName[PATH_MAX];
bool hasPrimaryAbi = false;
- for (int i = 0; i < N; i++) {
- const ZipEntryRO entry = zipFile.findEntryByIndex(i);
- if (entry == NULL) {
- continue;
- }
+ void* cookie = NULL;
+ if (!zipFile->startIteration(&cookie)) {
+ ALOGI("Couldn't iterate over APK%s\n", filePath.c_str());
+ return INSTALL_FAILED_INVALID_APK;
+ }
+ ZipEntryRO entry = NULL;
+ while ((entry = zipFile->nextEntry(cookie)) != NULL) {
// Make sure this entry has a filename.
- if (zipFile.getEntryFileName(entry, fileName, sizeof(fileName))) {
+ if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) {
continue;
}
@@ -346,15 +347,18 @@ iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, js
&& isFilenameSafe(lastSlash + 1))
|| !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
- install_status_t ret = callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
+ install_status_t ret = callFunc(env, callArg, zipFile.get(), entry, lastSlash + 1);
if (ret != INSTALL_SUCCEEDED) {
ALOGV("Failure for entry %s", lastSlash + 1);
+ zipFile->endIteration(cookie);
return ret;
}
}
}
+ zipFile->endIteration(cookie);
+
return INSTALL_SUCCEEDED;
}
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index ec19f0a..0b9ad9b 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -80,7 +80,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
stats_line s;
int64_t rawTag;
if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx,
- &s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
+ s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
&s.txBytes, &s.txPackets) == 9) {
if (s.idx != lastIdx + 1) {
ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c923e14..6de7a40 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -809,8 +809,15 @@
<!-- Allows access to the loop radio (Android@Home mesh network) device.
@hide -->
<permission android:name="android.permission.LOOP_RADIO"
- android:permissionGroup="android.permission-group.NETWORK"
- android:protectionLevel="signature|system" />
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="signature|system" />
+
+ <!-- Allows for the NFC process to unlock the device
+ @hide This should only be used by the Nfc apk
+ -->
+ <permission android:name="android.permission.NFC_UNLOCK"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for accessing accounts -->
diff --git a/docs/html/google/play/billing/v2/api.jd b/docs/html/google/play/billing/v2/api.jd
index 7e386a2..9501555 100644
--- a/docs/html/google/play/billing/v2/api.jd
+++ b/docs/html/google/play/billing/v2/api.jd
@@ -32,14 +32,6 @@ Store app installed on the device. </p>
asynchronous and uses service messages sent as broadcast intents, so
it is more complicated than Version 3. </p>
-<p>Version 2 supports both unmanaged and managed products, as well as supports
-subscriptions, where Version 3 does not yet offer support for subscriptions. If
-you want to sell subscriptions in your app, you should implement In-app Billing
-Version 2, rather than Version 3. </p>
-
-<p>If you do not need to sell subscriptions, you
-should implement In-app Billing Version 3 instead.</p>
-
<h2 id="billing-types">Product Types</h2>
<p>In-app Billing Version supports three different product types
@@ -500,11 +492,8 @@ limitations.</p>
<li>In-app billing can be implemented only in applications that you publish through Google
Play.</li>
<li>You must have a Google Wallet Merchant account to use Google Play In-app Billing.</li>
- <li>In-app billing requires version 2.3.4 (or higher) of the Android Market application.
- To support subscriptions, version 3.5 or higher of the Google Play app is required. On devices
- running Android 3.0, version 5.0.12 (or higher) of the MyApps application is required.</li>
- <li>An application can use in-app billing only if the device is running Android 1.6 (API level 4)
- or higher.</li>
+ <li>To support subscriptions, version 3.5 or higher of the Google Play app is required. </li>
+ <li>In-app Billing requires Android 1.6 (API level 4) or higher.</li>
<li>You can use in-app billing to sell only digital content. You cannot use in-app billing to sell
physical goods, personal services, or anything that requires physical delivery.</li>
<li>Google Play does not provide any form of content delivery. You are responsible for
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
new file mode 100644
index 0000000..f09ef9f
--- /dev/null
+++ b/docs/html/guide/components/intents-common.jd
@@ -0,0 +1,1312 @@
+page.title=Common Intents
+page.tags="IntentFilter"
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+ <h2>In this document
+ <a href="#" onclick="hideNestedItems('#tocIntents',this);return false;" class="header-toggle">
+ <span class="more">show more</span>
+ <span class="less" style="display:none">show less</span></a></h2>
+
+<ol id="tocIntents" class="hide-nested">
+ <li><a href="#Camera">Camera</a>
+ <ol>
+ <li><a href="#ImageCapture">Capture a picture or video and return it</a></li>
+ </ol>
+ </li>
+ <li><a href="#Contacts">Contacts/People App</a>
+ <ol>
+ <li><a href="#PickContact">Select a contact</a></li>
+ <li><a href="#PickContactDat">Select specific contact data</a></li>
+ <li><a href="#ViewContact">View a contact</a></li>
+ <li><a href="#EditContact">Edit an existing contact</a></li>
+ <li><a href="#InsertContact">Insert a contact</a></li>
+ </ol>
+ </li>
+ <li><a href="#Email">Email</a>
+ <ol>
+ <li><a href="#ComposeEmail">Compose an email with optional attachments</a></li>
+ </ol>
+ </li>
+ <li><a href="#Storage">File Storage</a>
+ <ol>
+ <li><a href="#GetFile">Retrieve a specific type of file</a></li>
+ <li><a href="#OpenFile">Open a specific type of file</a></li>
+ </ol>
+ </li>
+ <li><a href="#Maps">Maps</a>
+ <ol>
+ <li><a href="#ViewMap">Show a location on a map</a></li>
+ </ol>
+ </li>
+ <li><a href="#Music">Music or Video</a>
+ <ol>
+ <li><a href="#PlayMedia">Play a media file</a></li>
+ </ol>
+ </li>
+ <li><a href="#Phone">Phone</a>
+ <ol>
+ <li><a href="#DialPhone">Initiate a phone call</a></li>
+ </ol>
+ </li>
+ <li><a href="#Settings">Settings</a>
+ <ol>
+ <li><a href="#OpenSettings">Open a specific section of Settings</a></li>
+ </ol>
+ </li>
+ <li><a href="#Messaging">Text Messaging</a>
+ <ol>
+ <li><a href="#SendMessage">Compose an SMS/MMS message with attachment</a></li>
+ </ol>
+ </li>
+ <li><a href="#Browser">Web Browser</a>
+ <ol>
+ <li><a href="#ViewUrl">Load a web URL</a></li>
+ <li><a href="#SearchWeb">Perform a web search</a></li>
+ </ol>
+ </li>
+</ol>
+
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent
+Filters</a></li>
+ </ol>
+</div>
+</div>
+
+
+<p>An intent allows you to start an activity in another app by describing a simple
+action you'd like to perform (such as "view a map" or "take a picture")
+in an {@link android.content.Intent} object. This type of intent is
+called an <em>implicit</em> intent because it does not specify the app component
+to start, but instead specifies an <em>action</em> and provides some
+<em>data</em> with which to perform the action.</p>
+
+<p>When you call
+{@link android.content.Context#startActivity startActivity()} or
+{@link android.app.Activity#startActivityForResult startActivityForResult()} and pass it an
+implicit intent, the system <a href="{@docRoot}guide/components/intents-filters.html#Resolution"
+>resolves the intent</a> to an app that can handle the intent
+and starts its corresponding {@link android.app.Activity}. If there's more than one app
+that can handle the intent, the system presents the user with a dialog to pick which app
+to use.</p>
+
+<p>This page describes several implicit intents that you can use to perform common actions,
+organized by the type of app that handles the intent. Each section also shows how you can
+create an <a href="{@docRoot}guide/components/intents-filters.html#Receiving">intent filter</a> to
+advertise your app's ability to perform the same action.</p>
+
+<p class="caution"><strong>Caution:</strong> If there are no apps on the device that can receive
+the implicit intent, your app will crash when it calls {@link android.content.Context#startActivity
+startActivity()}. To first verify that an app exists to receive the intent, call {@link
+android.content.Intent#resolveActivity resolveActivity()} on your {@link android.content.Intent}
+object. If the result is non-null, there is at least one app that can handle the intent and
+it's safe to call {@link android.content.Context#startActivity startActivity()}. If the result is
+null, you should not use the intent and, if possible, you should disable the feature that invokes
+the intent.</p>
+
+
+<p>If you're not familiar with how to create intents or intent filters, you should first read
+<a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>.</p>
+
+
+
+
+
+<h2 id="Camera">Camera</h2>
+
+
+
+<h3 id="ImageCapture">Capture a picture or video and return it</h3>
+
+<p>To open a camera app and receive the resulting photo or video, use the {@link
+android.provider.MediaStore#ACTION_IMAGE_CAPTURE} or {@link
+android.provider.MediaStore#ACTION_VIDEO_CAPTURE} action. Also specify the URI location where you'd
+like the camera to save the photo or video, in the {@link android.provider.MediaStore#EXTRA_OUTPUT}
+extra.</p>
+
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.MediaStore#ACTION_IMAGE_CAPTURE} or<br>
+ {@link android.provider.MediaStore#ACTION_VIDEO_CAPTURE}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+ <dl>
+ <dt>{@link android.provider.MediaStore#EXTRA_OUTPUT}</dt>
+ <dd>The URI location where the camera app should save the photo or
+ video file (as a {@link android.net.Uri} object).</dd>
+ </dl>
+</dd>
+</dl>
+
+<p>When the camera app successfully returns
+focus to your activity (your app receives the {@link android.app.Activity#onActivityResult
+onActivityResult()} callback), you can access the photo or video at the URI you specified
+with the {@link android.provider.MediaStore#EXTRA_OUTPUT} value.</p>
+
+<p class="note"><strong>Note:</strong> When you use {@link
+android.provider.MediaStore#ACTION_IMAGE_CAPTURE} to capture a photo, the camera may also return a
+downscaled copy (a thumbnail) of the photo in the result {@link
+android.content.Intent}, saved as a {@link android.graphics.Bitmap} in an extra field named
+<code>"data"</code>.</p>
+
+
+<p><b>Example intent:</b></p>
+<pre>
+static final int REQUEST_IMAGE_CAPTURE = 1;
+static final Uri mLocationForPhotos;
+
+public void capturePhoto(String targetFilename) {
+ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ intent.putExtra(MediaStore.EXTRA_OUTPUT,
+ Uri.withAppendedPath(mLocationForPhotos, targetFilename);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
+ }
+}
+
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
+ Bitmap thumbnail = data.getParcelable("data");
+ // Do other work with full size photo saved in mLocationForPhotos
+ ...
+ }
+}
+</pre>
+
+<p>For more information about how to use this intent to capture a photo, including
+how to create an appropriate {@link android.net.Uri} for the output location, read
+<a href="{@docRoot}training/camera/photobasics.html">Taking Photos Simply</a> or
+<a href="{@docRoot}training/camera/videobasics.html">Taking Videos Simply</a>.</p>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.media.action.IMAGE_CAPTURE" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+<p>When handling this intent, your activity should check for the {@link
+android.provider.MediaStore#EXTRA_OUTPUT} extra in the incoming {@link android.content.Intent},
+then save the captured image or video at the location specified by that extra and call {@link
+android.app.Activity#setResult(int,Intent) setResult()} with an
+{@link android.content.Intent} that includes a compressed thumbnail
+in an extra named <code>"data"</code>.</p>
+
+
+
+
+<h2 id="Contacts">Contacts/People App</h2>
+
+
+<h3 id="PickContact">Select a contact</h3>
+
+<p>To have the user select a contact and provide your app access to all the contact information,
+use the {@link android.content.Intent#ACTION_PICK} action and specify the MIME type to
+{@link android.provider.ContactsContract.Contacts#CONTENT_TYPE
+Contacts.CONTENT_TYPE}.</p>
+
+<p>The result {@link android.content.Intent} delivered to your {@link
+android.app.Activity#onActivityResult onActivityResult()} callback contains the
+<code>content:</code> URI pointing to the selected contact. The response grants
+your app temporary permissions to read that contact using the <a
+href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a> API even if
+your app does not include the {@link android.Manifest.permission#READ_CONTACTS} permission.</p>
+
+<p class="note"><strong>Tip:</strong> If you need access to only a specific piece of contact
+information, such as a phone number or email address, instead see the next section about how to
+<a href="#PickContactData">select specific contact data</a>.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_PICK}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>{@link android.provider.ContactsContract.Contacts#CONTENT_TYPE
+Contacts.CONTENT_TYPE}
+</dd>
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+static final int REQUEST_SELECT_CONTACT = 1;
+
+public void selectContact() {
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivityForResult(intent, REQUEST_SELECT_CONTACT);
+ }
+}
+
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_SELECT_CONTACT && resultCode == RESULT_OK) {
+ Uri contactUri = data.getData();
+ // Do something with the selected contact at contactUri
+ ...
+ }
+}
+</pre>
+
+<p>For information about how to retrieve contact details once you have the contact URI,
+read <a href="{@docRoot}training/contacts-provider/retrieve-details.html">Retrieving Details
+for a Contact</a>. Remember, when you retrieve the contact URI with the above intent, you
+<strong>do not</strong> need the {@link android.Manifest.permission#READ_CONTACTS} permission
+to read details for that contact.</p>
+
+
+
+
+<h3 id="PickContactDat">Select specific contact data</h3>
+
+<p>To have the user select a specific piece of information from a contact, such as
+a phone number, email address, or other data type, use the
+{@link android.content.Intent#ACTION_PICK} action and specify the MIME type to one
+of the content types listed below, such as
+{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_TYPE
+CommonDataKinds.Phone.CONTENT_TYPE} to get the contact's phone number.</p>
+
+<p>If you need to retrieve only one type of data from a contact, this technique with a
+{@code CONTENT_TYPE} from the
+{@link android.provider.ContactsContract.CommonDataKinds} classes is more efficient than
+using the {@link android.provider.ContactsContract.Contacts#CONTENT_TYPE
+Contacts.CONTENT_TYPE} (as shown in the previous section) because the result provides you direct
+access to the desired data without requiring you to perform a more complex query to <a
+href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a>.</p>
+
+<p>The result {@link android.content.Intent} delivered to your {@link
+android.app.Activity#onActivityResult onActivityResult()} callback contains the
+<code>content:</code> URI pointing to the selected contact data. The response grants
+your app temporary permissions to read that contact data even if your app does
+not include the {@link android.Manifest.permission#READ_CONTACTS} permission.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_PICK}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>
+ <dl>
+ <dt>{@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_TYPE
+CommonDataKinds.Phone.CONTENT_TYPE}</dt>
+ <dd>Pick from contacts with a phone number.</dd>
+ <dt>{@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_TYPE
+CommonDataKinds.Email.CONTENT_TYPE}</dt>
+ <dd>Pick from contacts with an email address.</dd>
+ <dt>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_TYPE
+CommonDataKinds.StructuredPostal.CONTENT_TYPE}</dt>
+ <dd>Pick from contacts with a postal address.</dd>
+ </dl>
+ <p>Or one of many other {@code CONTENT_TYPE} values
+ under {@link android.provider.ContactsContract}.</p>
+</dd>
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+static final int REQUEST_SELECT_PHONE_NUMBER = 1;
+
+public void selectContact() {
+ // Start an activity for the user to pick a phone number from contacts
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setType(CommonDataKinds.Phone.CONTENT_TYPE);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivityForResult(intent, REQUEST_SELECT_PHONE_NUMBER);
+ }
+}
+
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_SELECT_PHONE_NUMBER && resultCode == RESULT_OK) {
+ // Get the URI and query the content provider for the phone number
+ Uri contactUri = data.getData();
+ String[] projection = new String[]{CommonDataKinds.Phone.NUMBER};
+ Cursor cursor = getContentResolver().query(contactUri, projection,
+ null, null, null);
+ // If the cursor returned is valid, get the phone number
+ if (cursor != null && cursor.moveToFirst()) {
+ int numberIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER);
+ String number = cursor.getString(numberIndex);
+ // Do something with the phone number
+ ...
+ }
+ }
+}
+</pre>
+
+
+
+
+
+<h3 id="ViewContact">View a contact</h3>
+
+<p>To display the details for a known contact, use the {@link android.content.Intent#ACTION_VIEW}
+action and specify the contact with a {@code content:} URI as the intent data.</p>
+
+<p>There are primarily two ways to initially retrieve the contact's URI:</p>
+<ul>
+ <li>Use the contact URI returned by the {@link android.content.Intent#ACTION_PICK},
+ shown in the previous section (this does not require any app permissions).</li>
+ <li>Access the list of all contacts directly, as described in <a
+ href="{@docRoot}training/contacts-provider/retrieve-names.html">Retrieving a List of
+ Contacts</a> (this requires the {@link android.Manifest.permission#READ_CONTACTS}
+ permission).</li>
+</ul>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_VIEW}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>{@code content:&lt;URI>}</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None. The type is inferred from contact URI.
+</dd>
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void viewContact(Uri contactUri) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+
+<h3 id="EditContact">Edit an existing contact</h3>
+
+<p>To edit a known contact, use the {@link android.content.Intent#ACTION_EDIT}
+action, specify the contact with a {@code content:} URI
+as the intent data, and include any known contact information in extras specified by
+constants in {@link android.provider.ContactsContract.Intents.Insert}.</p>
+
+<p>There are primarily two ways to initially retrieve the contact URI:</p>
+<ul>
+ <li>Use the contact URI returned by the {@link android.content.Intent#ACTION_PICK},
+ shown in the previous section (this does not require any app permissions).</li>
+ <li>Access the list of all contacts directly, as described in <a
+ href="{@docRoot}training/contacts-provider/retrieve-names.html">Retrieving a List of
+ Contacts</a> (this requires the {@link android.Manifest.permission#READ_CONTACTS}
+ permission).</li>
+</ul>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_EDIT}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>{@code content:&lt;URI>}</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>The type is inferred from contact URI.
+</dd>
+
+<dt><b>Extras</b> (optional)</dt>
+<dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}
+so you can populate fields of the contact details.
+</dd>
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void editContact(Uri contactUri, String email) {
+ Intent intent = new Intent(Intent.ACTION_EDIT);
+ intent.setDataAndType(contactUri, Contacts.CONTENT_TYPE);
+ intent.putExtra(Intents.Insert.EMAIL, email);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<p>For more information about how to edit a contact, read <a
+href="{@docRoot}training/contacts-provider/modify-data.html">Modifying
+Contacts Using Intents</a>.</p>
+
+
+
+
+<h3 id="InsertContact">Insert a contact</h3>
+
+<p>To insert a new contact, use the {@link android.content.Intent#ACTION_INSERT} action,
+specify {@link android.provider.ContactsContract.Contacts#CONTENT_TYPE Contacts.CONTENT_TYPE} as
+the MIME type, and include any known contact information in extras specified by
+constants in {@link android.provider.ContactsContract.Intents.Insert}.
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_INSERT}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>{@link android.provider.ContactsContract.Contacts#CONTENT_TYPE Contacts.CONTENT_TYPE}</dd>
+
+<dt><b>Extras</b> (optional)</dt>
+<dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}.
+</dd>
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void insertContact(String name, String email) {
+ Intent intent = new Intent(Intent.ACTION_INSERT);
+ intent.setType(Contacts.CONTENT_TYPE);
+ intent.putExtra(Intents.Insert.NAME, name);
+ intent.putExtra(Intents.Insert.EMAIL, email);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<p>For more information about how to insert a contact, read <a
+href="{@docRoot}training/contacts-provider/modify-data.html">Modifying
+Contacts Using Intents</a>.</p>
+
+
+
+
+
+
+
+<h2 id="Email">Email</h2>
+
+
+<h3 id="ComposeEmail">Compose an email with optional attachments</h3>
+
+
+<p>To compose an email, use one of the below actions based on whether you'll include attachments,
+and include email details such as the recipient and subject using the extra keys listed below.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_SENDTO} (for no attachment) or<br>
+ {@link android.content.Intent#ACTION_SEND} (for one attachment) or<br>
+ {@link android.content.Intent#ACTION_SEND_MULTIPLE} (for multiple attachments)</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>
+ <dl>
+ <dt>{@link org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE} ("text/plain")
+ <dt><code>"*/*"</code>
+ </dl>
+</dd>
+
+<dt><b>Extras</b> (optional)</dt>
+<dd>
+ <dl>
+ <dt>{@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</dt>
+ <dd>A string array of all "To" recipient email addresses.</dd>
+ <dt>{@link android.content.Intent#EXTRA_CC Intent.EXTRA_CC}</dt>
+ <dd>A string array of all "CC" recipient email addresses.</dd>
+ <dt>{@link android.content.Intent#EXTRA_BCC Intent.EXTRA_BCC}</dt>
+ <dd>A string array of all "BCC" recipient email addresses.</dd>
+ <dt>{@link android.content.Intent#EXTRA_SUBJECT Intent.EXTRA_SUBJECT}</dt>
+ <dd>A string with the email subject.</dd>
+ <dt>{@link android.content.Intent#EXTRA_TEXT Intent.EXTRA_TEXT}</dt>
+ <dd>A string with the body of the email.</dd>
+ <dt>{@link android.content.Intent#EXTRA_STREAM Intent.EXTRA_STREAM}</dt>
+ <dd>A {@link android.net.Uri} pointing to the attachment. If using the
+ {@link android.content.Intent#ACTION_SEND_MULTIPLE} action, this should instead
+ be an {@link java.util.ArrayList} containing multiple {@link android.net.Uri} objects.</dd>
+ </dl>
+</dd>
+
+</dl>
+
+
+<p><b>Example intent:</b></p>
+<pre>
+public void composeEmail(String[] addresses, String subject, Uri attachment) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("*/*");
+ intent.putExtra(Intent.EXTRA_EMAIL, addresses);
+ intent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ intent.putExtra(Intent.EXTRA_STREAM, attachment);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<p>If you want to ensure that your intent is handled only by an email app (and not other
+text messaging or social apps), then use the {@link android.content.Intent#ACTION_SENDTO} action
+and include the {@code "mailto:"} data scheme. For example:</p>
+
+<pre>
+public void composeEmail(String[] addresses, String subject) {
+ Intent intent = new Intent(Intent.ACTION_SENDTO);
+ intent.setData(Uri.parse("mailto:")); // only email apps should handle this
+ intent.putExtra(Intent.EXTRA_EMAIL, addresses);
+ intent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.SEND" />
+ &lt;data android:type="*/*" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.SENDTO" />
+ &lt;data android:scheme="mailto" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<h2 id="Storage">File Storage</h2>
+
+
+
+<h3 id="GetFile">Retrieve a specific type of file</h3>
+
+<p>To request that the user select a file such as a document or photo and return a reference to
+your app, use the {@link android.content.Intent#ACTION_GET_CONTENT} action and specify your desired
+MIME type. The file reference returned to your app is transient to your activity's current
+lifecycle, so if you want to access it later you must import a copy that you can read later.
+This intent also allows the user to create a new file in the process (for
+example, instead of selecting an existing photo, the user can capture a new photo with the camera).
+</p>
+
+<p>The result intent delivered to your {@link android.app.Activity#onActivityResult
+onActivityResult()} method includes data with a URI pointing to the file.
+The URI could be anything, such as an {@code http:} URI, {@code file:} URI, or {@code content:}
+URI. However, if you'd like to restrict selectable files to only those that are accessible
+from a content provider (a {@code content:} URI) and that are available as a file stream with {@link
+android.content.ContentResolver#openFileDescriptor openFileDescriptor()}, you should add
+the {@link android.content.Intent#CATEGORY_OPENABLE} category to your intent.</p>
+
+<p>On Android 4.3 (API level 18) and higher,
+you can also allow the user to select multiple files by adding
+{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE} to the intent, set to {@code true}.
+You can then access each of the selected files in a {@link android.content.ClipData}
+object returned by {@link android.content.Intent#getClipData()}.</p>
+
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_GET_CONTENT}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>The MIME type corresponding to the file type the user should select.
+</dd>
+
+<dt><b>Extras</b> (optional)</dt>
+<dd>
+ <dl>
+ <dt>{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE}
+ <dd>A boolean declaring whether the user can select more than one file at a time.
+ </dd>
+ <dt>{@link android.content.Intent#EXTRA_LOCAL_ONLY}
+ <dd>A boolean that declares whether the returned file must be available directly from
+ the device, rather than requiring a download from a remote service.
+ </dd>
+ </dl>
+</dd>
+
+<dt><b>Category</b> (optional)</dt>
+<dd>
+ <dl>
+ <dt>{@link android.content.Intent#CATEGORY_OPENABLE}</dt>
+ <dd>To return only "openable" files that can be represented as a file stream
+ with {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}.</dd>
+ </dl>
+</dd>
+
+</dl>
+
+<p><b>Example intent to get a photo:</b></p>
+<pre>
+static final int REQUEST_IMAGE_GET = 1;
+
+public void selectImage() {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivityForResult(intent, REQUEST_IMAGE_GET);
+ }
+}
+
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_IMAGE_GET && resultCode == RESULT_OK) {
+ Bitmap thumbnail = data.getParcelable("data");
+ Uri fullPhotoUri = data.getData();
+ // Do work with photo saved at fullPhotoUri
+ ...
+ }
+}
+</pre>
+
+<p><b>Example intent filter to return a photo:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.GET_CONTENT" />
+ &lt;data android:type="image/*" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;!-- The OPENABLE category declares that the returned file is accessible
+ from a content provider that supports {@link android.provider.OpenableColumns}
+ and {@link android.content.ContentResolver#openFileDescriptor ContentResolver.openFileDescriptor()} -->
+ &lt;category android:name="android.intent.category.OPENABLE" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+<h3 id="OpenFile">Open a specific type of file</h3>
+
+<p>Instead of retrieving a copy of a file that you must import to your app
+(by using the {@link android.content.Intent#ACTION_GET_CONTENT} action), when running on Android
+4.4 or higher, you can instead request to <em>open</em> a file that's managed by another app by
+using the {@link android.content.Intent#ACTION_OPEN_DOCUMENT} action and specifying a MIME type.
+To also allow the user to instead create a new document that your app can write to, use the {@link
+android.content.Intent#ACTION_CREATE_DOCUMENT} action instead. For example, instead of
+selecting from existing PDF documents, the {@link android.content.Intent#ACTION_CREATE_DOCUMENT}
+intent allows users to select where they'd like to create a new document (within another app
+that manages the document's storage)&mdash;your app then receives the URI location of where it
+can write the new document.</p>
+
+<p>Whereas the intent delivered to your {@link android.app.Activity#onActivityResult
+onActivityResult()} method from the {@link android.content.Intent#ACTION_GET_CONTENT} action may
+return a URI of any type, the result intent from {@link android.content.Intent#ACTION_OPEN_DOCUMENT}
+and {@link android.content.Intent#ACTION_CREATE_DOCUMENT} always specify the chosen file as a {@code
+content:} URI that's backed by a {@link android.provider.DocumentsProvider}. You can open the
+file with {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()} and
+query its details using columns from {@link android.provider.DocumentsContract.Document}.</p>
+
+<p>The returned URI grants your app long-term read access to the file (also possibly
+with write access). So the {@link android.content.Intent#ACTION_OPEN_DOCUMENT} action is
+particularly useful (instead of using {@link android.content.Intent#ACTION_GET_CONTENT})
+when you want to read an existing file without making a copy into your app,
+or when you want to open and edit a file in place.</p>
+
+<p>You can also allow the user to select multiple files by adding
+{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE} to the intent, set to {@code true}.
+If the user selects just one item, then you can retrieve the item from {@link
+android.content.Intent#getData()}. If the user selects more than one item, then {@link
+android.content.Intent#getData()} returns null and you must instead
+retrieve each item from a {@link android.content.ClipData}
+object that is returned by {@link android.content.Intent#getClipData()}.</p>
+
+<p class="note"><strong>Note:</strong> Your intent <strong>must</strong> specify a MIME type and
+<strong>must</strong> declare the {@link android.content.Intent#CATEGORY_OPENABLE} category. If
+appropriate, you can specify more than one MIME type by adding an array of MIME types with the
+{@link android.content.Intent#EXTRA_MIME_TYPES} extra&mdash;if you do so, you must set the
+primary MIME type in {@link android.content.Intent#setType setType()} to {@code "*/*"}.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_OPEN_DOCUMENT} or<br/>
+{@link android.content.Intent#ACTION_CREATE_DOCUMENT}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>The MIME type corresponding to the file type the user should select.
+</dd>
+
+<dt><b>Extras</b> (optional)</dt>
+<dd>
+ <dl>
+ <dt>{@link android.content.Intent#EXTRA_MIME_TYPES}
+ <dd>An array of MIME types corresponding to the types of files your app is
+ requesting. When you use this extra, you must set the primary MIME type in
+ {@link android.content.Intent#setType setType()} to {@code "*/*"}.</dd>
+ <dt>{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE}
+ <dd>A boolean that declares whether the user can select more than one file at a time.
+ </dd>
+ <dt>{@link android.content.Intent#EXTRA_TITLE}
+ <dd>For use with {@link android.content.Intent#ACTION_CREATE_DOCUMENT} to specify
+ an initial file name.
+ </dd>
+ <dt>{@link android.content.Intent#EXTRA_LOCAL_ONLY}
+ <dd>A boolean that declares whether the returned file must be available directly from
+ the device, rather than requiring a download from a remote service.
+ </dd>
+ </dl>
+</dd>
+
+<dt><b>Category</b></dt>
+<dd>
+ <dl>
+ <dt>{@link android.content.Intent#CATEGORY_OPENABLE}</dt>
+ <dd>To return only "openable" files that can be represented as a file stream
+ with {@link android.content.ContentResolver#openFileDescriptor openFileDescriptor()}.</dd>
+ </dl>
+</dd>
+
+</dl>
+
+<p><b>Example intent to get a photo:</b></p>
+<pre>
+static final int REQUEST_IMAGE_OPEN = 1;
+
+public void selectImage() {
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.setType("image/*");
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ // Only the system receives the ACTION_OPEN_DOCUMENT, so no need to test.
+ startActivityForResult(intent, REQUEST_IMAGE_OPEN);
+}
+
+&#64;Override
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_IMAGE_OPEN && resultCode == RESULT_OK) {
+ Uri fullPhotoUri = data.getData();
+ // Do work with full size photo saved at fullPhotoUri
+ ...
+ }
+}
+</pre>
+
+<p>Third party apps cannot actually respond to an intent with the
+{@link android.content.Intent#ACTION_OPEN_DOCUMENT} action. Instead, the system receives this
+intent and displays all the files available from various apps in a unified user interface.</p>
+
+<p>To provide your app's files in this UI and allow other apps to open them, you must implement
+a {@link android.provider.DocumentsProvider} and include an intent filter for
+{@link android.provider.DocumentsContract#PROVIDER_INTERFACE}
+({@code "android.content.action.DOCUMENTS_PROVIDER"}). For example:
+
+<pre>
+&lt;provider ...
+ android:grantUriPermissions="true"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_DOCUMENTS">
+ &lt;intent-filter>
+ &lt;action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+ &lt;/intent-filter>
+&lt;/provider>
+</pre>
+
+<p>For more information about how to make the files managed by your app openable from other apps,
+read the <a href="{@docRoot}guide/topics/providers/document-provider.html">Storage Access
+Framework</a> guide.</p>
+
+
+
+
+
+
+
+
+
+
+
+<h2 id="Maps">Maps</h2>
+
+<h3 id="ViewMap">Show a location on a map</h3>
+
+<p>To open a map, use the {@link android.content.Intent#ACTION_VIEW} action and specify
+the location information in the intent data with one of the schemes defined below.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_VIEW}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>
+<dl>
+ <dt><code>geo:<em>latitude</em>,<em>longitude</em></code></dt>
+ <dd>Show the map at the given longitude and latitude.
+ <p>Example: <code>"geo:47.6,-122.3"</code>
+ </dd>
+ <dt><code>geo:<em>latitude</em>,<em>longitude</em>?z=<em>zoom</em></code></dt>
+ <dd>Show the map at the given longitude and latitude at a certain zoom level. A zoom level of
+ 1 shows the whole Earth, centered at the given <em>lat</em>,<em>lng</em>. The highest
+ (closest) zoom level is 23.
+ <p>Example: <code>"geo:47.6,-122.3?z=11"</code>
+ </dd>
+ <dt><code>geo:0,0?q=lat,lng(label)</code></dt>
+ <dd>Show the map at the given longitude and latitude with a string label.
+ <p>Example: <code>"geo:0,0?q=34.99,-106.61(Treasure)"</code>
+ </dd>
+ <dt><code>geo:0,0?q=my+street+address</code></dt>
+ <dd>Show the location for "my street address" (may be a specific address or location query).
+ <p>Example: <code>"geo:0,0?q=1600+amphitheatre+parkway+ca"</code>
+ </dd>
+</dl>
+</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None</dd>
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void showMap(Uri geoLocation) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(geoLocation);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.VIEW" />
+ &lt;data android:scheme="geo" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+
+
+<h2 id="Music">Music or Video</h2>
+
+
+<h3 id="PlayMedia">Play a media file</h3>
+
+<p>To play a music file, use the {@link android.content.Intent#ACTION_VIEW} action and
+specify the URI location of the file in the intent data.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_VIEW}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>
+ <dl>
+ <dt>{@code file:<em>&lt;URI></em>}
+ <dt>{@code content:<em>&lt;URI></em>}
+ <dt>{@code http:<em>&lt;URL></em>}
+ </dl>
+</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>
+ <dl>
+ <dt><code>"audio/*"</code>
+ <dt><code>"application/ogg"</code>
+ <dt><code>"application/x-ogg"</code>
+ <dt><code>"application/itunes"</code>
+ <dt>Or any other that your app may require.
+ </dl>
+</dd>
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void playMedia(Uri file) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(file);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.VIEW" />
+ &lt;data android:type="audio/*" />
+ &lt;data android:type="application/ogg" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+
+
+<h2 id="Phone">Phone</h2>
+
+
+<h3 id="DialPhone">Initiate a phone call</h3>
+
+<p>To open the phone app and dial a phone number, use the {@link
+android.content.Intent#ACTION_DIAL} action and specify a phone number using
+the URI scheme defined below. When the phone app opens, it displays the phone number
+but the user must press the <em>Call</em> button to begin the phone call.</p>
+
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_DIAL}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>{@code tel:&lt;phone-number>}</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None</dd>
+
+</dl>
+
+
+<p>Valid telephone numbers are those defined
+in <a href="http://tools.ietf.org/html/rfc3966">the IETF RFC 3966</a>.
+Valid examples include the following:</p>
+<ul>
+<li><code>tel:2125551212</code> </li>
+<li><code>tel:(212) 555 1212</code></li>
+</ul>
+<p>The Phone's dialer is good at normalizing schemes, such as
+telephone numbers. So the scheme described isn't strictly required in the
+{@link android.net.Uri#parse(String) Uri.parse()} method.
+However, if you have not tried a scheme or are unsure whether it
+can be handled, use the {@link android.net.Uri#fromParts Uri.fromParts()}
+method instead.</p>
+
+
+<p><b>Example intent:</b></p>
+<pre>
+public void dialPhoneNumber(String phoneNumber) {
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ intent.setData(Uri.parse("tel:" + phoneNumber));
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+
+
+
+
+
+
+
+
+<h2 id="Settings">Settings</h2>
+
+<h3 id="OpenSettings">Open a specific section of Settings</h3>
+
+<p>To open a screen in the system settings when your app requires the user to change something,
+use one of the following intent actions to open the settings screen respective to the action name.
+</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>
+{@link android.provider.Settings#ACTION_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_WIRELESS_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_AIRPLANE_MODE_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_WIFI_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_APN_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_BLUETOOTH_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_DATE_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_LOCALE_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_INPUT_METHOD_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_DISPLAY_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_SECURITY_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_LOCATION_SOURCE_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_INTERNAL_STORAGE_SETTINGS}<br/>
+{@link android.provider.Settings#ACTION_MEMORY_CARD_SETTINGS}<br/>
+<p>See the {@link android.provider.Settings} documentation for additional settings screens
+that are available.</p>
+</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None</dd>
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void openWifiSettings() {
+ Intent intent = new Intent(Intent.ACTION_WIFI_SETTINGS);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+
+
+
+
+
+<h2 id="Messaging">Text Messaging</h2>
+
+<h3 id="SendMessage">Compose an SMS/MMS message with attachment</h3>
+
+<p>To initiate an SMS or MMS text message, use one of the intent actions below and specify message
+details such as the phone number, subject, and message body using the extra keys listed below.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_SENDTO} or<br>
+ {@link android.content.Intent#ACTION_SEND} or<br>
+ {@link android.content.Intent#ACTION_SEND_MULTIPLE}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>
+ <dl>
+ <dt>{@code sms:<em>&lt;phone_number></em>}
+ <dt>{@code smsto:<em>&lt;phone_number></em>}
+ <dt>{@code mms:<em>&lt;phone_number></em>}
+ <dt>{@code mmsto:<em>&lt;phone_number></em>}
+ </dl>
+ <p>Each of these schemes are handled the same.
+</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>
+ <dl>
+ <dt>{@link org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE} (<code>"text/plain"</code>)
+ <dt><code>"image/*"</code>
+ <dt><code>"video/*"</code>
+ </dl>
+</dd>
+
+<dt><b>Extras</b> (optional)</dt>
+<dd>
+ <dl>
+ <dt><code>"subject"</code></dt>
+ <dd>A string for the message subject (usually for MMS only).</dd>
+ <dt><code>"sms_body"</code></dt>
+ <dd>A string for the text message.</dd>
+ <dt>{@link android.content.Intent#EXTRA_STREAM}</dt>
+ <dd>A {@link android.net.Uri} pointing to the
+image or video to attach. If using the {@link android.content.Intent#ACTION_SEND_MULTIPLE} action,
+this extra should be an {@link java.util.ArrayList} of {@link
+android.net.Uri}s pointing to the images/videos to attach.</dd>
+ <dl>
+</dd>
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void composeMmsMessage(String message, Uri attachment) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(HTTP.PLAIN_TEXT_TYPE);
+ intent.putExtra("sms_body", message);
+ intent.putExtra(Intent.EXTRA_STREAM, attachment);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<p>If you want to ensure that your intent is handled only by a text messaging app (and not other
+email or social apps), then use the {@link android.content.Intent#ACTION_SENDTO} action
+and include the {@code "smsto:"} data scheme. For example:</p>
+
+<pre>
+public void composeMmsMessage(String message, Uri attachment) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setData(Uri.parse("smsto:")); // This ensures only SMS apps respond
+ intent.putExtra("sms_body", message);
+ intent.putExtra(Intent.EXTRA_STREAM, attachment);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.SEND" />
+ &lt;data android:type="text/plain" />
+ &lt;data android:type="image/*" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+<p class="note"><strong>Note:</strong> If you're developing an SMS/MMS messaging app, you must
+implement intent filters for several additional actions in order to be available as the
+<em>default SMS app</em> on Android 4.4 and higher. For more information, see the documentation
+at {@link android.provider.Telephony}.</p>
+
+
+
+
+
+
+
+
+
+
+<h2 id="Browser">Web Browser</h2>
+
+<h3 id="ViewUrl">Load a web URL</h3>
+
+<p>To open a web page, use the {@link android.content.Intent#ACTION_VIEW} action
+and specify the web URL in the intent data.</p>
+
+<dl>
+ <dt><b>Action</b></dt>
+ <dd>{@link android.content.Intent#ACTION_VIEW}<dd>
+
+ <dt><b>Data URI Scheme</b></dt>
+ <dd>{@code http:<em>&lt;URL></em>}<br/>
+ {@code https:<em>&lt;URL></em>}</dd>
+
+ <dt><b>MIME Type</b></dt>
+ <dd>
+ <dl>
+ <dt>{@link org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE} (<code>"text/plain"</code>)
+ <dt><code>"text/html"</code>
+ <dt><code>"application/xhtml+xml"</code>
+ <dt><code>"application/vnd.wap.xhtml+xml"</code>
+ </dl>
+ </dd>
+</dl>
+
+
+<p><b>Example intent:</b></p>
+<pre>
+public void openWebPage(String url) {
+ Uri webpage = Uri.parse(url);
+ Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.VIEW" />
+ &lt;!-- Include the host attribute if you want your app to respond
+ only to URLs with your app's domain. -->
+ &lt;data android:scheme="http" android:host="www.example.com" />
+ &lt;category android:name="android.intent.category.DEFAULT" />
+ &lt;!-- The BROWSABLE category is required to get links from web pages. -->
+ &lt;category android:name="android.intent.category.BROWSABLE" />
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+<p class="note"><strong>Tip:</strong> If your Android app provides functionality similar to
+your web site, include an intent filter for URLs that point to your web site. Then,
+if users have your app installed, links from emails or other web pages pointing to your web site
+open your Android app instead of your web page.</p>
+
+
+
+
+<h3 id="SearchWeb">Perform a web search</h3>
+
+<p>To initiate a web search, use the {@link android.content.Intent#ACTION_WEB_SEARCH} action
+and specify the search string in the
+{@link android.app.SearchManager#QUERY SearchManager.QUERY} extra.</p>
+
+
+<dl>
+ <dt><b>Action</b></dt>
+ <dd>{@link android.content.Intent#ACTION_WEB_SEARCH}</dd>
+
+ <dt><b>Data URI Scheme</b></dt>
+ <dd>None</dd>
+
+ <dt><b>MIME Type</b></dt>
+ <dd>None</dd>
+
+ <dt><b>Extras</b></dt>
+ <dd>
+ <dl>
+ <dt>{@link android.app.SearchManager#QUERY SearchManager.QUERY}</dt>
+ <dd>The search string.</dd>
+ </dl>
+ </dd>
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void searchWeb(String query) {
+ Intent intent = new Intent(Intent.ACTION_SEARCH);
+ intent.putExtra(SearchManager.QUERY, query);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+
+
diff --git a/docs/html/guide/components/intents-filters.jd b/docs/html/guide/components/intents-filters.jd
index dfe5fac..2f8c407 100644
--- a/docs/html/guide/components/intents-filters.jd
+++ b/docs/html/guide/components/intents-filters.jd
@@ -1,4 +1,5 @@
page.title=Intents and Intent Filters
+page.tags="IntentFilter"
@jd:body
<div id="qv-wrapper">
@@ -6,1049 +7,906 @@ page.title=Intents and Intent Filters
<h2>In this document</h2>
<ol>
-<li><a href="#iobjs">Intent Objects</a></li>
-<li><a href="#ires">Intent Resolution</a></li>
-<li style="margin-left: 2em"><a href="#ifs">Intent filters</a></li>
-<li style="margin-left: 2em"><a href="#ccases">Common cases</a></li>
-<li style="margin-left: 2em"><a href="#imatch">Using intent matching</a></li>
-<li><a href="#npex">Note Pad Example</a></li>
+ <li><a href="#Types">Intent Types</a></li>
+ <li><a href="#Building">Building an Intent</a>
+ <ol>
+ <li><a href="#ExampleExplicit">Example explicit intent</a></li>
+ <li><a href="#ExampleSend">Example implicit intent</a></li>
+ <li><a href="#ForceChooser">Forcing an app chooser</a></li>
+ </ol>
+ </li>
+ <li><a href="#Receiving">Receiving an Implicit Intent</a>
+ <ol>
+ <li><a href="#ExampleFilters">Example filters</a></li>
+ </ol>
+ </li>
+ <li><a href="#PendingIntent">Using a Pending Intent</a></li>
+ <li><a href="#Resolution">Intent Resolution</a>
+ <ol>
+ <li><a href="#ActionTest">Action test</a></li>
+ <li><a href="#CategoryTest">Category test</a></li>
+ <li><a href="#DataTest">Data test</a></li>
+ <li><a href="#imatch">Intent matching</a></li>
+ </ol>
+ </li>
</ol>
-<h2>Key classes</h2>
+<h2>See also</h2>
<ol>
-<li>{@link android.content.Intent}</li>
-<li>{@link android.content.IntentFilter}</li>
-<li>{@link android.content.BroadcastReceiver}</li>
-<li>{@link android.content.pm.PackageManager}</li>
+<li><a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a></li>
+<li><a href="{@docRoot}training/sharing/index.html">Sharing Content</a></li>
</ol>
</div>
</div>
-<p>
-Three of the core components of an application &mdash; activities, services, and
-broadcast receivers &mdash; are activated through messages, called <i>intents</i>.
-Intent messaging is a facility for late run-time binding between components in the same
-or different applications. The intent itself, an {@link android.content.Intent}
-object, is a passive data structure holding an abstract description of an operation
-to be performed &mdash; or, often in the case of broadcasts, a description of something
-that has happened and is being announced. There are separate mechanisms for
-delivering intents to each type of component:
-</p>
+
+
+<p>An {@link android.content.Intent} is a messaging object you can use to request an action
+from another <a href="{@docRoot}guide/components/fundamentals.html#Components">app component</a>.
+Although intents facilitate communication between components in several ways, there are three
+fundamental use-cases:</p>
<ul>
-<li>An Intent object is passed to <code>{@link android.content.Context#startActivity
-Context.startActivity()}</code> or <code>{@link android.app.Activity#startActivityForResult
-Activity.startActivityForResult()}</code> to launch an activity or get an existing
-activity to do something new. (It can also be passed to
-<code>{@link android.app.Activity#setResult(int, Intent) Activity.setResult()}</code>
-to return information to the activity that called {@code startActivityForResult()}.)</li>
-
-<li><p>An Intent object is passed to <code>{@link android.content.Context#startService
-Context.startService()}</code> to initiate a service or deliver new instructions to an
-ongoing service. Similarly, an intent can be passed to <code>{@link
-android.content.Context#bindService Context.bindService()}</code> to establish a
-connection between the calling component and a target service. It can optionally
-initiate the service if it's not already running.</p></li>
-
-<li><p>Intent objects passed to any of the broadcast methods (such as <code>{@link
-android.content.Context#sendBroadcast(Intent) Context.sendBroadcast()}</code>,
-<code>{@link android.content.Context#sendOrderedBroadcast(Intent, String)
-Context.sendOrderedBroadcast()}</code>, or <code>{@link
-android.content.Context#sendStickyBroadcast Context.sendStickyBroadcast()}</code>)
-are delivered to all interested broadcast receivers. Many kinds of broadcasts
-originate in system code.</p></li>
+<li><b>To start an activity:</b>
+<p>An {@link android.app.Activity} represents a single screen in an app. You can start a new
+instance of an {@link android.app.Activity} by passing an {@link android.content.Intent}
+to {@link android.content.Context#startActivity startActivity()}. The {@link android.content.Intent}
+describes the activity to start and carries any necessary data.</p>
+
+<p>If you want to receive a result from the activity when it finishes,
+call {@link android.app.Activity#startActivityForResult
+startActivityForResult()}. Your activity receives the result
+as a separate {@link android.content.Intent} object in your activity's {@link
+android.app.Activity#onActivityResult onActivityResult()} callback.
+For more information, see the <a
+href="{@docRoot}guide/components/activities.html">Activities</a> guide.</p></li>
+
+<li><b>To start a service:</b>
+<p>A {@link android.app.Service} is a component that performs operations in the background
+without a user interface. You can start a service to perform a one-time operation
+(such as download a file) by passing an {@link android.content.Intent}
+to {@link android.content.Context#startService startService()}. The {@link android.content.Intent}
+describes the service to start and carries any necessary data.</p>
+
+<p>If the service is designed with a client-server interface, you can bind to the service
+from another component by passing an {@link android.content.Intent} to {@link
+android.content.Context#bindService bindService()}</code>. For more information, see the <a
+href="{@docRoot}guide/components/services.html">Services</a> guide.</p></li>
+
+<li><b>To deliver a broadcast:</b>
+<p>A broadcast is a message that any app can receive. The system delivers various
+broadcasts for system events, such as when the system boots up or the device starts charging.
+You can deliver a broadcast to other apps by passing an {@link android.content.Intent}
+to {@link android.content.Context#sendBroadcast(Intent) sendBroadcast()},
+{@link android.content.Context#sendOrderedBroadcast(Intent, String)
+sendOrderedBroadcast()}, or {@link
+android.content.Context#sendStickyBroadcast sendStickyBroadcast()}.</p>
+</li>
</ul>
-<p>
-In each case, the Android system finds the appropriate activity, service, or set
-of broadcast receivers to respond to the intent, instantiating them if necessary.
-There is no overlap within these messaging systems: Broadcast intents are delivered
-only to broadcast receivers, never to activities or services. An intent passed to
-{@code startActivity()} is delivered only to an activity, never to a service or
-broadcast receiver, and so on.
-</p>
-<p>
-This document begins with a description of Intent objects. It then describes the
-rules Android uses to map intents to components &mdash; how it resolves which
-component should receive an intent message. For intents that don't explicitly
-name a target component, this process involves testing the Intent object against
-<i>intent filters</i> associated with potential targets.
-</p>
-<h2><a name="iobjs"></a>Intent Objects</h2>
+<h2 id="Types">Intent Types</h2>
-<p>
-An {@link android.content.Intent} object is a bundle of information. It
-contains information of interest to the component that receives the intent
-(such as the action to be taken and the data to act on) plus information
-of interest to the Android system (such as the category of component that
-should handle the intent and instructions on how to launch a target activity).
-Principally, it can contain the following:
+<p>There are two types of intents:</p>
+
+<ul>
+<li><b>Explicit intents</b> specify the component to start by name (the
+fully-qualified class name). You'll typically use an explicit intent to start a component in
+your own app, because you know the class name of the activity or service you want to start. For
+example, start a new activity in response to a user action or start a service to download
+a file in the background.</li>
+
+<li><b>Implicit intents</b> do not name a specific component, but instead declare a general action
+to perform, which allows a component from another app to handle it. For example, if you want to
+show the user a location on a map, you can use an implicit intent to request that another capable
+app show a specified location on a map.</li>
+</ul>
+
+<p>When you create an explicit intent to start an activity or service, the system immediately
+starts the app component specified in the {@link android.content.Intent} object.</p>
+
+<div class="figure" style="width:446px">
+<img src="{@docRoot}images/components/intent-filters@2x.png" width="446" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong> Illustration of how an implicit intent is
+delivered through the system to start another activity: <b>[1]</b> <em>Activity A</em> creates an
+{@link android.content.Intent} with an action description and passes it to {@link
+android.content.Context#startActivity startActivity()}. <b>[2]</b> The Android System searches all
+apps for an intent filter that matches the intent. When a match is found, <b>[3]</b> the system
+starts the matching activity (<em>Activity B</em>) by invoking its {@link
+android.app.Activity#onCreate onCreate()} method and passing it the {@link android.content.Intent}.
</p>
+</div>
+
+<p>When you create an implicit intent, the Android system finds the appropriate component to start
+by comparing the contents of the intent to the <em>intent filters</em> declared in the <a href=
+"{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a> of other apps on the
+device. If the intent matches an intent filter, the system starts that component and delivers it
+the {@link android.content.Intent} object. If multiple intent filters are compatible, the system
+displays a dialog so the user can pick which app to use.</p>
+
+<p>An intent filter is an expression in an app's manifest file that
+specifies the type of intents that the component
+would like to receive. For instance, by declaring an intent filter for an activity,
+you make it possible for other apps to directly start your activity with a certain kind of intent.
+Likewise, if you do <em>not</em> declare any intent filters for an activity, then it can be started
+only with an explicit intent.</p>
+
+<p class="caution"><strong>Caution:</strong> To ensure your app is secure, always use an explicit
+intent when starting a {@link android.app.Service} and do not
+declare intent filters for your services. Using an implicit intent to start a service is a
+security hazard because you cannot be certain what service will respond to the intent,
+and the user cannot see which service starts.</p>
+
+
+
+
+
+<h2 id="Building">Building an Intent</h2>
+
+<p>An {@link android.content.Intent} object carries information that the Android system uses
+to determine which component to start (such as the exact component name or component
+category that should receive the intent), plus information that the recipient component uses in
+order to properly perform the action (such as the action to take and the data to act upon).</p>
+
+
+<p>The primary information contained in an {@link android.content.Intent} is the following:</p>
<dl>
-<dt><b>Component name</b><a name="cname"></a></dt>
-<dd>The name of the component that should handle the intent. This field is
-a {@link android.content.ComponentName} object &mdash; a combination of the
-fully qualified class name of the target component (for example "{@code
-com.example.project.app.FreneticActivity}") and the package name set
-in the manifest file of the application where the component resides (for
-example, "{@code com.example.project}"). The package part of the component
-name and the package name set in the manifest do not necessarily have to match.
-
-<p>
-The component name is optional. If it is set, the Intent object is
-delivered to an instance of the designated class. If it is not set,
-Android uses other information in the Intent object to locate a suitable
-target &mdash; see <a href="#ires">Intent Resolution</a>, later in this
-document.
-</p>
+<dt><b>Component name</b></dt>
+<dd>The name of the component to start.
+
+<p>This is optional, but it's the critical piece of information that makes an intent
+<b>explicit</b>, meaning that the intent should be delivered only to the app component
+defined by the component name. Without a component name, the intent is <b>implicit</b> and the
+system decides which component should receive the intent based on the other intent information
+(such as the action, data, and category&mdash;described below). So if you need to start a specific
+component in your app, you should specify the component name.</p>
+
+<p class="note"><strong>Note:</strong> When starting a {@link android.app.Service}, you should
+<strong>always specify the component name</strong>. Otherwise, you cannot be certain what service
+will respond to the intent, and the user cannot see which service starts.</p>
+
+<p>This field of the {@link android.content.Intent} is a
+{@link android.content.ComponentName} object, which you can specify using a fully
+qualified class name of the target component, including the package name of the app. For example,
+{@code com.example.ExampleActivity}. You can set the component name with {@link
+android.content.Intent#setComponent setComponent()}, {@link android.content.Intent#setClass
+setClass()}, {@link android.content.Intent#setClassName(String, String) setClassName()}, or with the
+{@link android.content.Intent} constructor.</p>
-<p>
-The component name is set by <code>{@link android.content.Intent#setComponent
-setComponent()}</code>, <code>{@link android.content.Intent#setClass
-setClass()}</code>, or <code>{@link android.content.Intent#setClassName(String, String)
-setClassName()}</code> and read by <code>{@link android.content.Intent#getComponent
-getComponent()}</code>.
-</p>
</dd>
<p><dt><b>Action</b></dt>
-<dd>A string naming the action to be performed &mdash; or, in the case of broadcast
-intents, the action that took place and is being reported. The Intent class defines
-a number of action constants, including these:
-</p>
+<dd>A string that specifies the generic action to perform (such as <em>view</em> or <em>pick</em>).
-<table>
-<tr>
- <th>Constant</th>
- <th>Target component</th>
- <th>Action</th>
-</tr><tr>
- <td>{@code ACTION_CALL}
- <td>activity
- <td>Initiate a phone call.
-</tr><tr>
- <td>{@code ACTION_EDIT}
- <td>activity
- <td>Display data for the user to edit.
-</tr><tr>
- <td>{@code ACTION_MAIN}
- <td>activity
- <td>Start up as the initial activity of a task, with no data input and no returned output.
-</tr><tr>
- <td>{@code ACTION_SYNC}
- <td>activity
- <td>Synchronize data on a server with data on the mobile device.
-</tr><tr>
- <td>{@code ACTION_BATTERY_LOW}
- <td>broadcast receiver
- <td>A warning that the battery is low.
-</tr><tr>
- <td>{@code ACTION_HEADSET_PLUG}
- <td>broadcast receiver
- <td>A headset has been plugged into the device, or unplugged from it.
-</tr><tr>
- <td>{@code ACTION_SCREEN_ON}
- <td>broadcast receiver
- <td>The screen has been turned on.
-</tr><tr>
- <td>{@code ACTION_TIMEZONE_CHANGED}
- <td>broadcast receiver
- <td>The setting for the time zone has changed.
-</tr>
-</table>
+<p>In the case of a broadcast intent, this is the action that took place and is being reported.
+The action largely determines how the rest of the intent is structured&mdash;particularly
+what is contained in the data and extras.
-<p>
-See the {@link android.content.Intent} class description for a list of
-pre-defined constants for generic actions. Other actions are defined
-elsewhere in the Android API.
-You can also define your own action strings for activating the components
-in your application. Those you invent should include the application
-package as a prefix &mdash; for example:
-"<code>com.example.project.SHOW_COLOR</code>".
-</p>
+<p>You can specify your own actions for use by intents within your app (or for use by other
+apps to invoke components in your app), but you should usually use action constants
+defined by the {@link android.content.Intent} class or other framework classes. Here are some
+common actions for starting an activity:</p>
-<p>
-The action largely determines how the rest of the intent is structured
-&mdash; particularly the <a href="#data">data</a> and
-<a href="#extras">extras</a> fields &mdash;
-much as a method name determines a set of arguments and a return value.
-For this reason, it's a good idea to use action names that are
-as specific as possible, and to couple them tightly to the other fields of
-the intent. In other words, instead of defining an action in isolation,
-define an entire protocol for the Intent objects your components can handle.
-</p>
+<dl>
+<dt>{@link android.content.Intent#ACTION_VIEW}</dt>
+ <dd>Use this action in an intent with {@link
+ android.content.Context#startActivity startActivity()} when you have some information that
+ an activity can show to the user, such as a photo to view in a gallery app, or an address to
+ view in a map app.</dd>
+
+<dt>{@link android.content.Intent#ACTION_SEND}</dt>
+ <dd>Also known as the "share" intent, you should use this in an intent with {@link
+ android.content.Context#startActivity startActivity()} when you have some data that the user can
+ share through another app, such as an email app or social sharing app.</dd>
+</dl>
-<p>
-The action in an Intent object is set by the
-<code>{@link android.content.Intent#setAction setAction()}</code>
-method and read by
-<code>{@link android.content.Intent#getAction getAction()}</code>.
-</p>
-</dd>
+<p>See the {@link android.content.Intent} class reference for more
+constants that define generic actions. Other actions are defined
+elsewhere in the Android framework, such as in {@link android.provider.Settings} for actions
+that open specific screens in the system's Settings app.</p>
-<p><dt><b>Data</b><a name="data"></a></dt>
-<dd>The URI of the data to be acted on and the MIME type of that data. Different
-actions are paired with different kinds of data specifications. For example, if
-the action field is {@code ACTION_EDIT},
-the data field would contain the URI of the document to be displayed for editing.
-If the action is {@code ACTION_CALL}, the data field would be a {@code tel:} URI
-with the number to call. Similarly, if the action is {@code ACTION_VIEW} and the
-data field is an {@code http:} URI, the receiving activity would be called upon
-to download and display whatever data the URI refers to.
+<p>You can specify the action for an intent with {@link android.content.Intent#setAction
+setAction()} or with an {@link android.content.Intent} constructor.</p>
-<p>
-When matching an intent to a component that is capable of handling the data,
-it's often important to know the type of data (its MIME type) in addition to its URI.
-For example, a component able to display image data should not be called
-upon to play an audio file.
-</p>
+<p>If you define your own actions, be sure to include your app's package name
+as a prefix. For example:</p>
+<pre>static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";</pre>
+</dd>
-<p>
-In many cases, the data type can be inferred from the URI &mdash; particularly
-{@code content:} URIs, which indicate that the data is located on the device and
-controlled by a content provider (see the
-<a href="{@docRoot}guide/topics/providers/content-providers.html">separate
-discussion on content providers</a>). But the type can also be explicitly set
-in the Intent object.
-The <code>{@link android.content.Intent#setData setData()}</code> method specifies
-data only as a URI, <code>{@link android.content.Intent#setType setType()}</code>
-specifies it only as a MIME type, and <code>{@link
-android.content.Intent#setDataAndType setDataAndType()}</code> specifies it as both
-a URI and a MIME type. The URI is read by <code>{@link
-android.content.Intent#getData getData()}</code> and the type by <code>{@link
-android.content.Intent#getType getType()}</code>.
-</p>
+<dt><b>Data</b></dt>
+<dd>The URI (a {@link android.net.Uri} object) that references the data to be acted on and/or the
+MIME type of that data. The type of data supplied is generally dictated by the intent's action. For
+example, if the action is {@link android.content.Intent#ACTION_EDIT}, the data should contain the
+URI of the document to edit.
+
+<p>When creating an intent,
+it's often important to specify the type of data (its MIME type) in addition to its URI.
+For example, an activity that's able to display images probably won't be able
+to play an audio file, even though the URI formats could be similar.
+So specifying the MIME type of your data helps the Android
+system find the best component to receive your intent.
+However, the MIME type can sometimes be inferred from the URI&mdash;particularly when the data is a
+{@code content:} URI, which indicates the data is located on the device and controlled by a
+{@link android.content.ContentProvider}, which makes the data MIME type visible to the system.</p>
+
+<p>To set only the data URI, call {@link android.content.Intent#setData setData()}.
+To set only the MIME type, call {@link android.content.Intent#setType setType()}. If necessary, you
+can set both explicitly with {@link
+android.content.Intent#setDataAndType setDataAndType()}.</p>
+
+<p class="caution"><strong>Caution:</strong> If you want to set both the URI and MIME type,
+<strong>do not</strong> call {@link android.content.Intent#setData setData()} and
+{@link android.content.Intent#setType setType()} because they each nullify the value of the other.
+Always use {@link android.content.Intent#setDataAndType setDataAndType()} to set both
+URI and MIME type.</p>
</dd>
<p><dt><b>Category</b></dt>
-<dd>A string containing additional information about the kind of component
-that should handle the intent. Any number of category descriptions can be
-placed in an Intent object. As it does for actions, the Intent class defines
-several category constants, including these:
-
-<table>
-<tr>
- <th>Constant</th>
- <th>Meaning</th>
-</tr><tr>
- <td>{@code CATEGORY_BROWSABLE}
- <td>The target activity can be safely invoked by the browser to display data
- referenced by a link &mdash; for example, an image or an e-mail message.
-</tr><tr>
- <td>{@code CATEGORY_GADGET}
- <td>The activity can be embedded inside of another activity that hosts gadgets.
-</tr><tr>
- <td>{@code CATEGORY_HOME}
- <td>The activity displays the home screen, the first screen the user sees when
- the device is turned on or when the <em>Home</em> button is pressed.
-</tr><tr>
- <td>{@code CATEGORY_LAUNCHER}
- <td>The activity can be the initial activity of a task and is listed in
- the top-level application launcher.
-</tr><tr>
- <td>{@code CATEGORY_PREFERENCE}
- <td>The target activity is a preference panel.
-</tr>
-</table>
+<dd>A string containing additional information about the kind of component
+that should handle the intent. Any number of category descriptions can be
+placed in an intent, but most intents do not require a category.
+Here are some common categories:
-<p>
-See the {@link android.content.Intent} class description for the full list of
-categories.
-</p>
+<dl>
+<dt>{@link android.content.Intent#CATEGORY_BROWSABLE}</dt>
+ <dd>The target activity allows itself to be started by a web browser to display data
+ referenced by a link&mdash;such as an image or an e-mail message.
+ </dd>
+<dt>{@link android.content.Intent#CATEGORY_LAUNCHER}</dt>
+ <dd>The activity is the initial activity of a task and is listed in
+ the system's application launcher.
+ </dd>
+</dl>
-<p>
-The <code>{@link android.content.Intent#addCategory addCategory()}</code> method
-places a category in an Intent object, <code>{@link android.content.Intent#removeCategory
-removeCategory()}</code> deletes a category previously added, and <code>{@link android.content.Intent#getCategories getCategories()}</code> gets the set of all
-categories currently in the object.
-</p>
+<p>See the {@link android.content.Intent} class description for the full list of
+categories.</p>
+
+<p>You can specify a category with {@link android.content.Intent#addCategory addCategory()}.</p>
</dd>
+</dl>
-<p><dt><b>Extras</b><a name="extras"></a></dt>
-<dd>Key-value pairs for additional information that should be delivered to the
-component handling the intent. Just as some actions are paired with particular
-kinds of data URIs, some are paired with particular extras. For example, an
-{@code ACTION_TIMEZONE_CHANGED} intent has a "{@code time-zone}" extra that
-identifies the new time zone, and {@code ACTION_HEADSET_PLUG} has a
-"{@code state}" extra indicating whether the headset is now plugged in or
-unplugged, as well as a "{@code name}" extra for the type of headset.
-If you were to invent a {@code SHOW_COLOR} action, the color value would
-be set in an extra key-value pair.
-<p>
-The Intent object has a series of {@code put...()} methods for inserting various
-types of extra data and a similar set of {@code get...()} methods for reading
-the data. These methods parallel those for {@link android.os.Bundle} objects.
-In fact, the extras can be installed and read as a Bundle using the <code>{@link
-android.content.Intent#putExtras putExtras()}</code> and <code>{@link
-android.content.Intent#getExtras getExtras()}</code> methods.
-</p>
+<p>These properties listed above (component name, action, data, and category) represent the
+defining characteristics of an intent. By reading these properties, the Android system
+is able to resolve which app component it should start.</p>
+
+<p>However, an intent can carry additional information that does not affect
+how it is resolved to an app component. An intent can also supply:</p>
+
+<dl>
+<dt><b>Extras</b></dt>
+<dd>Key-value pairs that carry additional information required to accomplish the requested action.
+Just as some actions use particular kinds of data URIs, some actions also use particular extras.
+
+<p>You can add extra data with various {@link android.content.Intent#putExtra putExtra()} methods,
+each accepting two parameters: the key name and the value.
+You can also create a {@link android.os.Bundle} object with all the extra data, then insert
+the {@link android.os.Bundle} in the {@link android.content.Intent} with {@link
+android.content.Intent#putExtras putExtras()}.</p>
+
+<p>For example, when creating an intent to send an email with
+{@link android.content.Intent#ACTION_SEND}, you can specify the "to" recipient with the
+{@link android.content.Intent#EXTRA_EMAIL} key, and specify the "subject" with the
+{@link android.content.Intent#EXTRA_SUBJECT} key.</p>
+
+<p>The {@link android.content.Intent} class specifies many {@code EXTRA_*} constants
+for standardized data types. If you need to declare your own extra keys (for intents that
+your app receives), be sure to include your app's package name
+as a prefix. For example:</p>
+<pre>static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";</pre>
</dd>
-<p><dt><b>Flags</b></dt>
-<dd>Flags of various sorts. Many instruct the Android system how to launch an
-activity (for example, which task the activity should belong to) and how to treat
-it after it's launched (for example, whether it belongs in the list of recent
-activities). All these flags are defined in the Intent class.
+<dt><b>Flags</b></dt>
+<dd>Flags defined in the {@link android.content.Intent} class that function as metadata for the
+intent. The flags may instruct the Android system how to launch an activity (for example, which
+<a href="{@docRoot}guide/components/tasks-and-back-stack.html">task</a> the activity should belong
+to) and how to treat it after it's launched (for example, whether it belongs in the list of recent
+activities).
+
+<p>For more information, see the {@link android.content.Intent#setFlags setFlags()} method.</p>
</dd>
</dl>
-<p>
-The Android system and the applications that come with the platform employ
-Intent objects both to send out system-originated broadcasts and to activate
-system-defined components. To see how to structure an intent to activate a
-system component, consult the
-<a href="{@docRoot}guide/appendix/g-app-intents.html">list of intents</a>
-in the reference.
-</p>
-<h2><a name="ires"></a>Intent Resolution</h2>
-<p>
-Intents can be divided into two groups:
-</p>
+<h3 id="ExampleExplicit">Example explicit intent</h3>
-<ul>
-<li><i>Explicit intents</i> designate the target component by its
-name (the <a href="#cname">component name field</a>, mentioned earlier,
-has a value set). Since component names would generally not be known to
-developers of other applications, explicit intents are typically used
-for application-internal messages &mdash; such as an activity starting
-a subordinate service or launching a sister activity.</li>
-
-<li><p><i>Implicit intents</i> do not name a target (the field for
-the component name is blank). Implicit intents are often used to
-activate components in other applications.</p></li>
-</ul>
+<p>An explicit intent is one that you use to launch a specific app component, such as
+a particular activity or service in your app. To create an explicit intent, define
+the component name for the {@link android.content.Intent} object&mdash;all
+other intent properties are optional.</p>
-<p>
-Android delivers an explicit intent to an instance of the designated
-target class. Nothing in the Intent object other than the component
-name matters for determining which component should get the intent.
-</p>
+<p>For example, if you built a service in your app, named {@code DownloadService},
+designed to download a file from the web, you can start it with the following code:</p>
-<p>
-A different strategy is needed for implicit intents. In the absence of a
-designated target, the Android system must find the best component (or
-components) to handle the intent &mdash; a single activity or service to
-perform the requested action or the set of broadcast receivers to respond
-to the broadcast announcement. It does so by comparing the contents of
-the Intent object to <i>intent filters</i>, structures associated with
-components that can potentially receive intents. Filters advertise the
-capabilities of a component and delimit the intents it can handle. They
-open the component to the possibility of receiving implicit intents of
-the advertised type. If a component does not have any intent filters,
-it can receive only explicit intents. A component with filters can
-receive both explicit and implicit intents.
-</p>
+<pre>
+// Executed in an Activity, so 'this' is the {@link android.content.Context}
+// The fileUrl is a string URL, such as "http://www.example.com/image.png"
+Intent downloadIntent = new Intent(this, DownloadService.class);
+downloadIntent.setData({@link android.net.Uri#parse Uri.parse}(fileUrl));
+startService(downloadIntent);
+</pre>
-<p>
-Only three aspects of an Intent object are consulted when the object
-is tested against an intent filter:
-</p>
+<p>The {@link android.content.Intent#Intent(Context,Class)}
+constructor supplies the app {@link android.content.Context} and the
+component a {@link java.lang.Class} object. As such,
+this intent explicitly starts the {@code DownloadService} class in the app.</p>
-<p style="margin-left: 2em">action
-<br/>data (both URI and data type)
-<br/>category</p>
+<p>For more information about building and starting a service, see the
+<a href="{@docRoot}guide/components/services.html">Services</a> guide.</p>
-<p>
-The extras and flags play no part in resolving which component receives
-an intent.
-</p>
-<h3><a name="ifs"></a>Intent filters</h3>
-<p>
-To inform the system which implicit intents they can handle, activities,
-services, and broadcast receivers can have one or more intent filters.
-Each filter describes a capability of the component, a set of intents that
-the component is willing to receive. It, in effect, filters in
-intents of a desired type, while filtering out unwanted
-intents &mdash; but only unwanted implicit intents (those that don't name
-a target class). An explicit intent is always delivered to its target,
-no matter what it contains; the filter is not consulted. But an implicit
-intent is delivered to a component only if it can pass through one of the
-component's filters.
-</p>
+<h3 id="ExampleSend">Example implicit intent</h3>
-<p>
-A component has separate filters for each job it can do, each face it can
-present to the user. For example, the NoteEditor activity of the sample
-Note Pad application has two filters &mdash; one for starting up with a
-specific note that the user can view or edit, and another for starting
-with a new, blank note that the user can fill in and save. (All of Note
-Pad's filters are described in the <a href="#npex">Note Pad Example</a>
-section, later.)
-</p>
+<p>An implicit intent specifies an action that can invoke any app on the device able
+to perform the action. Using an implicit intent is useful when your app cannot perform the
+action, but other apps probably can and you'd like the user to pick which app to use.</p>
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Filters and security</h2>
-<p>An intent filter cannot be relied on for security. While it opens a
-component to receiving only certain kinds of implicit intents, it does
-nothing to prevent explicit intents from targeting the component. Even
-though a filter restricts the intents a component will be asked to handle
-to certain actions and data sources, someone could always put
-together an explicit intent with a different action and data source, and
-name the component as the target.
-</p>
+<p>For example, if you have content you want the user to share with other people, create an intent
+with the {@link android.content.Intent#ACTION_SEND} action
+and add extras that specify the content to share. When you call
+{@link android.content.Context#startActivity startActivity()} with that intent, the user can
+pick an app through which to share the content.</p>
+
+<p class="caution"><strong>Caution:</strong> It's possible that a user won't have <em>any</em>
+apps that handle the implicit intent you send to {@link android.content.Context#startActivity
+startActivity()}. If that happens, the call will fail and your app will crash. To verify
+that an activity will receive the intent, call {@link android.content.Intent#resolveActivity
+resolveActivity()} on your {@link android.content.Intent} object. If the result is non-null,
+then there is at least one app that can handle the intent and it's safe to call
+{@link android.content.Context#startActivity startActivity()}. If the result is null,
+you should not use the intent and, if possible, you should disable the feature that issues
+the intent.</p>
+
+
+<pre>
+// Create the text message with a string
+Intent sendIntent = new Intent();
+sendIntent.setAction(Intent.ACTION_SEND);
+sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
+sendIntent.setType({@link
+ org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE
+ HTTP.PLAIN_TEXT_TYPE}); // "text/plain" MIME type
+
+// Verify that the intent will resolve to an activity
+if (sendIntent.resolveActivity(getPackageManager()) != null) {
+ startActivity(sendIntent);
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> In this case, a URI is not used, but the intent's data type
+is declared to specify the content carried by the extras.</p>
+
+
+<p>When {@link android.content.Context#startActivity startActivity()} is called, the system
+examines all of the installed apps to determine which ones can handle this kind of intent (an
+intent with the {@link android.content.Intent#ACTION_SEND} action and that carries "text/plain"
+data). If there's only one app that can handle it, that app opens immediately and is given the
+intent. If multiple activities accept the intent, the system
+displays a dialog so the user can pick which app to use..</p>
+
+
+<div class="figure" style="width:200px">
+ <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="">
+ <p class="img-caption"><strong>Figure 2.</strong> A chooser dialog.</p>
</div>
-</div>
-<p>
-An intent filter is an instance of the {@link android.content.IntentFilter} class.
-However, since the Android system must know about the capabilities of a component
-before it can launch that component, intent filters are generally not set up in
-Java code, but in the application's manifest file (AndroidManifest.xml) as
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
-elements. (The one exception would be filters for
-broadcast receivers that are registered dynamically by calling <code>{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
-Handler) Context.registerReceiver()}</code>; they are directly created as
-IntentFilter objects.)
-</p>
+<h3 id="ForceChooser">Forcing an app chooser</h3>
-<p>
-A filter has fields that parallel the action, data, and category fields of an
-Intent object. An implicit intent is tested against the filter in all three areas.
-To be delivered to the component that owns the filter, it must pass all three tests.
-If it fails even one of them, the Android system won't deliver it to the
-component &mdash; at least not on the basis of that filter. However, since a
-component can have multiple intent filters, an intent that does not pass
-through one of a component's filters might make it through on another.
-</p>
+<p>When there is more than one app that responds to your implicit intent,
+the user can select which app to use and make that app the default choice for the
+action. This is nice when performing an action for which the user
+probably wants to use the same app from now on, such as when opening a web page (users
+often prefer just one web browser) .</p>
-<p>
-Each of the three tests is described in detail below:
-</p>
+<p>However, if multiple apps can respond to the intent and the user might want to use a different
+app each time, you should explicitly show a chooser dialog. The chooser dialog asks the
+user to select which app to use for the action every time (the user cannot select a default app for
+the action). For example, when your app performs "share" with the {@link
+android.content.Intent#ACTION_SEND} action, users may want to share using a different app depending
+on their current situation, so you should always use the chooser dialog, as shown in figure 2.</p>
-<dl>
-<dt><b>Action test</b></dt>
-<dd>An
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
-element in the manifest file lists actions as
-<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
-subelements. For example:
-
-<pre>&lt;intent-filter . . . &gt;
- &lt;action android:name="com.example.project.SHOW_CURRENT" /&gt;
- &lt;action android:name="com.example.project.SHOW_RECENT" /&gt;
- &lt;action android:name="com.example.project.SHOW_PENDING" /&gt;
- . . .
-&lt;/intent-filter&gt;</pre>
-<p>
-As the example shows, while an Intent object names just a single action,
-a filter may list more than one. The list cannot be empty; a filter must
-contain at least one {@code &lt;action&gt;} element, or it
-will block all intents.
-</p>
-<p>
-To pass this test, the action specified in the Intent object must match
-one of the actions listed in the filter. If the object or the filter
-does not specify an action, the results are as follows:
-</p>
+<p>To show the chooser, create an {@link android.content.Intent} using {@link
+android.content.Intent#createChooser createChooser()} and pass it to {@link
+android.app.Activity#startActivity startActivity()}. For example:</p>
-<ul>
-<li>If the filter fails to list any actions, there is nothing for an
-intent to match, so all intents fail the test. No intents can get
-through the filter.</li>
-
-<li><p>On the other hand, an Intent object that doesn't specify an
-action automatically passes the test &mdash; as long as the filter
-contains at least one action.</p></li>
-</ul
-</dd>
+<pre>
+Intent intent = new Intent(Intent.ACTION_SEND);
+...
-<dt><b>Category test</b></dt>
-<dd>An
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
-element also lists categories as subelements. For example:
+// Always use string resources for UI text.
+// This says something like "Share this photo with"
+String title = getResources().getString(R.string.chooser_title);
+// Create intent to show chooser
+Intent chooser = Intent.createChooser(intent, title);
-<pre>&lt;intent-filter . . . &gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
- . . .
-&lt;/intent-filter&gt;</pre>
+// Verify the intent will resolve to at least one activity
+if (sendIntent.resolveActivity(getPackageManager()) != null) {
+ startActivity(sendIntent);
+}
+</pre>
-<p>
-Note that the constants described earlier for actions and categories are not
-used in the manifest file. The full string values are used instead. For
-instance, the "{@code android.intent.category.BROWSABLE}" string in the example
-above corresponds to the {@code CATEGORY_BROWSABLE} constant mentioned earlier
-in this document. Similarly, the string "{@code android.intent.action.EDIT}"
-corresponds to the {@code ACTION_EDIT} constant.
-</p>
+<p>This displays a dialog with a list of apps that respond to the intent passed to the {@link
+android.content.Intent#createChooser createChooser()} method and uses the supplied text as the
+dialog title.</p>
-<p>
-For an intent to pass the category test, every category in the Intent object
-must match a category in the filter. The filter can list additional categories,
-but it cannot omit any that are in the intent.
-</p>
-<p>
-In principle, therefore, an Intent object with no categories should always pass
-this test, regardless of what's in the filter. That's mostly true. However,
-with one exception, Android treats all implicit intents passed to {@link
-android.content.Context#startActivity startActivity()} as if they contained
-at least one category: "{@code android.intent.category.DEFAULT}" (the
-{@code CATEGORY_DEFAULT} constant).
-Therefore, activities that are willing to receive implicit intents must
-include "{@code android.intent.category.DEFAULT}" in their intent filters.
-(Filters with "{@code android.intent.action.MAIN}" and
-"{@code android.intent.category.LAUNCHER}" settings are the exception.
-They mark activities that begin new tasks and that are represented on the
-launcher screen. They can include "{@code android.intent.category.DEFAULT}"
-in the list of categories, but don't need to.) See <a href="#imatch">Using
-intent matching</a>, later, for more on these filters.)
-</p>
-<dd>
-<dt><b>Data test</b></dt>
-<dd>Like the action and categories, the data specification for an intent filter
-is contained in a subelement. And, as in those cases, the subelement can appear
-multiple times, or not at all. For example:
-<pre>&lt;intent-filter . . . &gt;
- &lt;data android:mimeType="video/mpeg" android:scheme="http" . . . /&gt;
- &lt;data android:mimeType="audio/mpeg" android:scheme="http" . . . /&gt;
- . . .
-&lt;/intent-filter&gt;</pre>
-<p>
-Each
-<code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
-element can specify a URI and a data type (MIME media type). There are separate
-attributes &mdash; {@code scheme}, {@code host}, {@code port},
-and {@code path} &mdash; for each part of the URI:
-</p>
-<p style="margin-left: 2em">{@code scheme://host:port/path}</p>
-<p>
-For example, in the following URI,
-</p>
-<p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
-<p> the scheme is "{@code content}", the host is "{@code com.example.project}",
-the port is "{@code 200}", and the path is "{@code folder/subfolder/etc}".
-The host and port together constitute the URI <i>authority</i>; if a host is
-not specified, the port is ignored.
-</p>
+<h2 id="Receiving">Receiving an Implicit Intent</h2>
-<p>
-Each of these attributes is optional, but they are not independent of each other:
-For an authority to be meaningful, a scheme must also be specified.
-For a path to be meaningful, both a scheme and an authority must be specified.
-</p>
+<p>To advertise which implicit intents your app can receive, declare one or more intent filters for
+each of your app components with an <a href=
+"{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter&gt;}</a>
+element in your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a>.
+Each intent filter specifies the type of intents it accepts based on the intent's action,
+data, and category. The system will deliver an implicit intent to your app component only if the
+intent can pass through one of your intent filters.</p>
-<p>
-When the URI in an Intent object is compared to a URI specification in a filter,
-it's compared only to the parts of the URI actually mentioned in the filter.
-For example, if a filter specifies only a scheme, all URIs with that scheme match
-the filter. If a filter specifies a scheme and an authority but no path, all URIs
-with the same scheme and authority match, regardless of their paths. If a filter
-specifies a scheme, an authority, and a path, only URIs with the same scheme,
-authority, and path match. However, a path specification in the filter can
-contain wildcards to require only a partial match of the path.
-</p>
+<p class="note"><strong>Note:</strong> An explicit intent is always delivered to its target,
+regardless of any intent filters the component declares.</p>
-<p>
-The {@code type} attribute of a {@code &lt;data&gt;} element specifies the MIME type
-of the data. It's more common in filters than a URI. Both the Intent object and
-the filter can use a "*" wildcard for the subtype field &mdash; for example,
-"{@code text/*}" or "{@code audio/*}" &mdash; indicating any subtype matches.
-</p>
+<p>An app component should declare separate filters for each unique job it can do.
+For example, one activity in an image gallery app may have two filters: one filter
+to view an image, and another filter to edit an image. When the activity starts,
+it inspects the {@link android.content.Intent} and decides how to behave based on the information
+in the {@link android.content.Intent} (such as to show the editor controls or not).</p>
-<p>
-The data test compares both the URI and the data type in the Intent object to a URI
-and data type specified in the filter. The rules are as follows:
-</p>
+<p>Each intent filter is defined by an <a
+href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>
+element in the app's manifest file, nested in the corresponding app component (such
+as an <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a>
+element). Inside the <a
+href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code &lt;intent-filter>}</a>,
+you can specify the type of intents to accept using one or more
+of these three elements:</p>
-<ol type="a">
-<li>An Intent object that contains neither a URI nor a data type passes the
-test only if the filter likewise does not specify any URIs or data types.</li>
-
-<li><p>An Intent object that contains a URI but no data type (and a type cannot
-be inferred from the URI) passes the test only if its URI matches a URI in the
-filter and the filter likewise does not specify a type. This will be the case
-only for URIs like {@code mailto:} and {@code tel:} that do not refer to actual data.</p></li>
-
-<li><p>An Intent object that contains a data type but not a URI passes the test
-only if the filter lists the same data type and similarly does not specify a URI.</p></li>
-
-<li><p>An Intent object that contains both a URI and a data type (or a data type
-can be inferred from the URI) passes the data type part of the test only if its
-type matches a type listed in the filter. It passes the URI part of the test
-either if its URI matches a URI in the filter or if it has a {@code content:}
-or {@code file:} URI and the filter does not specify a URI. In other words,
-a component is presumed to support {@code content:} and {@code file:} data if
-its filter lists only a data type.</p></li>
-</ol>
+<dl>
+<dt><a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a></dt>
+ <dd>Declares the intent action accepted, in the {@code name} attribute. The value
+ must be the literal string value of an action, not the class constant.</dd>
+<dt><a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a></dt>
+ <dd>Declares the type of data accepted, using one or more attributes that specify various
+ aspects of the data URI (<code>scheme</code>, <code>host</code>, <code>port</code>,
+ <code>path</code>, etc.) and MIME type.</dd>
+<dt><a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a></dt>
+ <dd>Declares the intent category accepted, in the {@code name} attribute. The value
+ must be the literal string value of an action, not the class constant.
+
+ <p class="note"><strong>Note:</strong> In order to receive implicit intents, you
+ <strong>must include</strong> the
+ {@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods
+ {@link android.app.Activity#startActivity startActivity()} and
+ {@link android.app.Activity#startActivityForResult startActivityForResult()} treat all intents
+ as if they declared the {@link android.content.Intent#CATEGORY_DEFAULT} category.
+ If you do not declare this category in your intent filter, no implicit intents will resolve to
+ your activity.</p>
+ </dd>
</dl>
-<p>
-If an intent can pass through the filters of more than one activity or service,
-the user may be asked which component to activate. An exception is raised if
-no target can be found.
-</p>
+<p>For example, here's an activity declaration with an intent filter to receive an
+{@link android.content.Intent#ACTION_SEND} intent when the data type is text:</p>
+<pre>
+&lt;activity android:name="ShareActivity">
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.SEND"/>
+ &lt;category android:name="android.intent.category.DEFAULT"/>
+ &lt;data android:mimeType="text/plain"/>
+ &lt;/intent-filter>
+&lt;/activity>
+</pre>
-<h3><a name="ccases"></a>Common cases</h3>
+<p>It's okay to create a filter that includes more than one instance of
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code &lt;action>}</a>,
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a>, or
+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code &lt;category>}</a>.
+If you do, you simply need to be certain that the component can handle any and all combinations
+of those filter elements.</p>
-<p>
-The last rule shown above for the data test, rule (d), reflects the expectation
-that components are able to get local data from a file or content provider.
-Therefore, their filters can list just a data type and do not need to explicitly
-name the {@code content:} and {@code file:} schemes.
-This is a typical case. A {@code &lt;data&gt;} element like the following,
-for example, tells Android that the component can get image data from a content
-provider and display it:
-</p>
+<p>When you want to handle multiple kinds of intents, but only in specific combinations of
+action, data, and category type, then you need to create multiple intent filters.</p>
-<pre>&lt;data android:mimeType="image/*" /&gt;</pre>
-<p>
-Since most available data is dispensed by content providers, filters that
-specify a data type but not a URI are perhaps the most common.
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>Restricting access to components</h2>
+<p>Using an intent filter is not a secure way to prevent other apps from starting
+your components. Although intent filters restrict a component to respond to only
+certain kinds of implicit intents, another app can potentially start your app component
+by using an explicit intent if the developer determines your component names.
+If it's important that <em>only your own app</em> is able to start one of your components,
+set the <a href="{@docRoot}guide/topics/manifest/activity-element.html#exported">{@code
+exported}</a> attribute to {@code "false"} for that component.
</p>
+</div>
+</div>
-<p>
-Another common configuration is filters with a scheme and a data type. For
-example, a {@code &lt;data&gt;} element like the following tells Android that
-the component can get video data from the network and display it:
-</p>
+<p>An implicit intent is tested against a filter by comparing the intent to each of the
+three elements. To be delivered to the component, the intent must pass all three tests.
+If it fails to match even one of them, the Android system won't deliver the intent to the
+component. However, because a component may have multiple intent filters, an intent that does
+not pass through one of a component's filters might make it through on another filter.
+More information about how the system resolves intents is provided in the section below
+about <a href="#Resolution">Intent Resolution</a>.</p>
+
+<p class="caution"><strong>Caution:</strong> To avoid inadvertently running a different app's
+{@link android.app.Service}, always use an explicit intent to start your own service and do not
+declare intent filters for your service.</p>
+
+<p class="note"><strong>Note:</strong>
+For all activities, you must declare your intent filters in the manifest file.
+However, filters for broadcast receivers can be registered dynamically by calling
+{@link android.content.Context#registerReceiver(BroadcastReceiver, IntentFilter, String,
+Handler) registerReceiver()}. You can then unregister the receiver with {@link
+android.content.Context#unregisterReceiver unregisterReceiver()}. Doing so allows your app
+to listen for specific broadcasts during only a specified period of time while your app
+is running.</p>
+
+
+
+
+
+
+
+<h3 id="ExampleFilters">Example filters</h3>
+
+<p>To better understand some of the intent filter behaviors, look at the following snippet
+from the manifest file of a social-sharing app.</p>
+
+<pre>
+&lt;activity android:name="MainActivity">
+ &lt;!-- This activity is the main entry, should appear in app launcher -->
+ &lt;intent-filter>
+ &lt;action android:name="android.intent.action.MAIN" />
+ &lt;category android:name="android.intent.category.LAUNCHER" />
+ &lt;/intent-filter>
+&lt;/activity>
+
+&lt;activity android:name="ShareActivity">
+ &lt;!-- This activity handles "SEND" actions with text data -->
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.SEND"/>
+ &lt;category android:name="android.intent.category.DEFAULT"/>
+ &lt;data android:mimeType="text/plain"/>
+ &lt;/intent-filter&gt;
+ &lt;!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.intent.action.SEND"/>
+ &lt;action android:name="android.intent.action.SEND_MULTIPLE"/>
+ &lt;category android:name="android.intent.category.DEFAULT"/>
+ &lt;data android:mimeType="application/vnd.google.panorama360+jpg"/>
+ &lt;data android:mimeType="image/*"/>
+ &lt;data android:mimeType="video/*"/>
+ &lt;/intent-filter&gt;
+&lt;/activity&gt;
+</pre>
+
+<p>The first activity, {@code MainActivity}, is the app's main entry point&mdash;the activity that
+opens when the user initially launches the app with the launcher icon:</p>
+<ul>
+ <li>The {@link android.content.Intent#ACTION_MAIN} action
+ indicates this is the main entry point and does not expect any intent data.</li>
+ <li>The {@link android.content.Intent#CATEGORY_LAUNCHER} category indicates that this activity's
+ icon should be placed in the system's app launcher. If the <a
+ href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity>}</a> element
+ does not specify an icon with {@code icon}, then the system uses the icon from the <a
+ href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
+ element.</li>
+</ul>
+<p>These two must be paired together in order for the activity to appear in the app launcher.</p>
-<pre>&lt;data android:scheme="http" android:type="video/*" /&gt;</pre>
+<p>The second activity, {@code ShareActivity}, is intended to facilitate sharing text and media
+content. Although users might enter this activity by navigating to it from {@code MainActivity},
+they can also enter {@code ShareActivity} directly from another app that issues an implicit
+intent matching one of the two intent filters.</p>
-<p>
-Consider, for example, what the browser application does when
-the user follows a link on a web page. It first tries to display the data
-(as it could if the link was to an HTML page). If it can't display the data,
-it puts together an implicit intent with the scheme and data type and tries
-to start an activity that can do the job. If there are no takers, it asks the
-download manager to download the data. That puts it under the control
-of a content provider, so a potentially larger pool of activities
-(those with filters that just name a data type) can respond.
-</p>
+<p class="note"><strong>Note:</strong> The MIME type,
+<a href="https://developers.google.com/panorama/android/">{@code
+application/vnd.google.panorama360+jpg}</a>, is a special data type that specifies
+panoramic photos, which you can handle with the <a
+href="{@docRoot}reference/com/google/android/gms/panorama/package-summary.html">Google
+panorama</a> APIs.</p>
-<p>
-Most applications also have a way to start fresh, without a reference
-to any particular data. Activities that can initiate applications
-have filters with "{@code android.intent.action.MAIN}" specified as
-the action. If they are to be represented in the application launcher,
-they also specify the "{@code android.intent.category.LAUNCHER}"
-category:
-</p>
-<pre>&lt;intent-filter . . . &gt;
- &lt;action android:name="android.intent.action.MAIN" /&gt;
- &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
-&lt;/intent-filter&gt;</pre>
-<h3><a name="imatch"></a>Using intent matching</h3>
-<p>
-Intents are matched against intent filters not only to discover a target
-component to activate, but also to discover something about the set of
-components on the device. For example, the Android system populates the
-application launcher, the top-level screen that shows the applications
-that are available for the user to launch, by finding all the activities
- with intent filters that specify the "{@code android.intent.action.MAIN}"
-action and "{@code android.intent.category.LAUNCHER}" category
-(as illustrated in the previous section). It then displays the icons and
-labels of those activities in the launcher. Similarly, it discovers the
-home screen by looking for the activity with
-"{@code android.intent.category.HOME}" in its filter.
-</p>
-<p>
-Your application can use intent matching is a similar way.
-The {@link android.content.pm.PackageManager} has a set of {@code query...()}
-methods that return all components that can accept a particular intent, and
-a similar series of {@code resolve...()} methods that determine the best
-component to respond to an intent. For example,
-{@link android.content.pm.PackageManager#queryIntentActivities
-queryIntentActivities()} returns a list of all activities that can perform
-the intent passed as an argument, and {@link
-android.content.pm.PackageManager#queryIntentServices
-queryIntentServices()} returns a similar list of services.
-Neither method activates the components; they just list the ones that
-can respond. There's a similar method,
-{@link android.content.pm.PackageManager#queryBroadcastReceivers
-queryBroadcastReceivers()}, for broadcast receivers.
-</p>
-<h2 id="npex">Note Pad Example</h2>
-<p>
-The Note Pad sample application enables users to browse through a list
-of notes, view details about individual items in the list, edit the items,
-and add a new item to the list. This section looks at the intent filters
-declared in its manifest file. (If you're working offline in the SDK, you
-can find all the source files for this sample application, including its
-manifest file, at {@code &lt;sdk&gt;/samples/NotePad/index.html}.
-If you're viewing the documentation online, the source files are in the
-<a href="{@docRoot}resources/samples/index.html">Tutorials and Sample Code</a>
-section <a href="{@docRoot}resources/samples/NotePad/index.html">here</a>.)
-</p>
-<p>
-In its manifest file, the Note Pad application declares three activities,
-each with at least one intent filter. It also declares a content provider
-that manages the note data. Here is the manifest file in its entirety:
-</p>
-<pre>&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.notepad"&gt;
- &lt;application android:icon="@drawable/app_notes"
- android:label="@string/app_name" &gt;
-
- &lt;provider android:name="NotePadProvider"
- android:authorities="com.google.provider.NotePad" /&gt;
-
- &lt;activity android:name="NotesList" android:label="@string/title_notes_list"&gt;
- &lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.MAIN" /&gt;
- &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
- &lt;/intent-filter&gt;
- &lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.VIEW" /&gt;
- &lt;action android:name="android.intent.action.EDIT" /&gt;
- &lt;action android:name="android.intent.action.PICK" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /&gt;
- &lt;/intent-filter&gt;
- &lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.GET_CONTENT" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.item/vnd.google.note" /&gt;
- &lt;/intent-filter&gt;
- &lt;/activity&gt;
-
- &lt;activity android:name="NoteEditor"
- android:theme="@android:style/Theme.Light"
- android:label="@string/title_note" &gt;
- &lt;intent-filter android:label="@string/resolve_edit"&gt;
- &lt;action android:name="android.intent.action.VIEW" /&gt;
- &lt;action android:name="android.intent.action.EDIT" /&gt;
- &lt;action android:name="com.android.notepad.action.EDIT_NOTE" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.item/vnd.google.note" /&gt;
- &lt;/intent-filter&gt;
- &lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.INSERT" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /&gt;
- &lt;/intent-filter&gt;
- &lt;/activity&gt;
-
- &lt;activity android:name="TitleEditor"
- android:label="@string/title_edit_title"
- android:theme="@android:style/Theme.Dialog"&gt;
- &lt;intent-filter android:label="@string/resolve_title"&gt;
- &lt;action android:name="com.android.notepad.action.EDIT_TITLE" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;category android:name="android.intent.category.ALTERNATIVE" /&gt;
- &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.item/vnd.google.note" /&gt;
- &lt;/intent-filter&gt;
- &lt;/activity&gt;
-
- &lt;/application&gt;
-&lt;/manifest&gt;</pre>
-<p>
-The first activity, NotesList, is
-distinguished from the other activities by the fact that it operates
-on a directory of notes (the note list) rather than on a single note.
-It would generally serve as the initial user interface into the
-application. It can do three things as described by its three intent
-filters:
-</p>
-<ol>
-<li><pre>&lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.MAIN" /&gt;
- &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
-&lt;/intent-filter&gt;</pre>
-<p>
-This filter declares the main entry point into the Note Pad application.
-The standard {@code MAIN} action is an entry point that does not require
-any other information in the Intent (no data specification, for example),
-and the {@code LAUNCHER} category says that this entry point should be
-listed in the application launcher.
-</p></li>
-
-<li><pre>&lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.VIEW" /&gt;
- &lt;action android:name="android.intent.action.EDIT" /&gt;
- &lt;action android:name="android.intent.action.PICK" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /&gt;
-&lt;/intent-filter&gt;</pre>
+<h2 id="PendingIntent">Using a Pending Intent</h2>
-<p>
-This filter declares the things that the activity can do on a directory
-of notes. It can allow the user to view or edit the directory (via
-the {@code VIEW} and {@code EDIT} actions), or to pick a particular note
-from the directory (via the {@code PICK} action).
-</p>
+<p>A {@link android.app.PendingIntent} object is a wrapper around an {@link
+android.content.Intent} object. The primary purpose of a {@link android.app.PendingIntent}
+is to grant permission to a foreign application
+to use the contained {@link android.content.Intent} as if it were executed from your
+app's own process.</p>
-<p>
-The {@code mimeType} attribute of the
-<code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
-element specifies the kind of data that these actions operate on. It
-indicates that the activity can get a Cursor over zero or more items
-({@code vnd.android.cursor.dir}) from a content provider that holds
-Note Pad data ({@code vnd.google.note}). The Intent object that launches
-the activity would include a {@code content:} URI specifying the exact
-data of this type that the activity should open.
-</p>
+<p>Major use cases for a pending intent include:</p>
+<ul>
+ <li>Declare an intent to be executed when the user performs an action with your <a
+ href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notification</a>
+ (the Android system's {@link android.app.NotificationManager}
+ executes the {@link android.content.Intent}).
+ <li>Declare an intent to be executed when the user performs an action with your
+ <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widget</a>
+ (the Home screen app executes the {@link android.content.Intent}).
+ <li>Declare an intent to be executed at a specified time in the future (the Android
+ system's {@link android.app.AlarmManager} executes the {@link android.content.Intent}).
+</ul>
-<p>
-Note also the {@code DEFAULT} category supplied in this filter. It's
-there because the <code>{@link android.content.Context#startActivity
-Context.startActivity()}</code> and
-<code>{@link android.app.Activity#startActivityForResult
-Activity.startActivityForResult()}</code> methods treat all intents
-as if they contained the {@code DEFAULT} category &mdash; with just
-two exceptions:
-</p>
+<p>Because each {@link android.content.Intent} object is designed to be handled by a specific
+type of app component (either an {@link android.app.Activity}, a {@link android.app.Service}, or
+a {@link android.content.BroadcastReceiver}), so too must a {@link android.app.PendingIntent} be
+created with the same consideration. When using a pending intent, your app will not
+execute the intent with a call such as {@link android.content.Context#startActivity
+startActivity()}. You must instead declare the intended component type when you create the
+{@link android.app.PendingIntent} by calling the respective creator method:</p>
<ul>
-<li>Intents that explicitly name the target activity</li>
-<li>Intents consisting of the {@code MAIN} action and {@code LAUNCHER}
-category</li>
+ <li>{@link android.app.PendingIntent#getActivity PendingIntent.getActivity()} for an
+ {@link android.content.Intent} that starts an {@link android.app.Activity}.</li>
+ <li>{@link android.app.PendingIntent#getService PendingIntent.getService()} for an
+ {@link android.content.Intent} that starts a {@link android.app.Service}.</li>
+ <li>{@link android.app.PendingIntent#getBroadcast PendingIntent.getBroadcast()} for a
+ {@link android.content.Intent} that starts an {@link android.content.BroadcastReceiver}.</li>
</ul>
-<p>
-Therefore, the {@code DEFAULT} category is <em>required</em> for all
-filters &mdash; except for those with the {@code MAIN} action and
-{@code LAUNCHER} category. (Intent filters are not consulted for
-explicit intents.)
-</p></li>
-
-<li><pre>&lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.GET_CONTENT" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.item/vnd.google.note" /&gt;
-&lt;/intent-filter&gt;</pre>
+<p>Unless your app is <em>receiving</em> pending intents from other apps,
+the above methods to create a {@link android.app.PendingIntent} are the only
+{@link android.app.PendingIntent} methods you'll probably ever need.</p>
-<p>
-This filter describes the activity's ability to return a note selected by
-the user without requiring any specification of the directory the user should
-choose from. The {@code GET_CONTENT} action is similar to the {@code PICK}
-action. In both cases, the activity returns the URI for a note selected by
-the user. (In each case, it's returned to the activity that called
-<code>{@link android.app.Activity#startActivityForResult
-startActivityForResult()}</code> to start the NoteList activity.) Here,
-however, the caller specifies the type of data desired instead of the
-directory of data the user will be picking from.
-</p>
+<p>Each method takes the current app {@link android.content.Context}, the
+{@link android.content.Intent} you want to wrap, and one or more flags that specify
+how the intent should be used (such as whether the intent can be used more than once).</p>
-<p>
-The data type, <code>vnd.android.cursor.item/vnd.google.note</code>,
-indicates the type of data the activity can return &mdash; a URI for
-a single note. From the returned URI, the caller can get a Cursor for
-exactly one item ({@code vnd.android.cursor.item}) from the content
-provider that holds Note Pad data ({@code vnd.google.note}).
-</p>
+<p>More information about using pending intents is provided with the documentation for each
+of the respective use cases, such as in the <a
+href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a>
+and <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> API guides.</p>
-<p>
-In other words, for the {@code PICK} action in the previous filter,
-the data type indicates the type of data the activity could display to the
-user. For the {@code GET_CONTENT} filter, it indicates the type of data
-the activity can return to the caller.
-</p></li>
-</ol>
-<p>
-Given these capabilities, the following intents will resolve to the
-NotesList activity:
-</p>
-<dl style="margin-left: 2em">
-<dt>action: <code>android.intent.action.MAIN</code></dt>
-<dd>Launches the activity with no data specified.</dd>
-
-<dt>action: <code>android.intent.action.MAIN</code>
-<br/>category: <code>android.intent.category.LAUNCHER</code></dt>
-<dd> Launches the activity with no data selected specified.
-This is the actual intent used by the Launcher to populate its top-level
-list. All activities with filters that match this action and category
-are added to the list.</dd>
-
-<dt>action: <code>android.intent.action.VIEW</code>
-<br/>data: <code>content://com.google.provider.NotePad/notes</code></dt>
-<dd>Asks the activity to display a list of all the notes under
-<code>content://com.google.provider.NotePad/notes</code>. The user can then
-browse through the list and get information about the items in it.</dd>
-
-<dt>action: <code>android.intent.action.PICK</code>
-<br/>data: <code>content://com.google.provider.NotePad/notes</code></dt>
-<dd>Asks the activity to display a list of the notes under
-<code>content://com.google.provider.NotePad/notes</code>.
-The user can then pick a note from the list, and the activity will return
-the URI for that item back to the activity that started the NoteList activity.</dd>
-
-<dt>action: <code>android.intent.action.GET_CONTENT</code>
-<br/>data type: <code>vnd.android.cursor.item/vnd.google.note</code></dt>
-<dd>Asks the activity to supply a single item of Note Pad data.</dd>
-</dl>
-<p>
-The second activity, NoteEditor, shows
-users a single note entry and allows them to edit it. It can do two things
-as described by its two intent filters:
-<ol>
-<li><pre>&lt;intent-filter android:label="@string/resolve_edit"&gt;
- &lt;action android:name="android.intent.action.VIEW" /&gt;
+
+
+<h2 id="Resolution">Intent Resolution</h2>
+
+
+<p>When the system receives an implicit intent to start an activity, it searches for the
+best activity for the intent by comparing the intent to intent filters based on three aspects:</p>
+
+<ul>
+ <li>The intent action
+ <li>The intent data (both URI and data type)
+ <li>The intent category
+</ul>
+
+<p>The following sections describe how an intents are matched to the appropriate component(s)
+in terms of how the intent filter is declared in an app's manifest file.</p>
+
+
+<h3 id="ActionTest">Action test</h3>
+
+<p>To specify accepted intent actions, an intent filter can declare zero or more
+<a href="{@docRoot}guide/topics/manifest/action-element.html">{@code
+&lt;action&gt;}</a> elements. For example:</p>
+
+<pre>
+&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.EDIT" /&gt;
- &lt;action android:name="com.android.notepad.action.EDIT_NOTE" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.item/vnd.google.note" /&gt;
-&lt;/intent-filter&gt;</pre>
+ &lt;action android:name="android.intent.action.VIEW" /&gt;
+ ...
+&lt;/intent-filter&gt;
+</pre>
-<p>
-The first, primary, purpose of this activity is to enable the user to
-interact with a single note &mdash; to either {@code VIEW} the note or
-{@code EDIT} it. (The {@code EDIT_NOTE} category is a synonym for
-{@code EDIT}.) The intent would contain the URI for data matching the
-MIME type <code>vnd.android.cursor.item/vnd.google.note</code> &mdash;
-that is, the URI for a single, specific note. It would typically be a
-URI that was returned by the {@code PICK} or {@code GET_CONTENT}
-actions of the NoteList activity.
-</p>
+<p>To get through this filter, the action specified in the {@link android.content.Intent}
+ must match one of the actions listed in the filter.</p>
-<p>
-As before, this filter lists the {@code DEFAULT} category so that the
-activity can be launched by intents that don't explicitly specify the
-NoteEditor class.
-</p></li>
+<p>If the filter does not list any actions, there is nothing for an
+intent to match, so all intents fail the test. However, if an {@link android.content.Intent}
+does not specify an action, it will pass the test (as long as the filter
+contains at least one action).</p>
+
+
+
+<h3 id="CategoryTest">Category test</h3>
+
+<p>To specify accepted intent categories, an intent filter can declare zero or more
+<a href="{@docRoot}guide/topics/manifest/category-element.html">{@code
+&lt;category&gt;}</a> elements. For example:</p>
-<li><pre>&lt;intent-filter&gt;
- &lt;action android:name="android.intent.action.INSERT" /&gt;
+<pre>
+&lt;intent-filter&gt;
&lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /&gt;
-&lt;/intent-filter&gt;</pre>
+ &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
+ ...
+&lt;/intent-filter&gt;
+</pre>
-<p>
-The secondary purpose of this activity is to enable the user to create a new
-note, which it will {@code INSERT} into an existing directory of notes. The
-intent would contain the URI for data matching the MIME type
-<code>vnd.android.cursor.dir/vnd.google.note</code> &mdash; that
-is, the URI for the directory where the note should be placed.
-</p></li>
-</ol>
+<p>For an intent to pass the category test, every category in the {@link android.content.Intent}
+must match a category in the filter. The reverse is not necessary&mdash;the intent filter may
+declare more categories than are specified in the {@link android.content.Intent} and the
+{@link android.content.Intent} will still pass. Therefore, an intent with no categories should
+always pass this test, regardless of what categories are declared in the filter.</p>
+
+<p class="note"><strong>Note:</strong>
+Android automatically applies the the {@link android.content.Intent#CATEGORY_DEFAULT} category
+to all implicit intents passed to {@link
+android.content.Context#startActivity startActivity()} and {@link
+android.app.Activity#startActivityForResult startActivityForResult()}.
+So if you want your activity to receive implicit intents, it must
+include a category for {@code "android.intent.category.DEFAULT"} in its intent filters (as
+shown in the previous {@code &lt;intent-filter>} example.</p>
+
+
+
+<h3 id="DataTest">Data test</h3>
+
+<p>To specify accepted intent data, an intent filter can declare zero or more
+<a href="{@docRoot}guide/topics/manifest/data-element.html">{@code
+&lt;data&gt;}</a> elements. For example:</p>
+
+<pre>
+&lt;intent-filter&gt;
+ &lt;data android:mimeType="video/mpeg" android:scheme="http" ... /&gt;
+ &lt;data android:mimeType="audio/mpeg" android:scheme="http" ... /&gt;
+ ...
+&lt;/intent-filter&gt;
+</pre>
+
+<p>Each <code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
+element can specify a URI structure and a data type (MIME media type). There are separate
+attributes &mdash; {@code scheme}, {@code host}, {@code port},
+and {@code path} &mdash; for each part of the URI:
+</p>
+
+<p style="margin-left: 2em">{@code &lt;scheme>://&lt;host>:&lt;port>/&lt;path>}</p>
<p>
-Given these capabilities, the following intents will resolve to the
-NoteEditor activity:
+For example:
</p>
-<dl style:"margin-left: 2em">
-<dt>action: <code>android.intent.action.VIEW</code>
-<br/>data: <code>content://com.google.provider.NotePad/notes/<var>ID</var></code></dt>
-<dd>Asks the activity to display the content of the note identified
-by {@code <var>ID</var>}. (For details on how {@code content:} URIs
-specify individual members of a group, see
-<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.)
-
-<dt>action: <code>android.intent.action.EDIT</code>
-<br/>data: <code>content://com.google.provider.NotePad/notes/<var>ID</var></code></dt>
-<dd>Asks the activity to display the content of the note identified
-by {@code <var>ID</var>}, and to let the user edit it. If the user
-saves the changes, the activity updates the data for the note in the
-content provider.</dd>
-
-<dt>action: <code>android.intent.action.INSERT</code>
-<br/>data: <code>content://com.google.provider.NotePad/notes</code></dt>
-<dd>Asks the activity to create a new, empty note in the notes list at
-<code>content://com.google.provider.NotePad/notes</code>
-and allow the user to edit it. If the user saves the note, its URI
-is returned to the caller.
-</dd>
-</dl>
+<p style="margin-left: 2em">{@code content://com.example.project:200/folder/subfolder/etc}</p>
-<p>The last activity, TitleEditor,
-enables the user to edit the title of a note. This could be implemented
-by directly invoking the activity (by explicitly setting its component
-name in the Intent), without using an intent filter. But here we take
-the opportunity to show how to publish alternative operations on existing
-data:
+<p>In this URI, the scheme is {@code content}, the host is {@code com.example.project},
+the port is {@code 200}, and the path is {@code folder/subfolder/etc}.
</p>
-<pre>&lt;intent-filter android:label="@string/resolve_title"&gt;
- &lt;action android:name="com.android.notepad.action.EDIT_TITLE" /&gt;
- &lt;category android:name="android.intent.category.DEFAULT" /&gt;
- &lt;category android:name="android.intent.category.ALTERNATIVE" /&gt;
- &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" /&gt;
- &lt;data android:mimeType="vnd.android.cursor.item/vnd.google.note" /&gt;
-&lt;/intent-filter&gt;</pre>
+<p>Each of these attributes is optional in a <a
+href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element,
+but there are linear dependencies:</p>
+<ul>
+ <li>If a scheme is not specified, the host is ignored.</li>
+ <li>If a host is not specified, the port is ignored.</li>
+ <li>If both the scheme and host are not specified, the path is ignored.</li>
+</ul>
-<p>
-The single intent filter for this activity uses a custom action called
-"<code>com.android.notepad.action.EDIT_TITLE</code>". It must be invoked on
-a specific note (data type <code>vnd.android.cursor.item/vnd.google.note</code>),
-like the previous {@code VIEW} and {@code EDIT} actions. However, here the
-activity displays the title contained in the note data, not the content of
-the note itself.
+<p>When the URI in an intent is compared to a URI specification in a filter,
+it's compared only to the parts of the URI included in the filter. For example:</p>
+<ul>
+ <li>If a filter specifies only a scheme, all URIs with that scheme match
+the filter.</li>
+ <li>If a filter specifies a scheme and an authority but no path, all URIs
+with the same scheme and authority pass the filter, regardless of their paths.</li>
+ <li>If a filter specifies a scheme, an authority, and a path, only URIs with the same scheme,
+authority, and path pass the filter.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> A path specification can
+contain a wildcard asterisk (*) to require only a partial match of the path name.</p>
+
+<p>The data test compares both the URI and the MIME type in the intent to a URI
+and MIME type specified in the filter. The rules are as follows:
</p>
+<ol type="a">
+<li>An intent that contains neither a URI nor a MIME type passes the
+test only if the filter does not specify any URIs or MIME types.</li>
+
+<li>An intent that contains a URI but no MIME type (neither explicit nor inferable from the
+URI) passes the test only if its URI matches the filter's URI format
+and the filter likewise does not specify a MIME type.</li>
+
+<li>An intent that contains a MIME type but not a URI passes the test
+only if the filter lists the same MIME type and does not specify a URI format.</li>
+
+<li>An intent that contains both a URI and a MIME type (either explicit or inferable from the
+URI) passes the MIME type part of the test only if that
+type matches a type listed in the filter. It passes the URI part of the test
+either if its URI matches a URI in the filter or if it has a {@code content:}
+or {@code file:} URI and the filter does not specify a URI. In other words,
+a component is presumed to support {@code content:} and {@code file:} data if
+its filter lists <em>only</em> a MIME type.</p></li>
+</ol>
+
<p>
-In addition to supporting the usual {@code DEFAULT} category, the title
-editor also supports two other standard categories:
-<code>{@link android.content.Intent#CATEGORY_ALTERNATIVE ALTERNATIVE}</code>
-and <code>{@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE
-SELECTED_ALTERNATIVE}</code>.
-These categories identify activities that can be presented to users in
-a menu of options (much as the {@code LAUNCHER} category identifies
-activities that should be presented to user in the application launcher).
-Note that the filter also supplies an explicit label (via
-<code>android:label="@string/resolve_title"</code>) to better control
-what users see when presented with this activity as an alternative
-action to the data they are currently viewing. (For more information
-on these categories and building options menus, see the
-<code>{@link android.content.pm.PackageManager#queryIntentActivityOptions
-PackageManager.queryIntentActivityOptions()}</code> and
-<code>{@link android.view.Menu#addIntentOptions Menu.addIntentOptions()}</code>
-methods.)
+This last rule, rule (d), reflects the expectation
+that components are able to get local data from a file or content provider.
+Therefore, their filters can list just a data type and do not need to explicitly
+name the {@code content:} and {@code file:} schemes.
+This is a typical case. A <a
+href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a> element
+like the following, for example, tells Android that the component can get image data from a content
+provider and display it:
</p>
+<pre>
+&lt;intent-filter&gt;
+ &lt;data android:mimeType="image/*" /&gt;
+ ...
+&lt;/intent-filter&gt;</pre>
+
<p>
-Given these capabilities, the following intent will resolve to the
-TitleEditor activity:
+Because most available data is dispensed by content providers, filters that
+specify a data type but not a URI are perhaps the most common.
</p>
-<dl style="margin-left: 2em">
-<dt>action: <code>com.android.notepad.action.EDIT_TITLE</code>
-<br/>data: <code>content://com.google.provider.NotePad/notes/<var>ID</var></code></dt>
-<dd>Asks the activity to display the title associated with note <var>ID</var>, and
-allow the user to edit the title.</dd>
-</dl>
+<p>
+Another common configuration is filters with a scheme and a data type. For
+example, a <a
+href="{@docRoot}guide/topics/manifest/data-element.html">{@code &lt;data>}</a>
+element like the following tells Android that
+the component can retrieve video data from the network in order to perform the action:
+</p>
+<pre>
+&lt;intent-filter&gt;
+ &lt;data android:scheme="http" android:type="video/*" /&gt;
+ ...
+&lt;/intent-filter&gt;</pre>
+<h3 id="imatch">Intent matching</h3>
+<p>Intents are matched against intent filters not only to discover a target
+component to activate, but also to discover something about the set of
+components on the device. For example, the Home app populates the app launcher
+by finding all the activities with intent filters that specify the
+{@link android.content.Intent#ACTION_MAIN} action and
+{@link android.content.Intent#CATEGORY_LAUNCHER} category.</p>
-
+<p>Your application can use intent matching in a similar way.
+The {@link android.content.pm.PackageManager} has a set of {@code query...()}
+methods that return all components that can accept a particular intent, and
+a similar series of {@code resolve...()} methods that determine the best
+component to respond to an intent. For example,
+{@link android.content.pm.PackageManager#queryIntentActivities
+queryIntentActivities()} returns a list of all activities that can perform
+the intent passed as an argument, and {@link
+android.content.pm.PackageManager#queryIntentServices
+queryIntentServices()} returns a similar list of services.
+Neither method activates the components; they just list the ones that
+can respond. There's a similar method,
+{@link android.content.pm.PackageManager#queryBroadcastReceivers
+queryBroadcastReceivers()}, for broadcast receivers.
+</p>
diff --git a/docs/html/guide/components/services.jd b/docs/html/guide/components/services.jd
index 30da33a..da01d2c 100644
--- a/docs/html/guide/components/services.jd
+++ b/docs/html/guide/components/services.jd
@@ -212,41 +212,35 @@ element. For example:</p>
&lt;/manifest&gt;
</pre>
+<p>See the <a
+href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element
+reference for more information about declaring your service in the manifest.</p>
+
<p>There are other attributes you can include in the <a
href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element to
define properties such as permissions required to start the service and the process in
which the service should run. The <a
href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a>
attribute is the only required attribute&mdash;it specifies the class name of the service. Once
-you publish your application, you should not change this name, because if you do, you might break
-some functionality where explicit intents are used to reference your service (read the blog post, <a
+you publish your application, you should not change this name, because if you do, you risk breaking
+code due to dependence on explicit intents to start or bind the service (read the blog post, <a
href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">Things
That Cannot Change</a>).
-<p>See the <a
-href="{@docRoot}guide/topics/manifest/service-element.html">{@code &lt;service&gt;}</a> element
-reference for more information about declaring your service in the manifest.</p>
-
-<p>Just like an activity, a service can define intent filters that allow other components to
-invoke the service using implicit intents. By declaring intent filters, components
-from any application installed on the user's device can potentially start your service if your
-service declares an intent filter that matches the intent another application passes to {@link
-android.content.Context#startService startService()}.</p>
-
-<p>If you plan on using your service only locally (other applications do not use it), then you
-don't need to (and should not) supply any intent filters. Without any intent filters, you must
-start the service using an intent that explicitly names the service class. More information
-about <a href="#StartingAService">starting a service</a> is discussed below.</p>
+<p>To ensure your app is secure, <strong>always use an explicit intent when starting or binding
+your {@link android.app.Service}</strong> and do not declare intent filters for the service. If
+it's critical that you allow for some amount of ambiguity as to which service starts, you can
+supply intent filters for your services and exclude the component name from the {@link
+android.content.Intent}, but you then must set the package for the intent with {@link
+android.content.Intent#setPackage setPackage()}, which provides sufficient disambiguation for the
+target service.</p>
-<p>Additionally, you can ensure that your service is private to your application only if
-you include the <a
+<p>Additionally, you can ensure that your service is available to only your app by
+including the <a
href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a>
-attribute and set it to {@code "false"}. This is effective even if your service supplies intent
-filters.</p>
+attribute and setting it to {@code "false"}. This effectively stops other apps from starting your
+service, even when using an explicit intent.</p>
-<p>For more information about creating intent filters for your service, see the <a
-href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
-document.</p>
@@ -333,7 +327,7 @@ client. (Though, you also need to provide a small constructor for the service.)<
<pre>
public class HelloIntentService extends IntentService {
- /**
+ /**
* A constructor is required, and must call the super {@link android.app.IntentService#IntentService}
* constructor with a name for the worker thread.
*/
@@ -443,8 +437,8 @@ public class HelloService extends Service {
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
-
- // Get the HandlerThread's Looper and use it for our Handler
+
+ // Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@@ -458,7 +452,7 @@ public class HelloService extends Service {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
-
+
// If we get killed, after returning from here, restart
return START_STICKY;
}
@@ -468,10 +462,10 @@ public class HelloService extends Service {
// We don't provide binding, so return null
return null;
}
-
+
&#64;Override
public void onDestroy() {
- Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
</pre>
@@ -652,7 +646,7 @@ developer guides for more information.</p>
<h2 id="Foreground">Running a Service in the Foreground</h2>
<p>A foreground service is a service that's considered to be something the
-user is actively aware of and thus not a candidate for the system to kill when low on memory. A
+user is actively aware of and thus not a candidate for the system to kill when low on memory. A
foreground service must provide a notification for the status bar, which is placed under the
"Ongoing" heading, which means that the notification cannot be dismissed unless the service is
either stopped or removed from the foreground.</p>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 8f2795a..6a2b1ba 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -68,9 +68,16 @@
</a></li>
</ul>
</li>
- <li><a href="<?cs var:toroot ?>guide/components/intents-filters.html">
- <span class="en">Intents and Intent Filters</span>
- </a></li>
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/components/intents-filters.html">
+ <span class="en">Intents and Intent Filters</span>
+ </a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/components/intents-common.html">
+ <span class="en">Common Intents</span>
+ </a></li>
+ </ul>
+ </li>
<li><a href="<?cs var:toroot ?>guide/components/processes-and-threads.html">
<span class="en">Processes and Threads</span>
</a>
diff --git a/docs/html/guide/topics/manifest/category-element.jd b/docs/html/guide/topics/manifest/category-element.jd
index 41a2cfd..a4b93ee 100644
--- a/docs/html/guide/topics/manifest/category-element.jd
+++ b/docs/html/guide/topics/manifest/category-element.jd
@@ -27,6 +27,14 @@ by prefixing "{@code android.intent.category.}" to the
the string value for {@code CATEGORY_LAUNCHER} is
"{@code android.intent.category.LAUNCHER}".
+<p class="note"><strong>Note:</strong> In order to receive implicit intents, you must include the
+{@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods
+{@link android.app.Activity#startActivity startActivity()} and
+{@link android.app.Activity#startActivityForResult startActivityForResult()} treat all intents
+as if they declared the {@link android.content.Intent#CATEGORY_DEFAULT} category.
+If you do not declare it in your intent filter, no implicit intents will resolve to
+your activity.</p>
+
<p>
Custom categories should use the package name as a prefix, to ensure
that they are unique.
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index 766d2d7..27950d0 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -5,34 +5,35 @@ parent.link=manifest-intro.html
<dl class="xml">
<dt>syntax:</dt>
-<dd><pre class="stx">&lt;data android:<a href="#host">host</a>="<i>string</i>"
- android:<a href="#mime">mimeType</a>="<i>string</i>"
+<dd><pre class="stx">&lt;data android:<a href="#scheme">scheme</a>="<i>string</i>"
+ android:<a href="#host">host</a>="<i>string</i>"
+ android:<a href="#port">port</a>="<i>string</i>"
android:<a href="#path">path</a>="<i>string</i>"
android:<a href="#path">pathPattern</a>="<i>string</i>"
android:<a href="#path">pathPrefix</a>="<i>string</i>"
- android:<a href="#port">port</a>="<i>string</i>"
- android:<a href="#scheme">scheme</a>="<i>string</i>" /&gt;</pre></dd>
+ android:<a href="#mime">mimeType</a>="<i>string</i>" /&gt;</pre></dd>
<dt>contained in:</dt>
<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code></dd>
<dt>description:</dt>
-<dd>Adds a data specification to an intent filter. The specification can
-be just a data type (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> attribute),
-just a URI, or both a data type and a URI. A URI is specified by separate
+<dd>Adds a data specification to an intent filter. The specification can
+be just a data type (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> attribute),
+just a URI, or both a data type and a URI. A URI is specified by separate
attributes for each of its parts:
-<p style="margin-left: 2em">{@code scheme://host:port/path} <i>or</i>
-{@code pathPrefix} <i>or</i> {@code pathPattern}</p>
+<p style="margin-left: 2em">
+{@code &lt;scheme>://&lt;host>:&lt;port>/[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
<p>
-These attributes are optional, but also mutually dependent:
-If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> is not specified for the
-intent filter, all the other URI attributes are ignored. If a
-<code><a href="{@docRoot}guide/topics/manifest/data-element.html#host">host</a></code> is not specified for the filter,
-the {@code port} attribute and all the path attributes are ignored.
-</p>
+These attributes that specify the URL format are optional, but also mutually dependent:
+<ul>
+ <li>If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code>
+is not specified for the intent filter, all the other URI attributes are ignored.</li>
+ <li>If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#host">host</a></code>
+is not specified for the filter, the {@code port} attribute and all the path attributes are ignored.
+</ul>
<p>
All the {@code &lt;data&gt;} elements contained within the same
@@ -54,111 +55,117 @@ the same filter. So, for example, the following filter specification,
&lt;/intent-filter&gt;</pre>
<p>
-You can place any number of &lt;data&gt; elements inside an
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> to give it multiple data
-options. None of its attributes have default values.
+You can place any number of {@code &lt;data&gt;} elements inside an
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> to give it multiple data
+options. None of its attributes have default values.
</p>
<p>
Information on how intent filters work, including the rules for how Intent objects
are matched against filters, can be found in another document,
<a href="{@docRoot}guide/components/intents-filters.html">Intents and
-Intent Filters</a>. See also the
-<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#ifs">Intent Filters</a>
-section in the introduction.
+Intent Filters</a>. See also the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#ifs">Intent Filters</a>
+section in the manifest file overview.
</p></dd>
<dt>attributes:</dt>
<dd><dl class="attr">
+
+<dt><a name="scheme"></a>{@code android:scheme}</dt>
+<dd>The scheme part of a URI. This is the minimal essential attribute for
+specifying a URI; at least one {@code scheme} attribute must be set
+for the filter, or none of the other URI attributes are meaningful.
+
+<p>
+A scheme is specified without the trailing colon (for example,
+{@code http}, rather than {@code http:}).
+</p>
+
+<p>
+If the filter has a data type set (the <code><a
+href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code>
+attribute) but no scheme, the {@code content:} and {@code file:} schemes are
+assumed.
+</p>
+
+<p class="note"><strong>Note</strong>: Scheme matching in the Android framework is
+case-sensitive, unlike the RFC. As a result, you should always specify schemes
+using lowercase letters.</p>
+</dd>
+
<dt><a name="host"></a>{@code android:host}</dt>
<dd>The host part of a URI authority. This attribute is meaningless
-unless a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> attribute is also
+unless a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> attribute is also
specified for the filter.
-<p class="note">Note: host name matching in the Android framework is
+<p class="note"><strong>Note</strong>: host name matching in the Android framework is
case-sensitive, unlike the formal RFC. As a result, you should always specify
host names using lowercase letters.</p>
</dd>
-<dt><a name="mime"></a>{@code android:mimeType}</dt>
-<dd>A MIME media type, such as {@code image/jpeg} or {@code audio/mpeg4-generic}.
-The subtype can be the asterisk wildcard ({@code *}) to indicate that any
-subtype matches.
-<p>It's common for an intent filter to declare a {@code &lt;data>} that includes
-only the {@code android:mimeType} attribute.</p>
+<dt><a name="port"></a>{@code android:port}</dt>
+<dd>The port part of a URI authority. This attribute is meaningful only
+if the <code><a href="#scheme">scheme</a></code> and
+<code><a href="#host">host</a></code> attributes are also specified for
+the filter.</dd>
-<p class="note">Note: MIME type matching in the Android framework is
-case-sensitive, unlike formal RFC MIME types. As a result, you should always
-specify MIME types using lowercase letters.</p>
-</dd>
<dt><a name="path"></a>{@code android:path}
<br/>{@code android:pathPrefix}
<br/>{@code android:pathPattern}</dt>
-<dd>The path part of a URI. The {@code path} attribute specifies a complete
-path that is matched against the complete path in an Intent object. The
-{@code pathPrefix} attribute specifies a partial path that is matched against
-only the initial part of the path in the Intent object. The {@code pathPattern}
-attribute specifies a complete path that is matched against the complete path
-in the Intent object, but it can contain the following wildcards:
+<dd>The path part of a URI. The {@code path} attribute specifies a complete
+path that is matched against the complete path in an Intent object. The
+{@code pathPrefix} attribute specifies a partial path that is matched against
+only the initial part of the path in the Intent object. The {@code pathPattern}
+attribute specifies a complete path that is matched against the complete path
+in the Intent object, but it can contain the following wildcards:
<ul>
<li>An asterisk ('{@code *}') matches a sequence of 0 to many occurrences of
the immediately preceding character.</li>
-<li>A period followed by an asterisk ("{@code .*}") matches any sequence of
+<li>A period followed by an asterisk ("{@code .*}") matches any sequence of
0 to many characters.</li>
</ul>
<p>
-Because '{@code \}' is used as an escape character when the string is read
-from XML (before it is parsed as a pattern), you will need to double-escape:
-For example, a literal '{@code *}' would be written as "{@code \\*}" and a
-literal '{@code \}' would be written as "{@code \\\\}". This is basically
+Because '{@code \}' is used as an escape character when the string is read
+from XML (before it is parsed as a pattern), you will need to double-escape:
+For example, a literal '{@code *}' would be written as "{@code \\*}" and a
+literal '{@code \}' would be written as "{@code \\\\}". This is basically
the same as what you would need to write if constructing the string in Java code.
</p>
<p>
-For more information on these three types of patterns, see the descriptions of
+For more information on these three types of patterns, see the descriptions of
{@link android.os.PatternMatcher#PATTERN_LITERAL},
{@link android.os.PatternMatcher#PATTERN_PREFIX}, and
{@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB} in the
{@link android.os.PatternMatcher} class.
</p>
-<p>These attributes are meaningful only if the
-<code><a href="#scheme">scheme</a></code> and <code><a href="#host">host</a></code>
+<p>These attributes are meaningful only if the
+<code><a href="#scheme">scheme</a></code> and <code><a href="#host">host</a></code>
attributes are also specified for the filter.
</p></dd>
-<dt><a name="port"></a>{@code android:port}</dt>
-<dd>The port part of a URI authority. This attribute is meaningful only
-if the <code><a href="#scheme">scheme</a></code> and
-<code><a href="#host">host</a></code> attributes are also specified for
-the filter.</dd>
-
-<dt><a name="scheme"></a>{@code android:scheme}</dt>
-<dd>The scheme part of a URI. This is the minimal essential attribute for
-specifying a URI; at least one {@code scheme} attribute must be set
-for the filter, or none of the other URI attributes are meaningful.
+<dt><a name="mime"></a>{@code android:mimeType}</dt>
+<dd>A MIME media type, such as {@code image/jpeg} or {@code audio/mpeg4-generic}.
+The subtype can be the asterisk wildcard ({@code *}) to indicate that any
+subtype matches.
-<p>
-A scheme is specified without the trailing colon (for example,
-{@code http}, rather than {@code http:}).
-</p>
+<p>It's common for an intent filter to declare a {@code &lt;data>} that includes
+only the {@code android:mimeType} attribute.</p>
-<p>
-If the filter has a data type set (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code>
-attribute) but no scheme, the {@code content:} and {@code file:} schemes are
-assumed.
-</p>
-<p class="note">Note: scheme matching in the Android framework is
-case-sensitive, unlike the RFC. As a result, you should always specify schemes
-using lowercase letters.</p>
+<p class="note"><strong>Note</strong>: MIME type matching in the Android framework is
+case-sensitive, unlike formal RFC MIME types. As a result, you should always
+specify MIME types using lowercase letters.</p>
</dd>
-</dl></dd>
+
+</dl></dd>
<!-- ##api level indication## -->
<dt>introduced in:</dt>
diff --git a/docs/html/guide/topics/providers/document-provider.jd b/docs/html/guide/topics/providers/document-provider.jd
index cd1fd1a..8ea08bd 100644
--- a/docs/html/guide/topics/providers/document-provider.jd
+++ b/docs/html/guide/topics/providers/document-provider.jd
@@ -80,7 +80,7 @@ StorageClient</a></li>
across all of their their preferred document storage providers. A standard, easy-to-use UI
lets users browse files and access recents in a consistent way across apps and providers.</p>
-<p>Cloud or local storage services can participate in this ecosystem by implementing a new
+<p>Cloud or local storage services can participate in this ecosystem by implementing a
{@link android.provider.DocumentsProvider} that encapsulates their services. Client
apps that need access to a provider's documents can integrate with the SAF with just a few
lines of code.</p>
diff --git a/docs/html/images/components/intent-filters@2x.png b/docs/html/images/components/intent-filters@2x.png
new file mode 100644
index 0000000..5b1e38b
--- /dev/null
+++ b/docs/html/images/components/intent-filters@2x.png
Binary files differ
diff --git a/docs/html/training/basics/intents/filters.jd b/docs/html/training/basics/intents/filters.jd
index 9b6a111..10bf43d 100644
--- a/docs/html/training/basics/intents/filters.jd
+++ b/docs/html/training/basics/intents/filters.jd
@@ -148,8 +148,8 @@ the recipient's address using the {@code send} or {@code sendto} URI scheme. For
{@link android.content.Intent#CATEGORY_DEFAULT} category in the intent filter. The methods {@link
android.app.Activity#startActivity startActivity()} and {@link
android.app.Activity#startActivityForResult startActivityForResult()} treat all intents as if they
-contained the {@link android.content.Intent#CATEGORY_DEFAULT} category. If you do not declare it, no
-implicit intents will resolve to your activity.</p>
+declared the {@link android.content.Intent#CATEGORY_DEFAULT} category. If you do not declare it
+in your intent filter, no implicit intents will resolve to your activity.</p>
<p>For more information about sending and receiving {@link android.content.Intent#ACTION_SEND}
intents that perform social sharing behaviors, see the lesson about <a
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 79c017b..30dc95a 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -241,9 +241,13 @@ Intent intent = new Intent(Intent.ACTION_SEND);
// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
-// Create and start the chooser
+// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, title);
-startActivity(chooser);
+
+// Verify the intent will resolve to at least one activity
+if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(chooser);
+}
</pre>
<p>This displays a dialog with a list of apps that respond to the intent passed to the {@link
diff --git a/docs/html/training/sharing/send.jd b/docs/html/training/sharing/send.jd
index f5da68f..e869d5f 100644
--- a/docs/html/training/sharing/send.jd
+++ b/docs/html/training/sharing/send.jd
@@ -75,10 +75,12 @@ startActivity(sendIntent);
<p>If there's an installed application with a filter that matches
{@link android.content.Intent#ACTION_SEND} and MIME type text/plain, the Android system will run
it; if more than one application matches, the system displays a disambiguation dialog (a "chooser")
-that allows the user to choose an app. If you call
+that allows the user to choose an app.</p>
+
+<p>However, if you call
{@link android.content.Intent#createChooser(android.content.Intent, CharSequence)
-Intent.createChooser()}
-for the intent, Android will <strong>always</strong> display the chooser. This has some
+Intent.createChooser()}, passing it your {@link android.content.Intent} object, it returns a version
+of your intent that will <strong>always display the chooser</strong>. This has some
advantages:</p>
<ul>
@@ -102,10 +104,8 @@ startActivity(<strong>Intent.createChooser(sendIntent, getResources().getText(R.
<p>Optionally, you can set some standard extras for the intent:
{@link android.content.Intent#EXTRA_EMAIL}, {@link android.content.Intent#EXTRA_CC},
-{@link android.content.Intent#EXTRA_BCC}, {@link android.content.Intent#EXTRA_SUBJECT}. However,
-if the receiving application is not designed to use them, nothing will happen. You can use
-custom extras as well, but there's no effect unless the receiving application understands them.
-Typically, you'd use custom extras defined by the receiving application itself.</p>
+{@link android.content.Intent#EXTRA_BCC}, {@link android.content.Intent#EXTRA_SUBJECT}.
+If the receiving application is not designed to use them, it simply ignores them.</p>
<p class="note"><strong>Note:</strong> Some e-mail applications, such as Gmail, expect a
{@link java.lang.String String[]} for extras like {@link android.content.Intent#EXTRA_EMAIL} and
diff --git a/docs/html/training/system-ui/navigation.jd b/docs/html/training/system-ui/navigation.jd
index 3907bb2..1c73c70 100644
--- a/docs/html/training/system-ui/navigation.jd
+++ b/docs/html/training/system-ui/navigation.jd
@@ -63,6 +63,9 @@ user experience. </p>
the navigation bar and the status bar:</p>
<pre>View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
+// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
+// a general rule, you should design your app to hide the status bar whenever you
+// hide the navigation bar.
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);</pre>
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
new file mode 100644
index 0000000..923571e
--- /dev/null
+++ b/libs/hwui/AmbientShadow.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <math.h>
+#include <utils/Log.h>
+
+#include "AmbientShadow.h"
+#include "Vertex.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Calculate the shadows as a triangle strips while alpha value as the
+ * shadow values.
+ *
+ * @param vertices The shadow caster's polygon, which is represented in a Vector3
+ * array.
+ * @param vertexCount The length of caster's polygon in terms of number of
+ * vertices.
+ * @param rays The number of rays shooting out from the centroid.
+ * @param layers The number of rings outside the polygon.
+ * @param strength The darkness of the shadow, the higher, the darker.
+ * @param heightFactor The factor showing the higher the object, the lighter the
+ * shadow.
+ * @param geomFactor The factor scaling the geometry expansion along the normal.
+ *
+ * @param shadowVertexBuffer Return an floating point array of (x, y, a)
+ * triangle strips mode.
+ */
+void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount,
+ int rays, int layers, float strength, float heightFactor, float geomFactor,
+ VertexBuffer& shadowVertexBuffer) {
+
+ // Validate the inputs.
+ if (strength <= 0 || heightFactor <= 0 || layers <= 0 || rays <= 0
+ || geomFactor <= 0) {
+#if DEBUG_SHADOW
+ ALOGE("Invalid input for createAmbientShadow(), early return!");
+#endif
+ return;
+ }
+ int rings = layers + 1;
+ int size = rays * rings;
+ Vector2 centroid;
+ calculatePolygonCentroid(vertices, vertexCount, centroid);
+
+ Vector2 dir[rays];
+ float rayDist[rays];
+ float rayHeight[rays];
+ calculateRayDirections(rays, dir);
+
+ // Calculate the length and height of the points along the edge.
+ //
+ // The math here is:
+ // Intersect each ray (starting from the centroid) with the polygon.
+ for (int i = 0; i < rays; i++) {
+ int edgeIndex;
+ float edgeFraction;
+ float rayDistance;
+ calculateIntersection(vertices, vertexCount, centroid, dir[i], edgeIndex,
+ edgeFraction, rayDistance);
+ rayDist[i] = rayDistance;
+ if (edgeIndex < 0 || edgeIndex >= vertexCount) {
+#if DEBUG_SHADOW
+ ALOGE("Invalid edgeIndex!");
+#endif
+ edgeIndex = 0;
+ }
+ float h1 = vertices[edgeIndex].z;
+ float h2 = vertices[((edgeIndex + 1) % vertexCount)].z;
+ rayHeight[i] = h1 + edgeFraction * (h2 - h1);
+ }
+
+ // The output buffer length basically is roughly rays * layers, but since we
+ // need triangle strips, so we need to duplicate vertices to accomplish that.
+ const int shadowVertexCount = (2 + rays + ((layers) * 2 * (rays + 1)));
+ AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(shadowVertexCount);
+
+ // Calculate the vertex of the shadows.
+ //
+ // The math here is:
+ // Along the edges of the polygon, for each intersection point P (generated above),
+ // calculate the normal N, which should be perpendicular to the edge of the
+ // polygon (represented by the neighbor intersection points) .
+ // Shadow's vertices will be generated as : P + N * scale.
+ int currentIndex = 0;
+ for (int r = 0; r < layers; r++) {
+ int firstInLayer = currentIndex;
+ for (int i = 0; i < rays; i++) {
+
+ Vector2 normal(1.0f, 0.0f);
+ calculateNormal(rays, i, dir, rayDist, normal);
+
+ float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
+
+ // The vertex should be start from rayDist[i] then scale the
+ // normalizeNormal!
+ Vector2 intersection = dir[i] * rayDist[i] + centroid;
+
+ // Use 2 rings' vertices to complete one layer's strip
+ for (int j = r; j < (r + 2); j++) {
+ float jf = j / (float)(rings - 1);
+
+ float expansionDist = rayHeight[i] / heightFactor * geomFactor * jf;
+ AlphaVertex::set(&shadowVertices[currentIndex],
+ intersection.x + normal.x * expansionDist,
+ intersection.y + normal.y * expansionDist,
+ (1 - jf) * opacity);
+ currentIndex++;
+ }
+ }
+
+ // From one layer to the next, we need to duplicate the vertex to
+ // continue as a single strip.
+ shadowVertices[currentIndex] = shadowVertices[firstInLayer];
+ currentIndex++;
+ shadowVertices[currentIndex] = shadowVertices[firstInLayer + 1];
+ currentIndex++;
+ }
+
+ // After all rings are done, we need to jump into the polygon.
+ // In order to keep everything in a strip, we need to duplicate the last one
+ // of the rings and the first one inside the polygon.
+ int lastInRings = currentIndex - 1;
+ shadowVertices[currentIndex] = shadowVertices[lastInRings];
+ currentIndex++;
+
+ // We skip one and fill it back after we finish the internal triangles.
+ currentIndex++;
+ int firstInternal = currentIndex;
+
+ // Combine the internal area of the polygon into a triangle strip, too.
+ // The basic idea is zig zag between the intersection points.
+ // 0 -> (n - 1) -> 1 -> (n - 2) ...
+ for (int k = 0; k < rays; k++) {
+ int i = k / 2;
+ if ((k & 1) == 1) { // traverse the inside in a zig zag pattern for strips
+ i = rays - i - 1;
+ }
+ float cast = rayDist[i] * (1 + rayHeight[i] / heightFactor);
+ float opacity = strength * (0.5f) / (1 + rayHeight[i] / heightFactor);
+ float t = rayDist[i];
+
+ AlphaVertex::set(&shadowVertices[currentIndex], dir[i].x * t + centroid.x,
+ dir[i].y * t + centroid.y, opacity);
+ currentIndex++;
+ }
+
+ currentIndex = firstInternal - 1;
+ shadowVertices[currentIndex] = shadowVertices[firstInternal];
+}
+
+/**
+ * Calculate the centroid of a given polygon.
+ *
+ * @param vertices The shadow caster's polygon, which is represented in a
+ * straight Vector3 array.
+ * @param vertexCount The length of caster's polygon in terms of number of vertices.
+ *
+ * @param centroid Return the centroid of the polygon.
+ */
+void AmbientShadow::calculatePolygonCentroid(const Vector3* vertices, int vertexCount,
+ Vector2& centroid) {
+ float sumx = 0;
+ float sumy = 0;
+ int p1 = vertexCount - 1;
+ float area = 0;
+ for (int p2 = 0; p2 < vertexCount; p2++) {
+ float x1 = vertices[p1].x;
+ float y1 = vertices[p1].y;
+ float x2 = vertices[p2].x;
+ float y2 = vertices[p2].y;
+ float a = (x1 * y2 - x2 * y1);
+ sumx += (x1 + x2) * a;
+ sumy += (y1 + y2) * a;
+ area += a;
+ p1 = p2;
+ }
+
+ if (area == 0) {
+#if DEBUG_SHADOW
+ ALOGE("Area is 0!");
+#endif
+ centroid.x = vertices[0].x;
+ centroid.y = vertices[0].y;
+ } else {
+ centroid.x = sumx / (3 * area);
+ centroid.y = sumy / (3 * area);
+ }
+}
+
+/**
+ * Generate an array of rays' direction vectors.
+ *
+ * @param rays The number of rays shooting out from the centroid.
+ * @param dir Return the array of ray vectors.
+ */
+void AmbientShadow::calculateRayDirections(int rays, Vector2* dir) {
+ float deltaAngle = 2 * M_PI / rays;
+
+ for (int i = 0; i < rays; i++) {
+ dir[i].x = sinf(deltaAngle * i);
+ dir[i].y = cosf(deltaAngle * i);
+ }
+}
+
+/**
+ * Calculate the intersection of a ray hitting the polygon.
+ *
+ * @param vertices The shadow caster's polygon, which is represented in a
+ * Vector3 array.
+ * @param vertexCount The length of caster's polygon in terms of number of vertices.
+ * @param start The starting point of the ray.
+ * @param dir The direction vector of the ray.
+ *
+ * @param outEdgeIndex Return the index of the segment (or index of the starting
+ * vertex) that ray intersect with.
+ * @param outEdgeFraction Return the fraction offset from the segment starting
+ * index.
+ * @param outRayDist Return the ray distance from centroid to the intersection.
+ */
+void AmbientShadow::calculateIntersection(const Vector3* vertices, int vertexCount,
+ const Vector2& start, const Vector2& dir, int& outEdgeIndex,
+ float& outEdgeFraction, float& outRayDist) {
+ float startX = start.x;
+ float startY = start.y;
+ float dirX = dir.x;
+ float dirY = dir.y;
+ // Start the search from the last edge from poly[len-1] to poly[0].
+ int p1 = vertexCount - 1;
+
+ for (int p2 = 0; p2 < vertexCount; p2++) {
+ float p1x = vertices[p1].x;
+ float p1y = vertices[p1].y;
+ float p2x = vertices[p2].x;
+ float p2y = vertices[p2].y;
+
+ // The math here is derived from:
+ // f(t, v) = p1x * (1 - t) + p2x * t - (startX + dirX * v) = 0;
+ // g(t, v) = p1y * (1 - t) + p2y * t - (startY + dirY * v) = 0;
+ float div = (dirX * (p1y - p2y) + dirY * p2x - dirY * p1x);
+ if (div != 0) {
+ float t = (dirX * (p1y - startY) + dirY * startX - dirY * p1x) / (div);
+ if (t > 0 && t <= 1) {
+ float t2 = (p1x * (startY - p2y)
+ + p2x * (p1y - startY)
+ + startX * (p2y - p1y)) / div;
+ if (t2 > 0) {
+ outEdgeIndex = p1;
+ outRayDist = t2;
+ outEdgeFraction = t;
+ return;
+ }
+ }
+ }
+ p1 = p2;
+ }
+ return;
+};
+
+/**
+ * Calculate the normal at the intersection point between a ray and the polygon.
+ *
+ * @param rays The total number of rays.
+ * @param currentRayIndex The index of the ray which the normal is based on.
+ * @param dir The array of the all the rays directions.
+ * @param rayDist The pre-computed ray distances array.
+ *
+ * @param normal Return the normal.
+ */
+void AmbientShadow::calculateNormal(int rays, int currentRayIndex,
+ const Vector2* dir, const float* rayDist, Vector2& normal) {
+ int preIndex = (currentRayIndex - 1 + rays) % rays;
+ int postIndex = (currentRayIndex + 1) % rays;
+ Vector2 p1 = dir[preIndex] * rayDist[preIndex];
+ Vector2 p2 = dir[postIndex] * rayDist[postIndex];
+
+ // Now the V (deltaX, deltaY) is the vector going CW around the poly.
+ Vector2 delta = p2 - p1;
+ if (delta.length() != 0) {
+ delta.normalize();
+ // Calculate the normal , which is CCW 90 rotate to the V.
+ // 90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z)
+ normal.x = -delta.y;
+ normal.y = delta.x;
+ }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
new file mode 100644
index 0000000..079bdb7
--- /dev/null
+++ b/libs/hwui/AmbientShadow.h
@@ -0,0 +1,57 @@
+
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_AMBIENT_SHADOW_H
+#define ANDROID_HWUI_AMBIENT_SHADOW_H
+
+#include "Debug.h"
+#include "Vector.h"
+#include "VertexBuffer.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * AmbientShadow is used to calculate the ambient shadow value around a polygon.
+ *
+ * TODO: calculateIntersection() now is O(N*M), where N is the number of
+ * polygon's vertics and M is the number of rays. In fact, by staring tracing
+ * the vertex from the previous intersection, the algorithm can be O(N + M);
+ */
+class AmbientShadow {
+public:
+ static void createAmbientShadow(const Vector3* poly, int polyLength, int rays,
+ int layers, float strength, float heightFactor, float geomFactor,
+ VertexBuffer& shadowVertexBuffer);
+
+private:
+ static void calculatePolygonCentroid(const Vector3* poly, int len, Vector2& centroid);
+
+ static void calculateRayDirections(int rays, Vector2* dir);
+
+ static void calculateIntersection(const Vector3* poly, int nbVertices,
+ const Vector2& start, const Vector2& dir, int& outEdgeIndex,
+ float& outEdgeFraction, float& outRayDist);
+
+ static void calculateNormal(int rays, int currentRayIndex, const Vector2* dir,
+ const float* rayDist, Vector2& normal);
+}; // AmbientShadow
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1f37925..962d726 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -10,6 +10,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
thread/TaskManager.cpp \
font/CacheTexture.cpp \
font/Font.cpp \
+ AmbientShadow.cpp \
AssetAtlas.cpp \
FontRenderer.cpp \
GammaFontRenderer.cpp \
@@ -37,6 +38,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
ProgramCache.cpp \
RenderBufferCache.cpp \
ResourceCache.cpp \
+ ShadowTessellator.cpp \
SkiaColorFilter.cpp \
SkiaShader.cpp \
Snapshot.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f8d3589..5b751b9 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -473,7 +473,7 @@ bool Caches::unbindPixelBuffer() {
// Meshes and textures
///////////////////////////////////////////////////////////////////////////////
-void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
+void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
GLuint slot = currentProgram->position;
glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
@@ -482,7 +482,7 @@ void Caches::bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei str
}
}
-void Caches::bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride) {
+void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
GLuint slot = currentProgram->texCoords;
glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index f8f2284..963965d 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -208,13 +208,13 @@ public:
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gMeshStride and a size of 2.
*/
- void bindPositionVertexPointer(bool force, GLvoid* vertices, GLsizei stride = gMeshStride);
+ void bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
/**
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gMeshStride and a size of 2.
*/
- void bindTexCoordsVertexPointer(bool force, GLvoid* vertices, GLsizei stride = gMeshStride);
+ void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
/**
* Resets the vertex pointers.
@@ -379,9 +379,9 @@ private:
GLuint mCurrentBuffer;
GLuint mCurrentIndicesBuffer;
GLuint mCurrentPixelBuffer;
- void* mCurrentPositionPointer;
+ const void* mCurrentPositionPointer;
GLsizei mCurrentPositionStride;
- void* mCurrentTexCoordsPointer;
+ const void* mCurrentTexCoordsPointer;
GLsizei mCurrentTexCoordsStride;
bool mTexCoordsArrayEnabled;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 786f12a..f619205 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -85,6 +85,12 @@
// Turn on to highlight drawing batches and merged batches with different colors
#define DEBUG_MERGE_BEHAVIOR 0
+// Turn on to enable 3D support in the renderer (off by default until API for control exists)
+#define DEBUG_ENABLE_3D 0
+
+// Turn on to enable debugging shadow
+#define DEBUG_SHADOW 0
+
#if DEBUG_INIT
#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
#else
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 3dcbd0b..fca3588 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -79,13 +79,13 @@ public:
};
class DeferredDisplayList {
+ friend class DeferStateStruct; // used to give access to allocator
public:
DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
clear();
}
~DeferredDisplayList() { clear(); }
- void reset(const Rect& bounds) { mBounds.set(bounds); }
enum OpBatchId {
kOpBatch_None = 0, // Don't batch
@@ -120,6 +120,8 @@ public:
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
private:
+ DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
+
DeferredDisplayState* createState() {
return new (mAllocator) DeferredDisplayState();
}
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a3e4bb4..c616cd8 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -14,8 +14,12 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
#include <SkCanvas.h>
+#include <utils/Trace.h>
+
#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
@@ -65,11 +69,6 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
void DisplayList::clearResources() {
mDisplayListData = NULL;
- mClipRectOp = NULL;
- mSaveLayerOp = NULL;
- mSaveOp = NULL;
- mRestoreToCountOp = NULL;
-
delete mTransformMatrix;
delete mTransformCamera;
delete mTransformMatrix3D;
@@ -168,17 +167,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
return;
}
- // allocate reusable ops for state-deferral
- LinearAllocator& alloc = mDisplayListData->allocator;
- mClipRectOp = new (alloc) ClipRectOp();
- mSaveLayerOp = new (alloc) SaveLayerOp();
- mSaveOp = new (alloc) SaveOp();
- mRestoreToCountOp = new (alloc) RestoreToCountOp();
- if (CC_UNLIKELY(!mSaveOp)) { // temporary debug logging
- ALOGW("Error: %s's SaveOp not allocated, size %d", getName(), mSize);
- CRASH();
- }
-
mFunctorCount = recorder.getFunctorCount();
Caches& caches = Caches::getInstance();
@@ -253,6 +241,7 @@ void DisplayList::init() {
mHasOverlappingRendering = true;
mTranslationX = 0;
mTranslationY = 0;
+ mTranslationZ = 0;
mRotation = 0;
mRotationX = 0;
mRotationY= 0;
@@ -269,6 +258,7 @@ void DisplayList::init() {
mHeight = 0;
mPivotExplicitlySet = false;
mCaching = false;
+ mIs3dRoot = true; // TODO: setter, java side impl
}
size_t DisplayList::getSize() {
@@ -320,27 +310,38 @@ void DisplayList::updateMatrix() {
mPivotY = mPrevHeight / 2.0f;
}
}
- if ((mMatrixFlags & ROTATION_3D) == 0) {
+ if (!DEBUG_ENABLE_3D && (mMatrixFlags & ROTATION_3D) == 0) {
mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
} else {
- if (!mTransformCamera) {
- mTransformCamera = new Sk3DView();
- mTransformMatrix3D = new SkMatrix();
+ if (DEBUG_ENABLE_3D) {
+ mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
+ mTranslationZ);
+ mTransform.rotate(mRotationX, 1, 0, 0);
+ mTransform.rotate(mRotationY, 0, 1, 0);
+ mTransform.rotate(mRotation, 0, 0, 1);
+ mTransform.scale(mScaleX, mScaleY, 1);
+ mTransform.translate(-mPivotX, -mPivotY);
+ } else {
+ /* TODO: support this old transform approach, based on API level */
+ if (!mTransformCamera) {
+ mTransformCamera = new Sk3DView();
+ mTransformMatrix3D = new SkMatrix();
+ }
+ mTransformMatrix->reset();
+ mTransformCamera->save();
+ mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ mTransformCamera->rotateX(mRotationX);
+ mTransformCamera->rotateY(mRotationY);
+ mTransformCamera->rotateZ(-mRotation);
+ mTransformCamera->getMatrix(mTransformMatrix3D);
+ mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
+ mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
+ mPivotY + mTranslationY);
+ mTransformMatrix->postConcat(*mTransformMatrix3D);
+ mTransformCamera->restore();
}
- mTransformMatrix->reset();
- mTransformCamera->save();
- mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
- mTransformCamera->rotateX(mRotationX);
- mTransformCamera->rotateY(mRotationY);
- mTransformCamera->rotateZ(-mRotation);
- mTransformCamera->getMatrix(mTransformMatrix3D);
- mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
- mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
- mPivotY + mTranslationY);
- mTransformMatrix->postConcat(*mTransformMatrix3D);
- mTransformCamera->restore();
}
}
mMatrixDirty = false;
@@ -417,8 +418,13 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
if (mMatrixFlags != 0) {
if (mMatrixFlags == TRANSLATION) {
renderer.translate(mTranslationX, mTranslationY);
+ renderer.translateZ(mTranslationZ);
} else {
+#if DEBUG_ENABLE_3D
+ renderer.concatMatrix(mTransform);
+#else
renderer.concatMatrix(mTransformMatrix);
+#endif
}
}
bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
@@ -436,14 +442,107 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
clipToBoundsNeeded = false; // clipping done by saveLayer
}
- handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
- mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
- mClipToBounds);
+
+ SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
+ 0, 0, mRight - mLeft, mBottom - mTop,
+ mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
}
}
if (clipToBoundsNeeded) {
- handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
- PROPERTY_SAVECOUNT, mClipToBounds);
+ ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
+ mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+ }
+}
+
+/**
+ * Apply property-based transformations to input matrix
+ */
+void DisplayList::applyViewPropertyTransforms(mat4& matrix) {
+ if (mLeft != 0 || mTop != 0) {
+ matrix.translate(mLeft, mTop);
+ }
+ if (mStaticMatrix) {
+ mat4 stat(*mStaticMatrix);
+ matrix.multiply(stat);
+ } else if (mAnimationMatrix) {
+ mat4 anim(*mAnimationMatrix);
+ matrix.multiply(anim);
+ }
+ if (mMatrixFlags != 0) {
+ if (mMatrixFlags == TRANSLATION) {
+ matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
+ } else {
+#if DEBUG_ENABLE_3D
+ matrix.multiply(mTransform);
+#else
+ mat4 temp(*mTransformMatrix);
+ matrix.multiply(temp);
+#endif
+ }
+ }
+}
+
+/**
+ * Organizes the DisplayList hierarchy to prepare for Z-based draw order.
+ *
+ * This should be called before a call to defer() or drawDisplayList()
+ *
+ * Each DisplayList that serves as a 3d root builds its list of composited children,
+ * which are flagged to not draw in the standard draw loop.
+ */
+void DisplayList::computeOrdering() {
+ ATRACE_CALL();
+ mat4::identity();
+ for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
+ DrawDisplayListOp* childOp = mDisplayListData->children[i];
+ childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity());
+ }
+}
+
+void DisplayList::computeOrderingImpl(
+ DrawDisplayListOp* opState,
+ KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
+ const mat4* transformFrom3dRoot) {
+ // TODO: should avoid this calculation in most cases
+ opState->mTransformFrom3dRoot.load(*transformFrom3dRoot);
+ opState->mTransformFrom3dRoot.multiply(opState->mTransformFromParent);
+
+ if (mTranslationZ != 0.0f) { // TODO: other signals, such as custom 4x4 matrix
+ // composited layer, insert into current 3d root and flag for out of order draw
+ opState->mSkipInOrderDraw = true;
+
+ Vector3 pivot(mPivotX, mPivotY, 0.0f);
+ mat4 totalTransform(opState->mTransformFrom3dRoot);
+ applyViewPropertyTransforms(totalTransform);
+ totalTransform.mapPoint3d(pivot);
+ const float key = pivot.z;
+
+ if (compositedChildrenOf3dRoot->indexOfKey(key) < 0) {
+ compositedChildrenOf3dRoot->add(key, Vector<DrawDisplayListOp*>());
+ }
+ compositedChildrenOf3dRoot->editValueFor(key).push(opState);
+ } else {
+ // standard in order draw
+ opState->mSkipInOrderDraw = false;
+ }
+
+ m3dNodes.clear();
+ if (mIs3dRoot) {
+ // create a new 3d space for children by separating their ordering
+ compositedChildrenOf3dRoot = &m3dNodes;
+ transformFrom3dRoot = &mat4::identity();
+ } else {
+ transformFrom3dRoot = &(opState->mTransformFrom3dRoot);
+ }
+
+ if (mDisplayListData->children.size() > 0) {
+ for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
+ DrawDisplayListOp* childOp = mDisplayListData->children[i];
+ childOp->mDisplayList->computeOrderingImpl(childOp,
+ compositedChildrenOf3dRoot, transformFrom3dRoot);
+ }
}
}
@@ -454,6 +553,8 @@ public:
inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
}
+ inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
+
private:
DeferStateStruct& mDeferStruct;
const int mLevel;
@@ -474,6 +575,8 @@ public:
#endif
operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
}
+ inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
+
private:
ReplayStateStruct& mReplayStruct;
const int mLevel;
@@ -490,11 +593,60 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
replayStruct.mDrawGlStatus);
}
+template <class T>
+void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
+ T& handler, const int level) {
+ if (m3dNodes.size() == 0 ||
+ (mode == kNegativeZChildren && m3dNodes.keyAt(0) > 0.0f) ||
+ (mode == kPositiveZChildren && m3dNodes.keyAt(m3dNodes.size() - 1) < 0.0f)) {
+ // nothing to draw
+ return;
+ }
+
+ LinearAllocator& alloc = handler.allocator();
+ ClipRectOp* op = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
+ SkRegion::kIntersect_Op); // clip to 3d root bounds for now
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+
+ for (int i = 0; i < m3dNodes.size(); i++) {
+ const float zValue = m3dNodes.keyAt(i);
+
+ if (mode == kPositiveZChildren && zValue < 0.0f) continue;
+ if (mode == kNegativeZChildren && zValue > 0.0f) break;
+
+ const Vector<DrawDisplayListOp*>& nodesAtZ = m3dNodes[i];
+ for (int j = 0; j < nodesAtZ.size(); j++) {
+ DrawDisplayListOp* op = nodesAtZ[j];
+ if (mode == kPositiveZChildren) {
+ /* draw shadow on renderer with parent matrix applied, passing in the child's total matrix
+ *
+ * TODO:
+ * -determine and pass background shape (and possibly drawable alpha)
+ * -view must opt-in to shadows
+ * -consider shadows for other content
+ */
+ mat4 shadowMatrix(op->mTransformFrom3dRoot);
+ op->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
+ DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, op->mDisplayList->mAlpha,
+ op->mDisplayList->getWidth(), op->mDisplayList->getHeight());
+ handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds);
+ }
+
+ renderer.concatMatrix(op->mTransformFrom3dRoot);
+ op->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
+ handler(op, renderer.getSaveCount() - 1, mClipToBounds);
+ op->mSkipInOrderDraw = true;
+ }
+ }
+ handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
+}
+
/**
* This function serves both defer and replay modes, and will organize the displayList's component
* operations for a single frame:
*
- * Every 'simple' operation that affects just the matrix and alpha (or other factors of
+ * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
* DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
* defer logic) and operations in displayListOps are issued through the 'handler' which handles the
* defer vs replay logic, per operation
@@ -517,8 +669,9 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level)
clipRect->right, clipRect->bottom);
#endif
+ LinearAllocator& alloc = handler.allocator();
int restoreTo = renderer.getSaveCount();
- handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+ handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
PROPERTY_SAVECOUNT, mClipToBounds);
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
@@ -526,30 +679,31 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level)
setViewProperties<T>(renderer, handler, level + 1);
- if (mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight)) {
- DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
- handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
- renderer.restoreToCount(restoreTo);
- renderer.setOverrideLayerAlpha(1.0f);
- return;
- }
+ bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight);
+ if (!quickRejected) {
+ // for 3d root, draw children with negative z values
+ iterate3dChildren(kNegativeZChildren, renderer, handler, level);
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- int saveCount = renderer.getSaveCount() - 1;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
+ op->output(level + 1);
#endif
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCount, mClipToBounds);
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, mClipToBounds);
+ }
+
+ // for 3d root, draw children with positive z values
+ iterate3dChildren(kPositiveZChildren, renderer, handler, level);
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
- handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
- renderer.restoreToCount(restoreTo);
+ handler(new (alloc) RestoreToCountOp(restoreTo),
+ PROPERTY_SAVECOUNT, mClipToBounds);
renderer.setOverrideLayerAlpha(1.0f);
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index f52181a..4bd79eb 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -26,6 +26,7 @@
#include <private/hwui/DrawGlInfo.h>
+#include <utils/KeyedVector.h>
#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
@@ -37,6 +38,8 @@
#include <androidfw/ResourceTypes.h>
#include "Debug.h"
+#include "Matrix.h"
+#include "DeferredDisplayList.h"
#define TRANSLATION 0x0001
#define ROTATION 0x0002
@@ -65,36 +68,70 @@ class ClipRectOp;
class SaveLayerOp;
class SaveOp;
class RestoreToCountOp;
+class DrawDisplayListOp;
-struct DeferStateStruct {
- DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
- : mDeferredList(deferredList), mRenderer(renderer), mReplayFlags(replayFlags) {}
- DeferredDisplayList& mDeferredList;
+/**
+ * Holds data used in the playback a tree of DisplayLists.
+ */
+class PlaybackStateStruct {
+protected:
+ PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
+ : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator){}
+
+public:
OpenGLRenderer& mRenderer;
const int mReplayFlags;
+
+ // Allocator with the lifetime of a single frame.
+ // replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator
+ LinearAllocator * const mAllocator;
};
-struct ReplayStateStruct {
+class DeferStateStruct : public PlaybackStateStruct {
+public:
+ DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
+ : PlaybackStateStruct(renderer, replayFlags, &(deferredList.mAllocator)), mDeferredList(deferredList) {}
+
+ DeferredDisplayList& mDeferredList;
+};
+
+class ReplayStateStruct : public PlaybackStateStruct {
+public:
ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
- : mRenderer(renderer), mDirty(dirty), mReplayFlags(replayFlags),
- mDrawGlStatus(DrawGlInfo::kStatusDone) {}
- OpenGLRenderer& mRenderer;
+ : PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator),
+ mDirty(dirty), mDrawGlStatus(DrawGlInfo::kStatusDone) {}
+
Rect& mDirty;
- const int mReplayFlags;
status_t mDrawGlStatus;
+ LinearAllocator mReplayAllocator;
};
/**
- * Refcounted structure that holds data used in display list stream
+ * Refcounted structure that holds the list of commands used in display list stream.
*/
class DisplayListData : public LightRefBase<DisplayListData> {
public:
+ // allocator into which all ops were allocated
LinearAllocator allocator;
+
+ // pointers to all ops within display list, pointing into allocator data
Vector<DisplayListOp*> displayListOps;
+
+ // list of children display lists for quick, non-drawing traversal
+ Vector<DrawDisplayListOp*> children;
};
/**
- * Replays recorded drawing commands.
+ * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
+ *
+ * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
+ * functionality is split between DisplayListRenderer (which manages the recording), DisplayListData
+ * (which holds the actual data), and DisplayList (which holds properties and performs playback onto
+ * a renderer).
+ *
+ * Note that DisplayListData is swapped out from beneath an individual DisplayList when a view's
+ * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
+ * attached.
*/
class DisplayList {
public:
@@ -113,6 +150,7 @@ public:
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
+ void computeOrdering();
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
@@ -188,12 +226,7 @@ public:
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
- mMatrixDirty = true;
- if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
- mMatrixFlags &= ~TRANSLATION;
- } else {
- mMatrixFlags |= TRANSLATION;
- }
+ onTranslationUpdate();
}
}
@@ -204,12 +237,7 @@ public:
void setTranslationY(float translationY) {
if (translationY != mTranslationY) {
mTranslationY = translationY;
- mMatrixDirty = true;
- if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
- mMatrixFlags &= ~TRANSLATION;
- } else {
- mMatrixFlags |= TRANSLATION;
- }
+ onTranslationUpdate();
}
}
@@ -217,6 +245,17 @@ public:
return mTranslationY;
}
+ void setTranslationZ(float translationZ) {
+ if (translationZ != mTranslationZ) {
+ mTranslationZ = translationZ;
+ onTranslationUpdate();
+ }
+ }
+
+ float getTranslationZ() const {
+ return mTranslationZ;
+ }
+
void setRotation(float rotation) {
if (rotation != mRotation) {
mRotation = rotation;
@@ -454,12 +493,36 @@ public:
}
private:
+ enum ChildrenSelectMode {
+ kNegativeZChildren,
+ kPositiveZChildren
+ };
+
+ void onTranslationUpdate() {
+ mMatrixDirty = true;
+ if (mTranslationX == 0.0f && mTranslationY == 0.0f && mTranslationZ == 0.0f) {
+ mMatrixFlags &= ~TRANSLATION;
+ } else {
+ mMatrixFlags |= TRANSLATION;
+ }
+ }
+
void outputViewProperties(const int level);
+ void applyViewPropertyTransforms(mat4& matrix);
+
+ void computeOrderingImpl(DrawDisplayListOp* opState,
+ KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
+ const mat4* transformFromRoot);
+
template <class T>
inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
template <class T>
+ inline void iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
+ T& handler, const int level);
+
+ template <class T>
inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
void init();
@@ -509,7 +572,7 @@ private:
bool mClipToBounds;
float mAlpha;
bool mHasOverlappingRendering;
- float mTranslationX, mTranslationY;
+ float mTranslationX, mTranslationY, mTranslationZ;
float mRotation, mRotationX, mRotationY;
float mScaleX, mScaleY;
float mPivotX, mPivotY;
@@ -526,23 +589,17 @@ private:
SkMatrix* mTransformMatrix3D;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
+ Matrix4 mTransform;
bool mCaching;
+ bool mIs3dRoot;
+
/**
- * State operations - needed to defer displayList property operations (for example, when setting
- * an alpha causes a SaveLayerAlpha to occur). These operations point into mDisplayListData's
- * allocation, or null if uninitialized.
- *
- * These are initialized (via friend re-constructors) when a displayList is issued in either
- * replay or deferred mode. If replaying, the ops are not used until the next frame. If
- * deferring, the ops may be stored in the DeferredDisplayList to be played back a second time.
- *
- * They should be used at most once per frame (one call to 'iterate') to avoid overwriting data
+ * Draw time state - these properties are only set and used during rendering
*/
- ClipRectOp* mClipRectOp;
- SaveLayerOp* mSaveLayerOp;
- SaveOp* mSaveOp;
- RestoreToCountOp* mRestoreToCountOp;
+
+ // for 3d roots, contains a z sorted list of all children items
+ KeyedVector<float, Vector<DrawDisplayListOp*> > m3dNodes; // TODO: good data structure
}; // class DisplayList
}; // namespace uirenderer
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 88077d4..1980b03 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -262,7 +262,6 @@ protected:
///////////////////////////////////////////////////////////////////////////////
class SaveOp : public StateOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveOp(int flags)
: mFlags(flags) {}
@@ -295,7 +294,6 @@ private:
};
class RestoreToCountOp : public StateOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
RestoreToCountOp(int count)
: mCount(count) {}
@@ -328,7 +326,6 @@ private:
};
class SaveLayerOp : public StateOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveLayerOp(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags)
@@ -524,7 +521,6 @@ protected:
};
class ClipRectOp : public ClipOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
: ClipOp(op), mArea(left, top, right, bottom) {}
@@ -1100,7 +1096,7 @@ private:
class DrawColorOp : public DrawOp {
public:
DrawColorOp(int color, SkXfermode::Mode mode)
- : DrawOp(0), mColor(color), mMode(mode) {};
+ : DrawOp(NULL), mColor(color), mMode(mode) {};
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawColor(mColor, mMode);
@@ -1505,7 +1501,7 @@ private:
class DrawFunctorOp : public DrawOp {
public:
DrawFunctorOp(Functor* functor)
- : DrawOp(0), mFunctor(functor) {}
+ : DrawOp(NULL), mFunctor(functor) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
renderer.startMark("GL functor");
@@ -1525,20 +1521,21 @@ private:
};
class DrawDisplayListOp : public DrawBoundedOp {
+ friend class DisplayList; // grant DisplayList access to info of child
public:
- DrawDisplayListOp(DisplayList* displayList, int flags)
+ DrawDisplayListOp(DisplayList* displayList, int flags, const mat4& transformFromParent)
: DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
- mDisplayList(displayList), mFlags(flags) {}
+ mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
- if (mDisplayList && mDisplayList->isRenderable()) {
+ if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
mDisplayList->defer(deferStruct, level + 1);
}
}
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
bool useQuickReject) {
- if (mDisplayList && mDisplayList->isRenderable()) {
+ if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
mDisplayList->replay(replayStruct, level + 1);
}
}
@@ -1559,13 +1556,58 @@ public:
private:
DisplayList* mDisplayList;
- int mFlags;
+ const int mFlags;
+
+ ///////////////////////////
+ // Properties below are used by DisplayList::computeOrderingImpl() and iterate()
+ ///////////////////////////
+ /**
+ * Records transform vs parent, used for computing total transform without rerunning DL contents
+ */
+ const mat4 mTransformFromParent;
+
+ /**
+ * Holds the transformation between the 3d root ViewGroup and this DisplayList drawing
+ * instance. Represents any translations / transformations done within the drawing of the 3d
+ * root ViewGroup's draw, before the draw of the View represented by this DisplayList draw
+ * instance.
+ *
+ * Note: doesn't include any transformation recorded within the DisplayList and its properties.
+ */
+ mat4 mTransformFrom3dRoot;
+ bool mSkipInOrderDraw;
+};
+
+/**
+ * Not a canvas operation, used only by 3d / z ordering logic in DisplayList::iterate()
+ */
+class DrawShadowOp : public DrawOp {
+public:
+ DrawShadowOp(const mat4& casterTransform, float casterAlpha, float width, float height)
+ : DrawOp(NULL), mCasterTransform(casterTransform), mCasterAlpha(casterAlpha),
+ mWidth(width), mHeight(height) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ return renderer.drawShadow(mCasterTransform, mCasterAlpha, mWidth, mHeight);
+ }
+
+ virtual void output(int level, uint32_t logFlags) const {
+ OP_LOG("DrawShadow of width %.2f, height %.2f", mWidth, mHeight);
+ }
+
+ virtual const char* name() { return "DrawShadow"; }
+
+private:
+ const mat4 mCasterTransform;
+ const float mCasterAlpha;
+ const float mWidth;
+ const float mHeight;
};
class DrawLayerOp : public DrawOp {
public:
DrawLayerOp(Layer* layer, float x, float y)
- : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
+ : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawLayer(mLayer, mX, mY);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index d024923..19a027d 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -111,6 +111,7 @@ DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) {
} else {
displayList->initFromDisplayListRenderer(*this, true);
}
+ // TODO: should just avoid setting the DisplayList's DisplayListData
displayList->setRenderable(mHasDrawOps);
return displayList;
}
@@ -120,7 +121,8 @@ bool DisplayListRenderer::isDeferred() {
}
void DisplayListRenderer::setViewport(int width, int height) {
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
+ mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
mWidth = width;
mHeight = height;
@@ -248,7 +250,10 @@ status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
// resources cache, but we rely on the caller (UI toolkit) to
// do the right thing for now
- addDrawOp(new (alloc()) DrawDisplayListOp(displayList, flags));
+ DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList, flags, currentTransform());
+ addDrawOp(op);
+ mDisplayListData->children.push(op);
+
return DrawGlInfo::kStatusDone;
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index d233150..7269378 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -328,6 +328,7 @@ private:
return patch;
}
+ // TODO: move these to DisplayListData
Vector<SkBitmap*> mBitmapResources;
Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 48613fe..f7493a3 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -733,7 +733,9 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int
if (mRs == 0) {
mRs = new RSC::RS();
- if (!mRs->init(RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
+ // a null path is OK because there are no custom kernels used
+ // hence nothing gets cached by RS
+ if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
ALOGE("blur RS failed to init");
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index bd371a3..742ffd4 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -194,11 +194,9 @@ void Layer::defer() {
dirtyRect.set(0, 0, width, height);
}
- if (deferredList) {
- deferredList->reset(dirtyRect);
- } else {
- deferredList = new DeferredDisplayList(dirtyRect);
- }
+ delete deferredList;
+ deferredList = new DeferredDisplayList(dirtyRect);
+
DeferStateStruct deferredState(*deferredList, *renderer,
DisplayList::kReplayFlag_ClipChildren);
@@ -206,6 +204,7 @@ void Layer::defer() {
renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom, !isBlend());
+ displayList->computeOrdering();
displayList->defer(deferredState, 0);
deferredUpdateScheduled = false;
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index ba22071..4f5cd26 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -89,8 +89,9 @@ uint8_t Matrix4::getType() const {
float m01 = data[kSkewX];
float m10 = data[kSkewY];
float m11 = data[kScaleY];
+ float m32 = data[kTranslateZ];
- if (m01 != 0.0f || m10 != 0.0f) {
+ if (m01 != 0.0f || m10 != 0.0f || m32 != 0.0f) {
mType |= kTypeAffine;
}
@@ -131,11 +132,13 @@ bool Matrix4::changesBounds() const {
}
bool Matrix4::isPureTranslate() const {
- return getGeometryType() <= kTypeTranslate;
+ // NOTE: temporary hack to workaround ignoreTransform behavior with Z values
+ // TODO: separate this into isPure2dTranslate vs isPure3dTranslate
+ return getGeometryType() <= kTypeTranslate && (data[kTranslateZ] == 0.0f);
}
bool Matrix4::isSimple() const {
- return getGeometryType() <= (kTypeScale | kTypeTranslate);
+ return getGeometryType() <= (kTypeScale | kTypeTranslate) && (data[kTranslateZ] == 0.0f);
}
bool Matrix4::isIdentity() const {
@@ -369,6 +372,84 @@ void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
mType = kTypeUnknown;
}
+// translated from android.opengl.Matrix#frustumM()
+void Matrix4::loadFrustum(float left, float top, float right, float bottom, float near, float far) {
+ float r_width = 1.0f / (right - left);
+ float r_height = 1.0f / (top - bottom);
+ float r_depth = 1.0f / (near - far);
+ float x = 2.0f * (near * r_width);
+ float y = 2.0f * (near * r_height);
+ float A = (right + left) * r_width;
+ float B = (top + bottom) * r_height;
+ float C = (far + near) * r_depth;
+ float D = 2.0f * (far * near * r_depth);
+
+ memset(&data, 0, sizeof(data));
+ mType = kTypeUnknown;
+
+ data[kScaleX] = x;
+ data[kScaleY] = y;
+ data[8] = A;
+ data[9] = B;
+ data[kScaleZ] = C;
+ data[kTranslateZ] = D;
+ data[11] = -1.0f;
+}
+
+// translated from android.opengl.Matrix#setLookAtM()
+void Matrix4::loadLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ float fx = centerX - eyeX;
+ float fy = centerY - eyeY;
+ float fz = centerZ - eyeZ;
+
+ // Normalize f
+ float rlf = 1.0f / sqrt(fx*fx + fy*fy + fz*fz);
+ fx *= rlf;
+ fy *= rlf;
+ fz *= rlf;
+
+ // compute s = f x up (x means "cross product")
+ float sx = fy * upZ - fz * upY;
+ float sy = fz * upX - fx * upZ;
+ float sz = fx * upY - fy * upX;
+
+ // and normalize s
+ float rls = 1.0f / sqrt(sx*sx + sy*sy + sz*sz);
+ sx *= rls;
+ sy *= rls;
+ sz *= rls;
+
+ // compute u = s x f
+ float ux = sy * fz - sz * fy;
+ float uy = sz * fx - sx * fz;
+ float uz = sx * fy - sy * fx;
+
+ mType = kTypeUnknown;
+ data[0] = sx;
+ data[1] = ux;
+ data[2] = -fx;
+ data[3] = 0.0f;
+
+ data[4] = sy;
+ data[5] = uy;
+ data[6] = -fy;
+ data[7] = 0.0f;
+
+ data[8] = sz;
+ data[9] = uz;
+ data[10] = -fz;
+ data[11] = 0.0f;
+
+ data[12] = 0.0f;
+ data[13] = 0.0f;
+ data[14] = 0.0f;
+ data[15] = 1.0f;
+
+ translate(-eyeX, -eyeY, -eyeZ);
+}
+
void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
loadIdentity();
@@ -382,6 +463,14 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float
mType = kTypeTranslate | kTypeScale | kTypeRectToRect;
}
+void Matrix4::mapPoint3d(Vector3& vec) const {
+ //TODO: optimize simple case
+ Vector3 orig(vec);
+ vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
+ vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
+ vec.z = orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ];
+}
+
#define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c)
void Matrix4::mapPoint(float& x, float& y) const {
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index b861ba4..00ca050 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -121,6 +121,10 @@ public:
void loadRotate(float angle);
void loadRotate(float angle, float x, float y, float z);
void loadMultiply(const Matrix4& u, const Matrix4& v);
+ void loadFrustum(float left, float top, float right, float bottom, float near, float far);
+ void loadLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ);
void loadOrtho(float left, float right, float bottom, float top, float near, float far);
@@ -134,17 +138,18 @@ public:
void multiply(float v);
- void translate(float x, float y) {
+ void translate(float x, float y, float z = 0) {
if ((getType() & sGeometryMask) <= kTypeTranslate) {
data[kTranslateX] += x;
data[kTranslateY] += y;
+ data[kTranslateZ] += z;
} else {
// Doing a translation will only affect the translate bit of the type
// Save the type
uint8_t type = mType;
Matrix4 u;
- u.loadTranslate(x, y, 0.0f);
+ u.loadTranslate(x, y, z);
multiply(u);
// Restore the type and fix the translate bit
@@ -190,8 +195,9 @@ public:
void copyTo(float* v) const;
void copyTo(SkMatrix& v) const;
- void mapRect(Rect& r) const;
- void mapPoint(float& x, float& y) const;
+ void mapPoint3d(Vector3& vec) const;
+ void mapPoint(float& x, float& y) const; // 2d only
+ void mapRect(Rect& r) const; // 2d only
float getTranslateX() const;
float getTranslateY() const;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 214d0b1..578a251 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -36,7 +36,9 @@
#include "Fence.h"
#include "PathTessellator.h"
#include "Properties.h"
+#include "ShadowTessellator.h"
#include "Vector.h"
+#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
@@ -180,7 +182,21 @@ void OpenGLRenderer::setViewport(int width, int height) {
}
void OpenGLRenderer::initViewport(int width, int height) {
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ float dist = std::max(width, height) * 1.5;
+
+ if (DEBUG_ENABLE_3D) {
+ // TODO: make view proj app configurable
+ Matrix4 projection;
+ projection.loadFrustum(-width / 2, -height / 2, width / 2, height / 2, dist, 0);
+ Matrix4 view;
+ view.loadLookAt(0, 0, dist,
+ 0, 0, 0,
+ 0, 1, 0);
+ mViewProjMatrix.loadMultiply(projection, view);
+ mViewProjMatrix.translate(-width/2, -height/2);
+ } else {
+ mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ }
mWidth = width;
mHeight = height;
@@ -753,7 +769,7 @@ bool OpenGLRenderer::restoreSnapshot() {
if (restoreOrtho) {
Rect& r = previous->viewport;
glViewport(r.left, r.top, r.right, r.bottom);
- mOrthoMatrix.load(current->orthoMatrix);
+ mViewProjMatrix.load(current->orthoMatrix);
}
mSaveCount--;
@@ -984,7 +1000,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
mSnapshot->height = bounds.getHeight();
- mSnapshot->orthoMatrix.load(mOrthoMatrix);
+ mSnapshot->orthoMatrix.load(mViewProjMatrix);
endTiling();
debugOverdraw(false, false);
@@ -1013,7 +1029,9 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
- mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+
+ // TODO: determine best way to support 3d drawing within HW layers
+ mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
return true;
}
@@ -1539,10 +1557,8 @@ void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
}
void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
- SkMatrix transform;
- currentTransform().copyTo(transform);
- transform.preConcat(*matrix);
- currentTransform().load(transform);
+ mat4 transform(*matrix);
+ currentTransform().multiply(transform);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1927,10 +1943,10 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
if (!ignoreTransform) {
- mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform(), offset);
+ mCaches.currentProgram->set(mViewProjMatrix, mModelView, currentTransform(), offset);
if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
} else {
- mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity(), offset);
+ mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
}
}
@@ -2064,9 +2080,12 @@ void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
int32_t replayFlags) {
status_t status;
+
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
+ // compute 3d ordering
+ displayList->computeOrdering();
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
status = startFrame();
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
@@ -2082,7 +2101,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
flushLayers();
status = startFrame();
- return status | deferredList.flush(*this, dirty);
+ return deferredList.flush(*this, dirty) | status;
}
return DrawGlInfo::kStatusDone;
@@ -2562,7 +2581,7 @@ status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPa
setupDrawColorFilterUniforms();
setupDrawShaderUniforms();
- void* vertices = vertexBuffer.getBuffer();
+ const void* vertices = vertexBuffer.getBuffer();
bool force = mCaches.unbindMeshBuffer();
mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
mCaches.resetTexCoordsVertexPointer();
@@ -3366,6 +3385,25 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint
return drawColorRects(rects, count, color, mode);
}
+status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha,
+ float width, float height) {
+ if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
+
+ // For now, always and scissor
+ // TODO: use quickReject
+ mCaches.enableScissor();
+
+ SkPaint paint;
+ paint.setColor(0x3f000000);
+ // Force the draw to use alpha values.
+ paint.setAntiAlias(true);
+
+ VertexBuffer shadowVertexBuffer;
+ ShadowTessellator::tessellateAmbientShadow(width, height, casterTransform,
+ shadowVertexBuffer);
+ return drawVertexBuffer(shadowVertexBuffer, &paint);
+}
+
status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
if (count == 0) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ff37e18..6046531 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -265,6 +265,12 @@ public:
ANDROID_API void getMatrix(SkMatrix* matrix);
virtual void setMatrix(SkMatrix* matrix);
virtual void concatMatrix(SkMatrix* matrix);
+ virtual void concatMatrix(Matrix4& matrix) {
+ currentTransform().multiply(matrix);
+ }
+ void translateZ(float z) {
+ currentTransform().translate(0,0,z);
+ }
ANDROID_API const Rect& getClipBounds();
@@ -314,6 +320,9 @@ public:
DrawOpMode drawOpMode = kDrawOpMode_Immediate);
virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
+ status_t drawShadow(const mat4& casterTransform, float casterAlpha,
+ float width, float height);
+
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
@@ -1069,8 +1078,8 @@ private:
// Dimensions of the drawing surface
int mWidth, mHeight;
- // Matrix used for ortho projection in shaders
- mat4 mOrthoMatrix;
+ // Matrix used for view/projection in shaders
+ mat4 mViewProjMatrix;
/**
* Model-view matrix used to position/size objects
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index e0044e8..236658d 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -22,84 +22,11 @@
#include "Matrix.h"
#include "Rect.h"
#include "Vertex.h"
+#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
-class VertexBuffer {
-public:
- VertexBuffer():
- mBuffer(0),
- mVertexCount(0),
- mCleanupMethod(NULL)
- {}
-
- ~VertexBuffer() {
- if (mCleanupMethod) mCleanupMethod(mBuffer);
- }
-
- /**
- This should be the only method used by the PathTessellator. Subsequent calls to alloc will
- allocate space within the first allocation (useful if you want to eventually allocate
- multiple regions within a single VertexBuffer, such as with PathTessellator::tesselateLines()
- */
- template <class TYPE>
- TYPE* alloc(int vertexCount) {
- if (mVertexCount) {
- TYPE* reallocBuffer = (TYPE*)mReallocBuffer;
- // already have allocated the buffer, re-allocate space within
- if (mReallocBuffer != mBuffer) {
- // not first re-allocation, leave space for degenerate triangles to separate strips
- reallocBuffer += 2;
- }
- mReallocBuffer = reallocBuffer + vertexCount;
- return reallocBuffer;
- }
- mVertexCount = vertexCount;
- mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
- mCleanupMethod = &(cleanup<TYPE>);
-
- return (TYPE*)mBuffer;
- }
-
- template <class TYPE>
- void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) {
- int verticesToCopy = srcBuffer.getVertexCount();
-
- TYPE* dst = alloc<TYPE>(verticesToCopy);
- TYPE* src = (TYPE*)srcBuffer.getBuffer();
-
- for (int i = 0; i < verticesToCopy; i++) {
- TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset);
- }
- }
-
- void* getBuffer() const { return mBuffer; } // shouldn't be const, since not a const ptr?
- unsigned int getVertexCount() const { return mVertexCount; }
-
- template <class TYPE>
- void createDegenerateSeparators(int allocSize) {
- TYPE* end = (TYPE*)mBuffer + mVertexCount;
- for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) {
- memcpy(degen, degen - 1, sizeof(TYPE));
- memcpy(degen + 1, degen + 2, sizeof(TYPE));
- }
- }
-
-private:
- template <class TYPE>
- static void cleanup(void* buffer) {
- delete[] (TYPE*)buffer;
- }
-
- void* mBuffer;
- unsigned int mVertexCount;
-
- void* mReallocBuffer; // used for multi-allocation
-
- void (*mCleanupMethod)(void*);
-};
-
class PathTessellator {
public:
static void expandBoundsForStroke(SkRect& bounds, const SkPaint* paint);
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
new file mode 100644
index 0000000..49a3d2c
--- /dev/null
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <math.h>
+#include <utils/Log.h>
+
+#include "AmbientShadow.h"
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+// TODO: Support path as the input of the polygon instead of the rect's width
+// and height.
+void ShadowTessellator::tessellateAmbientShadow(float width, float height,
+ const mat4& casterTransform, VertexBuffer& shadowVertexBuffer) {
+
+ Vector3 pivot(width / 2, height / 2, 0.0f);
+ casterTransform.mapPoint3d(pivot);
+
+ // TODO: The zScaleFactor need to be mapped to the screen.
+ float zScaleFactor = 0.5;
+ Rect blockRect(pivot.x - width * zScaleFactor, pivot.y - height * zScaleFactor,
+ pivot.x + width * zScaleFactor, pivot.y + height * zScaleFactor);
+
+ // Generate the caster's polygon from the rect.
+ // TODO: support arbitrary polygon, and the z value need to be computed
+ // according to the transformation for each vertex.
+ const int vertexCount = 4;
+ Vector3 polygon[vertexCount];
+ polygon[0].x = blockRect.left;
+ polygon[0].y = blockRect.top;
+ polygon[0].z = pivot.z;
+ polygon[1].x = blockRect.right;
+ polygon[1].y = blockRect.top;
+ polygon[1].z = pivot.z;
+ polygon[2].x = blockRect.right;
+ polygon[2].y = blockRect.bottom;
+ polygon[2].z = pivot.z;
+ polygon[3].x = blockRect.left;
+ polygon[3].y = blockRect.bottom;
+ polygon[3].z = pivot.z;
+
+ // A bunch of parameters to tweak the shadow.
+ // TODO: Allow some of these changable by debug settings or APIs.
+ const int rays = 120;
+ const int layers = 2;
+ const float strength = 0.5;
+ const float heightFactor = 120;
+ const float geomFactor = 60;
+
+ AmbientShadow::createAmbientShadow(polygon, vertexCount, rays, layers, strength,
+ heightFactor, geomFactor, shadowVertexBuffer);
+
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
new file mode 100644
index 0000000..05cb00c
--- /dev/null
+++ b/libs/hwui/ShadowTessellator.h
@@ -0,0 +1,37 @@
+
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_SHADOW_TESSELLATOR_H
+#define ANDROID_HWUI_SHADOW_TESSELLATOR_H
+
+#include "Debug.h"
+#include "Matrix.h"
+
+namespace android {
+namespace uirenderer {
+
+class ShadowTessellator {
+public:
+ static void tessellateAmbientShadow(float width, float height,
+ const mat4& casterTransform, VertexBuffer& shadowVertexBuffer);
+
+}; // ShadowTessellator
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_SHADOW_TESSELLATOR_H
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index 497924e..5110272 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -107,6 +107,21 @@ struct Vector2 {
}
}; // class Vector2
+class Vector3 {
+public:
+ float x;
+ float y;
+ float z;
+
+ Vector3() :
+ x(0.0f), y(0.0f), z(0.0f) {
+ }
+
+ Vector3(float px, float py, float pz) :
+ x(px), y(py), z(pz) {
+ }
+};
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
new file mode 100644
index 0000000..8b6872e
--- /dev/null
+++ b/libs/hwui/VertexBuffer.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 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_HWUI_VERTEX_BUFFER_H
+#define ANDROID_HWUI_VERTEX_BUFFER_H
+
+
+namespace android {
+namespace uirenderer {
+
+class VertexBuffer {
+public:
+ VertexBuffer():
+ mBuffer(0),
+ mVertexCount(0),
+ mCleanupMethod(NULL)
+ {}
+
+ ~VertexBuffer() {
+ if (mCleanupMethod) mCleanupMethod(mBuffer);
+ }
+
+ /**
+ This should be the only method used by the Tessellator. Subsequent calls to
+ alloc will allocate space within the first allocation (useful if you want to
+ eventually allocate multiple regions within a single VertexBuffer, such as
+ with PathTessellator::tesselateLines())
+ */
+ template <class TYPE>
+ TYPE* alloc(int vertexCount) {
+ if (mVertexCount) {
+ TYPE* reallocBuffer = (TYPE*)mReallocBuffer;
+ // already have allocated the buffer, re-allocate space within
+ if (mReallocBuffer != mBuffer) {
+ // not first re-allocation, leave space for degenerate triangles to separate strips
+ reallocBuffer += 2;
+ }
+ mReallocBuffer = reallocBuffer + vertexCount;
+ return reallocBuffer;
+ }
+ mVertexCount = vertexCount;
+ mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
+ mCleanupMethod = &(cleanup<TYPE>);
+
+ return (TYPE*)mBuffer;
+ }
+
+ template <class TYPE>
+ void copyInto(const VertexBuffer& srcBuffer, float xOffset, float yOffset) {
+ int verticesToCopy = srcBuffer.getVertexCount();
+
+ TYPE* dst = alloc<TYPE>(verticesToCopy);
+ TYPE* src = (TYPE*)srcBuffer.getBuffer();
+
+ for (int i = 0; i < verticesToCopy; i++) {
+ TYPE::copyWithOffset(&dst[i], src[i], xOffset, yOffset);
+ }
+ }
+
+ const void* getBuffer() const { return mBuffer; }
+ unsigned int getVertexCount() const { return mVertexCount; }
+
+ template <class TYPE>
+ void createDegenerateSeparators(int allocSize) {
+ TYPE* end = (TYPE*)mBuffer + mVertexCount;
+ for (TYPE* degen = (TYPE*)mBuffer + allocSize; degen < end; degen += 2 + allocSize) {
+ memcpy(degen, degen - 1, sizeof(TYPE));
+ memcpy(degen + 1, degen + 2, sizeof(TYPE));
+ }
+ }
+
+private:
+ template <class TYPE>
+ static void cleanup(void* buffer) {
+ delete[] (TYPE*)buffer;
+ }
+
+ void* mBuffer;
+ unsigned int mVertexCount;
+
+ void* mReallocBuffer; // used for multi-allocation
+
+ void (*mCleanupMethod)(void*);
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_VERTEX_BUFFER_H
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index de20227..a4d491d8 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -16,8 +16,6 @@
package android.media;
-import com.android.internal.util.Objects;
-
import android.Manifest;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
@@ -43,6 +41,7 @@ import android.view.Display;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -493,11 +492,11 @@ public class MediaRouter {
boolean volumeChanged = false;
boolean presentationDisplayChanged = false;
- if (!Objects.equal(route.mName, globalRoute.name)) {
+ if (!Objects.equals(route.mName, globalRoute.name)) {
route.mName = globalRoute.name;
changed = true;
}
- if (!Objects.equal(route.mDescription, globalRoute.description)) {
+ if (!Objects.equals(route.mDescription, globalRoute.description)) {
route.mDescription = globalRoute.description;
changed = true;
}
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index b09c5bd..58d3520 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -1525,6 +1525,8 @@ class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.Rendering
if (DEBUG) {
setBackgroundColor(DEBUG_REGION_BACKGROUND);
+ } else {
+ setBackgroundColor(captionStyle.windowColor);
}
}
@@ -1537,6 +1539,8 @@ class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.Rendering
final CueLayout cueBox = mRegionCueBoxes.get(i);
cueBox.setCaptionStyle(captionStyle, fontSize);
}
+
+ setBackgroundColor(captionStyle.windowColor);
}
/**
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
index c2461e6..dc9dd79 100644
--- a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
@@ -16,11 +16,11 @@
package com.android.media.remotedisplay;
-import com.android.internal.util.Objects;
-
import android.media.RemoteDisplayState.RemoteDisplayInfo;
import android.text.TextUtils;
+import java.util.Objects;
+
/**
* Represents a remote display that has been discovered.
*/
@@ -86,7 +86,7 @@ public class RemoteDisplay {
}
public void setName(String name) {
- if (!Objects.equal(mMutableInfo.name, name)) {
+ if (!Objects.equals(mMutableInfo.name, name)) {
mMutableInfo.name = name;
mImmutableInfo = null;
}
@@ -97,7 +97,7 @@ public class RemoteDisplay {
}
public void setDescription(String description) {
- if (!Objects.equal(mMutableInfo.description, description)) {
+ if (!Objects.equals(mMutableInfo.description, description)) {
mMutableInfo.description = description;
mImmutableInfo = null;
}
diff --git a/opengl/java/android/opengl/EGLLogWrapper.java b/opengl/java/android/opengl/EGLLogWrapper.java
index 36e88a2..c677957 100644
--- a/opengl/java/android/opengl/EGLLogWrapper.java
+++ b/opengl/java/android/opengl/EGLLogWrapper.java
@@ -326,7 +326,7 @@ class EGLLogWrapper implements EGL11 {
}
public boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface) {
- begin("eglInitialize");
+ begin("eglSwapBuffers");
arg("display", display);
arg("surface", surface);
end();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index f6b43c7..f1dca1d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -40,7 +40,6 @@ import com.android.documentsui.DocumentsActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Objects;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import com.google.common.collect.ArrayListMultimap;
@@ -51,6 +50,7 @@ import libcore.io.IoUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -295,7 +295,7 @@ public class RootsCache {
private RootInfo getRootLocked(String authority, String rootId) {
for (RootInfo root : mRoots.get(authority)) {
- if (Objects.equal(root.rootId, rootId)) {
+ if (Objects.equals(root.rootId, rootId)) {
return root;
}
}
@@ -308,7 +308,7 @@ public class RootsCache {
synchronized (mLock) {
final int rootIcon = root.derivedIcon != 0 ? root.derivedIcon : root.icon;
for (RootInfo test : mRoots.get(root.authority)) {
- if (Objects.equal(test.rootId, root.rootId)) {
+ if (Objects.equals(test.rootId, root.rootId)) {
continue;
}
final int testIcon = test.derivedIcon != 0 ? test.derivedIcon : test.icon;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 931dac9..923c79c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -46,13 +46,13 @@ import android.widget.TextView;
import com.android.documentsui.DocumentsActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Objects;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
/**
* Display list of known storage backend roots.
@@ -157,7 +157,7 @@ public class RootsFragment extends Fragment {
final Object item = mAdapter.getItem(i);
if (item instanceof RootItem) {
final RootInfo testRoot = ((RootItem) item).root;
- if (Objects.equal(testRoot, root)) {
+ if (Objects.equals(testRoot, root)) {
mList.setItemChecked(i, true);
return;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 1bae9b8..dfcd8a8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.nfc.NfcUnlock;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState;
@@ -50,6 +51,7 @@ import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
+
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -296,6 +298,11 @@ public class KeyguardHostView extends KeyguardViewBase {
}
}
}
+ @Override
+ public void onNfcUnlock() {
+ if (NfcUnlock.getPropertyEnabled()) mCallback.dismiss(true);
+ }
+
};
private static final boolean isMusicPlaying(int playbackState) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a849316..3b712e9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -36,6 +36,7 @@ import static android.os.BatteryManager.EXTRA_LEVEL;
import static android.os.BatteryManager.EXTRA_HEALTH;
import android.media.AudioManager;
import android.media.IRemoteControlDisplay;
+import android.nfc.NfcUnlock;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
@@ -94,6 +95,7 @@ public class KeyguardUpdateMonitor {
protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
private static final int MSG_SCREEN_TURNED_ON = 319;
private static final int MSG_SCREEN_TURNED_OFF = 320;
+ private static final int MSG_NFC_UNLOCK = 321;
private static KeyguardUpdateMonitor sInstance;
@@ -194,6 +196,9 @@ public class KeyguardUpdateMonitor {
case MSG_SCREEN_TURNED_ON:
handleScreenTurnedOn();
break;
+ case MSG_NFC_UNLOCK:
+ handleNfcUnlock();
+ break;
}
}
};
@@ -311,6 +316,15 @@ public class KeyguardUpdateMonitor {
}
};
+ private final BroadcastReceiver mNfcUnlockReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (NfcUnlock.ACTION_NFC_UNLOCK.equals(intent.getAction())) {
+ mHandler.sendEmptyMessage(MSG_NFC_UNLOCK);
+ }
+ }
+ }
+ ;
/**
* When we receive a
* {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
@@ -495,6 +509,15 @@ public class KeyguardUpdateMonitor {
}
}
+ private void handleNfcUnlock() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onNfcUnlock();
+ }
+ }
+ }
+
private KeyguardUpdateMonitor(Context context) {
mContext = context;
@@ -524,6 +547,11 @@ public class KeyguardUpdateMonitor {
filter.addAction(Intent.ACTION_USER_REMOVED);
context.registerReceiver(mBroadcastReceiver, filter);
+ final IntentFilter nfcUnlockIntentFilter = new IntentFilter();
+ nfcUnlockIntentFilter.addAction(NfcUnlock.ACTION_NFC_UNLOCK);
+ context.registerReceiver(mNfcUnlockReceiver, nfcUnlockIntentFilter,
+ NfcUnlock.NFC_UNLOCK_PERMISSION, null /* run on default scheduler */);
+
final IntentFilter bootCompleteFilter = new IntentFilter();
bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index c08880d..481d132 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -20,6 +20,7 @@ import android.app.admin.DevicePolicyManager;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.SystemClock;
+import android.util.Log;
import android.view.WindowManagerPolicy;
import com.android.internal.telephony.IccCardConstants;
@@ -172,4 +173,9 @@ class KeyguardUpdateMonitorCallback {
* {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
*/
public void onScreenTurnedOff(int why) { }
+
+ /**
+ * Called when the NFC Service has found a tag that is registered for NFC unlock.
+ */
+ public void onNfcUnlock() { }
}
diff --git a/preloaded-classes b/preloaded-classes
index 960c8ac..342126d 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1428,7 +1428,6 @@ com.android.internal.util.AsyncChannel
com.android.internal.util.AsyncChannel$DeathMonitor
com.android.internal.util.FastXmlSerializer
com.android.internal.util.MemInfoReader
-com.android.internal.util.Objects
com.android.internal.util.Preconditions
com.android.internal.util.XmlUtils
com.android.internal.view.ActionBarPolicy
@@ -2299,6 +2298,7 @@ javax.crypto.CipherSpi
javax.crypto.KeyAgreementSpi
javax.crypto.MacSpi
javax.crypto.SecretKey
+javax.crypto.spec.GCMParameterSpec
javax.crypto.spec.IvParameterSpec
javax.crypto.spec.SecretKeySpec
javax.microedition.khronos.egl.EGL
diff --git a/services/java/Android.mk b/services/java/Android.mk
index 8c3d0f0..9651239 100644
--- a/services/java/Android.mk
+++ b/services/java/Android.mk
@@ -1,18 +1,18 @@
LOCAL_PATH:= $(call my-dir)
-# the library
+# Build services.jar
# ============================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
- com/android/server/EventLogTags.logtags \
- com/android/server/am/EventLogTags.logtags
-
LOCAL_MODULE:= services
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files) \
+ com/android/server/EventLogTags.logtags \
+ com/android/server/am/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
include $(BUILD_JAVA_LIBRARY)
-
include $(BUILD_DROIDDOC)
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 5ae9a6d..1fb164d 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -31,6 +31,7 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -64,54 +65,51 @@ import static android.app.AlarmManager.ELAPSED_REALTIME;
import com.android.internal.util.LocalLog;
-class AlarmManagerService extends IAlarmManager.Stub {
+class AlarmManagerService extends SystemService {
// The threshold for how long an alarm can be late before we print a
// warning message. The time duration is in milliseconds.
private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
private static final int RTC_MASK = 1 << RTC;
- private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
+ private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
- private static final int TIME_CHANGED_MASK = 1 << 16;
- private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
+ static final int TIME_CHANGED_MASK = 1 << 16;
+ static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
// Mask for testing whether a given alarm type is wakeup vs non-wakeup
- private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
-
- private static final String TAG = "AlarmManager";
- private static final String ClockReceiver_TAG = "ClockReceiver";
- private static final boolean localLOGV = false;
- private static final boolean DEBUG_BATCH = localLOGV || false;
- private static final boolean DEBUG_VALIDATE = localLOGV || false;
- private static final int ALARM_EVENT = 1;
- private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+ static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
+
+ static final String TAG = "AlarmManager";
+ static final String ClockReceiver_TAG = "ClockReceiver";
+ static final boolean localLOGV = false;
+ static final boolean DEBUG_BATCH = localLOGV || false;
+ static final boolean DEBUG_VALIDATE = localLOGV || false;
+ static final int ALARM_EVENT = 1;
+ static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
- private static final Intent mBackgroundIntent
+ static final Intent mBackgroundIntent
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
- private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
+ static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
- private static final boolean WAKEUP_STATS = false;
+ static final boolean WAKEUP_STATS = false;
- private final Context mContext;
+ final LocalLog mLog = new LocalLog(TAG);
- private final LocalLog mLog = new LocalLog(TAG);
+ final Object mLock = new Object();
- private Object mLock = new Object();
-
- private int mDescriptor;
+ int mDescriptor;
private long mNextWakeup;
private long mNextNonWakeup;
- private int mBroadcastRefCount = 0;
- private PowerManager.WakeLock mWakeLock;
- private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
- private final AlarmThread mWaitThread = new AlarmThread();
- private final AlarmHandler mHandler = new AlarmHandler();
- private ClockReceiver mClockReceiver;
+ int mBroadcastRefCount = 0;
+ PowerManager.WakeLock mWakeLock;
+ ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
+ final AlarmHandler mHandler = new AlarmHandler();
+ ClockReceiver mClockReceiver;
private UninstallReceiver mUninstallReceiver;
- private final ResultReceiver mResultReceiver = new ResultReceiver();
- private final PendingIntent mTimeTickSender;
- private final PendingIntent mDateChangeSender;
+ final ResultReceiver mResultReceiver = new ResultReceiver();
+ PendingIntent mTimeTickSender;
+ PendingIntent mDateChangeSender;
class WakeupEvent {
public long when;
@@ -125,8 +123,8 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
- private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
- private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
+ final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
+ final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
static final class Batch {
long start; // These endpoints are always in ELAPSED
@@ -317,9 +315,9 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
// minimum recurrence period or alarm futurity for us to be able to fuzz it
- private static final long MIN_FUZZABLE_INTERVAL = 10000;
- private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
- private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+ static final long MIN_FUZZABLE_INTERVAL = 10000;
+ static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
+ final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
static long convertToElapsed(long when, int type) {
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
@@ -403,7 +401,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
- private static final class InFlight extends Intent {
+ static final class InFlight extends Intent {
final PendingIntent mPendingIntent;
final WorkSource mWorkSource;
final Pair<String, ComponentName> mTarget;
@@ -427,7 +425,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
- private static final class FilterStats {
+ static final class FilterStats {
final BroadcastStats mBroadcastStats;
final Pair<String, ComponentName> mTarget;
@@ -443,7 +441,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
- private static final class BroadcastStats {
+ static final class BroadcastStats {
final String mPackageName;
long aggregateTime;
@@ -459,47 +457,48 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
- private final HashMap<String, BroadcastStats> mBroadcastStats
+ final HashMap<String, BroadcastStats> mBroadcastStats
= new HashMap<String, BroadcastStats>();
- public AlarmManagerService(Context context) {
- mContext = context;
+ @Override
+ public void onStart() {
mDescriptor = init();
mNextWakeup = mNextNonWakeup = 0;
// We have to set current TimeZone info to kernel
// because kernel doesn't keep this after reboot
- String tz = SystemProperties.get(TIMEZONE_PROPERTY);
- if (tz != null) {
- setTimeZone(tz);
- }
+ setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
+ mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND), 0,
UserHandle.ALL);
Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
+ mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
// now that we have initied the driver schedule the alarm
- mClockReceiver= new ClockReceiver();
+ mClockReceiver = new ClockReceiver();
mClockReceiver.scheduleTimeTickEvent();
mClockReceiver.scheduleDateChangedEvent();
mUninstallReceiver = new UninstallReceiver();
if (mDescriptor != -1) {
- mWaitThread.start();
+ AlarmThread waitThread = new AlarmThread();
+ waitThread.start();
} else {
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
+
+ publishBinderService(Context.ALARM_SERVICE, mService);
}
-
+
+ @Override
protected void finalize() throws Throwable {
try {
close(mDescriptor);
@@ -508,19 +507,51 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
- @Override
- public void set(int type, long triggerAtTime, long windowLength, long interval,
- PendingIntent operation, WorkSource workSource) {
- if (workSource != null) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.UPDATE_DEVICE_STATS,
- "AlarmManager.set");
+ void setTimeZoneImpl(String tz) {
+ if (TextUtils.isEmpty(tz)) {
+ return;
+ }
+
+ TimeZone zone = TimeZone.getTimeZone(tz);
+ // Prevent reentrant calls from stepping on each other when writing
+ // the time zone property
+ boolean timeZoneWasChanged = false;
+ synchronized (this) {
+ String current = SystemProperties.get(TIMEZONE_PROPERTY);
+ if (current == null || !current.equals(zone.getID())) {
+ if (localLOGV) {
+ Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
+ }
+ timeZoneWasChanged = true;
+ SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
+ }
+
+ // Update the kernel timezone information
+ // Kernel tracks time offsets as 'minutes west of GMT'
+ int gmtOffset = zone.getOffset(System.currentTimeMillis());
+ setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
}
- set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
+ TimeZone.setDefault(null);
+
+ if (timeZoneWasChanged) {
+ Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra("time-zone", zone.getID());
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
}
- public void set(int type, long triggerAtTime, long windowLength, long interval,
+ void removeImpl(PendingIntent operation) {
+ if (operation == null) {
+ return;
+ }
+ synchronized (mLock) {
+ removeLocked(operation);
+ }
+ }
+
+ void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, boolean isStandalone, WorkSource workSource) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
@@ -606,231 +637,64 @@ class AlarmManagerService extends IAlarmManager.Stub {
rescheduleKernelAlarmsLocked();
}
- private void logBatchesLocked() {
- ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
- PrintWriter pw = new PrintWriter(bs);
- final long nowRTC = System.currentTimeMillis();
- final long nowELAPSED = SystemClock.elapsedRealtime();
- final int NZ = mAlarmBatches.size();
- for (int iz = 0; iz < NZ; iz++) {
- Batch bz = mAlarmBatches.get(iz);
- pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
- dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC);
- pw.flush();
- Slog.v(TAG, bs.toString());
- bs.reset();
- }
- }
-
- private boolean validateConsistencyLocked() {
- if (DEBUG_VALIDATE) {
- long lastTime = Long.MIN_VALUE;
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.start >= lastTime) {
- // duplicate start times are okay because of standalone batches
- lastTime = b.start;
- } else {
- Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
- logBatchesLocked();
- return false;
- }
- }
- }
- return true;
- }
-
- private Batch findFirstWakeupBatchLocked() {
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasWakeups()) {
- return b;
+ private final IBinder mService = new IAlarmManager.Stub() {
+ @Override
+ public void set(int type, long triggerAtTime, long windowLength, long interval,
+ PendingIntent operation, WorkSource workSource) {
+ if (workSource != null) {
+ getContext().enforceCallingPermission(
+ android.Manifest.permission.UPDATE_DEVICE_STATS,
+ "AlarmManager.set");
}
- }
- return null;
- }
- private void rescheduleKernelAlarmsLocked() {
- // Schedule the next upcoming wakeup alarm. If there is a deliverable batch
- // prior to that which contains no wakeups, we schedule that as well.
- if (mAlarmBatches.size() > 0) {
- final Batch firstWakeup = findFirstWakeupBatchLocked();
- final Batch firstBatch = mAlarmBatches.get(0);
- if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
- mNextWakeup = firstWakeup.start;
- setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
- }
- if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
- mNextNonWakeup = firstBatch.start;
- setLocked(ELAPSED_REALTIME, firstBatch.start);
- }
+ setImpl(type, triggerAtTime, windowLength, interval, operation,
+ false, workSource);
}
- }
-
- public void setTime(long millis) {
- mContext.enforceCallingOrSelfPermission(
- "android.permission.SET_TIME",
- "setTime");
-
- SystemClock.setCurrentTimeMillis(millis);
- }
-
- public void setTimeZone(String tz) {
- mContext.enforceCallingOrSelfPermission(
- "android.permission.SET_TIME_ZONE",
- "setTimeZone");
-
- long oldId = Binder.clearCallingIdentity();
- try {
- if (TextUtils.isEmpty(tz)) return;
- TimeZone zone = TimeZone.getTimeZone(tz);
- // Prevent reentrant calls from stepping on each other when writing
- // the time zone property
- boolean timeZoneWasChanged = false;
- synchronized (this) {
- String current = SystemProperties.get(TIMEZONE_PROPERTY);
- if (current == null || !current.equals(zone.getID())) {
- if (localLOGV) {
- Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
- }
- timeZoneWasChanged = true;
- SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
- }
-
- // Update the kernel timezone information
- // Kernel tracks time offsets as 'minutes west of GMT'
- int gmtOffset = zone.getOffset(System.currentTimeMillis());
- setKernelTimezone(mDescriptor, -(gmtOffset / 60000));
- }
-
- TimeZone.setDefault(null);
- if (timeZoneWasChanged) {
- Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra("time-zone", zone.getID());
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
-
- public void remove(PendingIntent operation) {
- if (operation == null) {
- return;
- }
- synchronized (mLock) {
- removeLocked(operation);
- }
- }
-
- public void removeLocked(PendingIntent operation) {
- boolean didRemove = false;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(operation);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
- }
+ @Override
+ public void setTime(long millis) {
+ getContext().enforceCallingOrSelfPermission(
+ "android.permission.SET_TIME",
+ "setTime");
- if (didRemove) {
- if (DEBUG_BATCH) {
- Slog.v(TAG, "remove(operation) changed bounds; rebatching");
- }
- rebatchAllAlarmsLocked(true);
- rescheduleKernelAlarmsLocked();
+ SystemClock.setCurrentTimeMillis(millis);
}
- }
- public void removeLocked(String packageName) {
- boolean didRemove = false;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(packageName);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
+ @Override
+ public void setTimeZone(String tz) {
+ getContext().enforceCallingOrSelfPermission(
+ "android.permission.SET_TIME_ZONE",
+ "setTimeZone");
+
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ setTimeZoneImpl(tz);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
}
- if (didRemove) {
- if (DEBUG_BATCH) {
- Slog.v(TAG, "remove(package) changed bounds; rebatching");
- }
- rebatchAllAlarmsLocked(true);
- rescheduleKernelAlarmsLocked();
- }
- }
+ @Override
+ public void remove(PendingIntent operation) {
+ removeImpl(operation);
- public void removeUserLocked(int userHandle) {
- boolean didRemove = false;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(userHandle);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
}
- if (didRemove) {
- if (DEBUG_BATCH) {
- Slog.v(TAG, "remove(user) changed bounds; rebatching");
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump AlarmManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
}
- rebatchAllAlarmsLocked(true);
- rescheduleKernelAlarmsLocked();
- }
- }
- public boolean lookForPackageLocked(String packageName) {
- for (int i = 0; i < mAlarmBatches.size(); i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasPackage(packageName)) {
- return true;
- }
+ dumpImpl(pw);
}
- return false;
- }
+ };
- private void setLocked(int type, long when)
- {
- if (mDescriptor != -1)
- {
- // The kernel never triggers alarms with negative wakeup times
- // so we ensure they are positive.
- long alarmSeconds, alarmNanoseconds;
- if (when < 0) {
- alarmSeconds = 0;
- alarmNanoseconds = 0;
- } else {
- alarmSeconds = when / 1000;
- alarmNanoseconds = (when % 1000) * 1000 * 1000;
- }
-
- set(mDescriptor, type, alarmSeconds, alarmNanoseconds);
- }
- else
- {
- Message msg = Message.obtain();
- msg.what = ALARM_EVENT;
-
- mHandler.removeMessages(ALARM_EVENT);
- mHandler.sendMessageAtTime(msg, when);
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump AlarmManager from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
+ void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
final long nowRTC = System.currentTimeMillis();
@@ -980,6 +844,159 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
+ private void logBatchesLocked() {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+ PrintWriter pw = new PrintWriter(bs);
+ final long nowRTC = System.currentTimeMillis();
+ final long nowELAPSED = SystemClock.elapsedRealtime();
+ final int NZ = mAlarmBatches.size();
+ for (int iz = 0; iz < NZ; iz++) {
+ Batch bz = mAlarmBatches.get(iz);
+ pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
+ dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC);
+ pw.flush();
+ Slog.v(TAG, bs.toString());
+ bs.reset();
+ }
+ }
+
+ private boolean validateConsistencyLocked() {
+ if (DEBUG_VALIDATE) {
+ long lastTime = Long.MIN_VALUE;
+ final int N = mAlarmBatches.size();
+ for (int i = 0; i < N; i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.start >= lastTime) {
+ // duplicate start times are okay because of standalone batches
+ lastTime = b.start;
+ } else {
+ Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
+ logBatchesLocked();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private Batch findFirstWakeupBatchLocked() {
+ final int N = mAlarmBatches.size();
+ for (int i = 0; i < N; i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.hasWakeups()) {
+ return b;
+ }
+ }
+ return null;
+ }
+
+ void rescheduleKernelAlarmsLocked() {
+ // Schedule the next upcoming wakeup alarm. If there is a deliverable batch
+ // prior to that which contains no wakeups, we schedule that as well.
+ if (mAlarmBatches.size() > 0) {
+ final Batch firstWakeup = findFirstWakeupBatchLocked();
+ final Batch firstBatch = mAlarmBatches.get(0);
+ if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+ mNextWakeup = firstWakeup.start;
+ setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+ }
+ if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
+ mNextNonWakeup = firstBatch.start;
+ setLocked(ELAPSED_REALTIME, firstBatch.start);
+ }
+ }
+ }
+
+ private void removeLocked(PendingIntent operation) {
+ boolean didRemove = false;
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(operation);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(operation) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ }
+ }
+
+ void removeLocked(String packageName) {
+ boolean didRemove = false;
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(packageName);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(package) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ }
+ }
+
+ void removeUserLocked(int userHandle) {
+ boolean didRemove = false;
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(userHandle);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(user) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ }
+ }
+
+ boolean lookForPackageLocked(String packageName) {
+ for (int i = 0; i < mAlarmBatches.size(); i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.hasPackage(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void setLocked(int type, long when) {
+ if (mDescriptor != -1) {
+ // The kernel never triggers alarms with negative wakeup times
+ // so we ensure they are positive.
+ long alarmSeconds, alarmNanoseconds;
+ if (when < 0) {
+ alarmSeconds = 0;
+ alarmNanoseconds = 0;
+ } else {
+ alarmSeconds = when / 1000;
+ alarmNanoseconds = (when % 1000) * 1000 * 1000;
+ }
+
+ set(mDescriptor, type, alarmSeconds, alarmNanoseconds);
+ } else {
+ Message msg = Message.obtain();
+ msg.what = ALARM_EVENT;
+
+ mHandler.removeMessages(ALARM_EVENT);
+ mHandler.sendMessageAtTime(msg, when);
+ }
+ }
+
private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
String prefix, String label, long now) {
for (int i=list.size()-1; i>=0; i--) {
@@ -1020,7 +1037,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
private native int waitForAlarm(int fd);
private native int setKernelTimezone(int fd, int minuteswest);
- private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+ void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
// batches are temporally sorted, so we need only pull from the
// start of the list until we either empty it or hit a batch
// that is not yet deliverable
@@ -1166,13 +1183,13 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (DEBUG_BATCH) {
Slog.v(TAG, "Time changed notification from kernel; rebatching");
}
- remove(mTimeTickSender);
+ removeImpl(mTimeTickSender);
rebatchAllAlarms();
mClockReceiver.scheduleTimeTickEvent();
Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
}
synchronized (mLock) {
@@ -1206,7 +1223,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
Alarm alarm = triggerList.get(i);
try {
if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
- alarm.operation.send(mContext, 0,
+ alarm.operation.send(getContext(), 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
@@ -1248,7 +1265,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
// is a repeating alarm, so toss the hoser.
- remove(alarm.operation);
+ removeImpl(alarm.operation);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Failure sending alarm.", e);
@@ -1310,7 +1327,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
// is a repeating alarm, so toss the hoser.
- remove(alarm.operation);
+ removeImpl(alarm.operation);
}
}
}
@@ -1323,7 +1340,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_DATE_CHANGED);
- mContext.registerReceiver(this, filter);
+ getContext().registerReceiver(this, filter);
}
@Override
@@ -1354,7 +1371,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
final long tickEventDelay = nextTime - currentTime;
final WorkSource workSource = null; // Let system take blame for time tick events.
- set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+ setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
0, mTimeTickSender, true, workSource);
}
@@ -1368,7 +1385,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
calendar.add(Calendar.DAY_OF_MONTH, 1);
final WorkSource workSource = null; // Let system take blame for date change events.
- set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
+ setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
}
}
@@ -1379,12 +1396,12 @@ class AlarmManagerService extends IAlarmManager.Stub {
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
- mContext.registerReceiver(this, filter);
+ getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
- mContext.registerReceiver(this, sdFilter);
+ getContext().registerReceiver(this, sdFilter);
}
@Override
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index b234a4e..6e72e24 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -19,6 +19,8 @@ package com.android.server;
import android.os.BatteryStats;
import com.android.internal.app.IBatteryStats;
import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
import android.app.ActivityManagerNative;
import android.content.ContentResolver;
@@ -134,13 +136,10 @@ public final class BatteryService extends Binder {
private boolean mSentLowBatteryBroadcast = false;
- private BatteryListener mBatteryPropertiesListener;
- private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
-
- public BatteryService(Context context, LightsService lights) {
+ public BatteryService(Context context, LightsManager lightsManager) {
mContext = context;
mHandler = new Handler(true /*async*/);
- mLed = new Led(context, lights);
+ mLed = new Led(context, lightsManager);
mBatteryStats = BatteryStatsService.getService();
mCriticalBatteryLevel = mContext.getResources().getInteger(
@@ -158,13 +157,11 @@ public final class BatteryService extends Binder {
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
- mBatteryPropertiesListener = new BatteryListener();
-
IBinder b = ServiceManager.getService("batteryproperties");
- mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
+ final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
+ IBatteryPropertiesRegistrar.Stub.asInterface(b);
try {
- mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
+ batteryPropertiesRegistrar.registerListener(new BatteryListener());
} catch (RemoteException e) {
// Should never happen.
}
@@ -677,7 +674,7 @@ public final class BatteryService extends Binder {
};
private final class Led {
- private final LightsService.Light mBatteryLight;
+ private final Light mBatteryLight;
private final int mBatteryLowARGB;
private final int mBatteryMediumARGB;
@@ -685,8 +682,8 @@ public final class BatteryService extends Binder {
private final int mBatteryLedOn;
private final int mBatteryLedOff;
- public Led(Context context, LightsService lights) {
- mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
+ public Led(Context context, LightsManager lights) {
+ mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
mBatteryLowARGB = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLowARGB);
@@ -712,7 +709,7 @@ public final class BatteryService extends Binder {
mBatteryLight.setColor(mBatteryLowARGB);
} else {
// Flash red when battery is low and not charging
- mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
+ mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
}
} else if (status == BatteryManager.BATTERY_STATUS_CHARGING
@@ -732,8 +729,14 @@ public final class BatteryService extends Binder {
}
private final class BatteryListener extends IBatteryPropertiesListener.Stub {
+ @Override
public void batteryPropertiesChanged(BatteryProperties props) {
- BatteryService.this.update(props);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ BatteryService.this.update(props);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
}
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index da1b254..bce85ce 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -120,6 +120,8 @@ public class BootReceiver extends BroadcastReceiver {
// Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
-LOG_SIZE, "SYSTEM_LAST_KMSG");
+ addFileToDropBox(db, prefs, headers, "/sys/fs/pstore/console-ramoops",
+ -LOG_SIZE, "SYSTEM_LAST_KMSG");
addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
-LOG_SIZE, "SYSTEM_RECOVERY_LOG");
addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
@@ -184,6 +186,11 @@ public class BootReceiver extends BroadcastReceiver {
File file = new File("/proc/last_kmsg");
long fileTime = file.lastModified();
+ if (fileTime <= 0) {
+ file = new File("/sys/fs/pstore/console-ramoops");
+ fileTime = file.lastModified();
+ }
+
if (fileTime <= 0) return; // File does not exist
if (prefs != null) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index f061149..0b3eb12 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -30,7 +30,7 @@ import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.InputBindResult;
-import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/java/com/android/server/LocalServices.java b/services/java/com/android/server/LocalServices.java
new file mode 100644
index 0000000..deff79d
--- /dev/null
+++ b/services/java/com/android/server/LocalServices.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.util.ArrayMap;
+
+/**
+ * This class is used in a similar way as ServiceManager, except the services registered here
+ * are not Binder objects and are only available in the same process.
+ *
+ * Once all services are converted to the SystemService interface, this class can be absorbed
+ * into SystemServiceManager.
+ */
+public final class LocalServices {
+ private LocalServices() {}
+
+ private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
+ new ArrayMap<Class<?>, Object>();
+
+ /**
+ * Returns a local service instance that implements the specified interface.
+ *
+ * @param type The type of service.
+ * @return The service object.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getService(Class<T> type) {
+ synchronized (sLocalServiceObjects) {
+ return (T) sLocalServiceObjects.get(type);
+ }
+ }
+
+ /**
+ * Adds a service instance of the specified interface to the global registry of local services.
+ */
+ public static <T> void addService(Class<T> type, T service) {
+ synchronized (sLocalServiceObjects) {
+ if (sLocalServiceObjects.containsKey(type)) {
+ throw new IllegalStateException("Overriding service registration");
+ }
+ sLocalServiceObjects.put(type, service);
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3a1c747..38f4c78 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,8 @@
package com.android.server;
import android.app.ActivityManagerNative;
+import android.app.IAlarmManager;
+import android.app.INotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -26,7 +28,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.AudioService;
-import android.net.wifi.p2p.WifiP2pService;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -59,9 +60,12 @@ import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.input.InputManagerService;
+import com.android.server.lights.LightsManager;
+import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
+import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.Installer;
import com.android.server.pm.PackageManagerService;
@@ -70,9 +74,14 @@ import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.print.PrintManagerService;
import com.android.server.search.SearchManagerService;
+import com.android.server.statusbar.StatusBarManagerService;
+import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightService;
import com.android.server.usb.UsbService;
import com.android.server.wallpaper.WallpaperManagerService;
import com.android.server.wifi.WifiService;
+import com.android.server.wifi.p2p.WifiP2pService;
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
@@ -131,12 +140,12 @@ class ServerThread {
Installer installer = null;
AccountManagerService accountManager = null;
ContentService contentService = null;
- LightsService lights = null;
+ LightsManager lights = null;
PowerManagerService power = null;
DisplayManagerService display = null;
BatteryService battery = null;
VibratorService vibrator = null;
- AlarmManagerService alarm = null;
+ IAlarmManager alarm = null;
MountService mountService = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
@@ -152,8 +161,7 @@ class ServerThread {
DockObserver dock = null;
UsbService usb = null;
SerialService serial = null;
- TwilightService twilight = null;
- UiModeManagerService uiMode = null;
+ TwilightManager twilight = null;
RecognitionManagerService recognition = null;
NetworkTimeUpdateService networkTimeUpdater = null;
CommonTimeManagementService commonTimeMgmtService = null;
@@ -203,6 +211,8 @@ class ServerThread {
Slog.e("System", "************ Failure starting bootstrap service", e);
}
+ final SystemServiceManager systemServiceManager = new SystemServiceManager(context);
+
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -278,8 +288,8 @@ class ServerThread {
Slog.i(TAG, "System Content Providers");
ActivityManagerService.installSystemProviders();
- Slog.i(TAG, "Lights Service");
- lights = new LightsService(context);
+ systemServiceManager.startService(LightsService.class);
+ lights = LocalServices.getService(LightsManager.class);
Slog.i(TAG, "Battery Service");
battery = new BatteryService(context, lights);
@@ -295,17 +305,16 @@ class ServerThread {
// only initialize the power service after we have started the
// lights service, content providers and the battery service.
- power.init(context, lights, ActivityManagerService.self(), battery,
+ power.init(context, lights, battery,
BatteryStatsService.getService(),
ActivityManagerService.self().getAppOpsService(), display);
- Slog.i(TAG, "Alarm Manager");
- alarm = new AlarmManagerService(context);
- ServiceManager.addService(Context.ALARM_SERVICE, alarm);
+ systemServiceManager.startService(AlarmManagerService.class);
+ alarm = IAlarmManager.Stub.asInterface(
+ ServiceManager.getService(Context.ALARM_SERVICE));
Slog.i(TAG, "Init Watchdog");
- Watchdog.getInstance().init(context, battery, power, alarm,
- ActivityManagerService.self());
+ Watchdog.getInstance().init(context, ActivityManagerService.self());
Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");
Slog.i(TAG, "Input Manager");
@@ -350,9 +359,9 @@ class ServerThread {
DevicePolicyManagerService devicePolicy = null;
StatusBarManagerService statusBar = null;
+ INotificationManager notification = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
- NotificationManagerService notification = null;
WallpaperManagerService wallpaper = null;
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
@@ -401,7 +410,7 @@ class ServerThread {
ActivityManagerNative.getDefault().showBootMessage(
context.getResources().getText(
com.android.internal.R.string.android_upgrading_starting_apps),
- false);
+ false);
} catch (RemoteException e) {
}
@@ -571,22 +580,12 @@ class ServerThread {
reportWtf("making Content Service ready", e);
}
- try {
- Slog.i(TAG, "Notification Manager");
- notification = new NotificationManagerService(context, statusBar, lights);
- ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
- networkPolicy.bindNotificationManager(notification);
- } catch (Throwable e) {
- reportWtf("starting Notification Manager", e);
- }
+ systemServiceManager.startService(NotificationManagerService.class);
+ notification = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ networkPolicy.bindNotificationManager(notification);
- try {
- Slog.i(TAG, "Device Storage Monitor");
- ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
- new DeviceStorageMonitorService(context));
- } catch (Throwable e) {
- reportWtf("starting DeviceStorageMonitor service", e);
- }
+ systemServiceManager.startService(DeviceStorageMonitorService.class);
if (!disableLocation) {
try {
@@ -685,20 +684,10 @@ class ServerThread {
}
}
- try {
- Slog.i(TAG, "Twilight Service");
- twilight = new TwilightService(context);
- } catch (Throwable e) {
- reportWtf("starting TwilightService", e);
- }
+ systemServiceManager.startService(TwilightService.class);
+ twilight = LocalServices.getService(TwilightManager.class);
- try {
- Slog.i(TAG, "UI Mode Manager Service");
- // Listen for UI mode changes
- uiMode = new UiModeManagerService(context, twilight);
- } catch (Throwable e) {
- reportWtf("starting UiModeManagerService", e);
- }
+ systemServiceManager.startService(UiModeManagerService.class);
if (!disableNonCoreServices) {
try {
@@ -858,13 +847,7 @@ class ServerThread {
}
}
- if (notification != null) {
- try {
- notification.systemReady();
- } catch (Throwable e) {
- reportWtf("making Notification Service ready", e);
- }
- }
+ systemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
try {
wm.systemReady();
@@ -913,8 +896,6 @@ class ServerThread {
final ConnectivityService connectivityF = connectivity;
final DockObserver dockF = dock;
final UsbService usbF = usb;
- final TwilightService twilightF = twilight;
- final UiModeManagerService uiModeF = uiMode;
final AppWidgetService appWidgetF = appWidget;
final WallpaperManagerService wallpaperF = wallpaper;
final InputMethodManagerService immF = imm;
@@ -992,16 +973,6 @@ class ServerThread {
reportWtf("making USB Service ready", e);
}
try {
- if (twilightF != null) twilightF.systemReady();
- } catch (Throwable e) {
- reportWtf("makin Twilight Service ready", e);
- }
- try {
- if (uiModeF != null) uiModeF.systemReady();
- } catch (Throwable e) {
- reportWtf("making UI Mode Service ready", e);
- }
- try {
if (recognitionF != null) recognitionF.systemReady();
} catch (Throwable e) {
reportWtf("making Recognition Service ready", e);
@@ -1010,6 +981,7 @@ class ServerThread {
// It is now okay to let the various system services start their
// third party code...
+ systemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
try {
if (appWidgetF != null) appWidgetF.systemRunning(safeMode);
@@ -1086,6 +1058,8 @@ class ServerThread {
} catch (Throwable e) {
reportWtf("Notifying MediaRouterService running", e);
}
+
+ systemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
}
});
diff --git a/services/java/com/android/server/SystemService.java b/services/java/com/android/server/SystemService.java
new file mode 100644
index 0000000..37afb4f
--- /dev/null
+++ b/services/java/com/android/server/SystemService.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * System services respond to lifecycle events that help the services know what
+ */
+public abstract class SystemService {
+ /*
+ * Boot Phases
+ */
+ public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+ public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+ public static final int PHASE_BOOT_COMPLETE = 1000;
+
+ private SystemServiceManager mManager;
+ private Context mContext;
+
+ final void init(Context context, SystemServiceManager manager) {
+ mContext = context;
+ mManager = manager;
+ onCreate(context);
+ }
+
+ /**
+ * Services are not yet available. This is a good place to do setup work that does
+ * not require other services.
+ *
+ * @param context The system context.
+ */
+ public void onCreate(Context context) {}
+
+ /**
+ * Called when the dependencies listed in the @Service class-annotation are available
+ * and after the chosen start phase.
+ * When this method returns, the service should be published.
+ */
+ public abstract void onStart();
+
+ /**
+ * Called on each phase of the boot process. Phases before the service's start phase
+ * (as defined in the @Service annotation) are never received.
+ *
+ * @param phase The current boot phase.
+ */
+ public void onBootPhase(int phase) {}
+
+ /**
+ * Publish the service so it is accessible to other services and apps.
+ */
+ protected final void publishBinderService(String name, IBinder service) {
+ ServiceManager.addService(name, service);
+ }
+
+ /**
+ * Get a binder service by its name.
+ */
+ protected final IBinder getBinderService(String name) {
+ return ServiceManager.getService(name);
+ }
+
+ /**
+ * Publish the service so it is only accessible to the system process.
+ */
+ protected final <T> void publishLocalService(Class<T> type, T service) {
+ LocalServices.addService(type, service);
+ }
+
+ /**
+ * Get a local service by interface.
+ */
+ protected final <T> T getLocalService(Class<T> type) {
+ return LocalServices.getService(type);
+ }
+
+ public final Context getContext() {
+ return mContext;
+ }
+
+// /**
+// * Called when a new user has been created. If your service deals with multiple users, this
+// * method should be overridden.
+// *
+// * @param userHandle The user that was created.
+// */
+// public void onUserCreated(int userHandle) {
+// }
+//
+// /**
+// * Called when an existing user has started a new session. If your service deals with multiple
+// * users, this method should be overridden.
+// *
+// * @param userHandle The user who started a new session.
+// */
+// public void onUserStarted(int userHandle) {
+// }
+//
+// /**
+// * Called when a background user session has entered the foreground. If your service deals with
+// * multiple users, this method should be overridden.
+// *
+// * @param userHandle The user who's session entered the foreground.
+// */
+// public void onUserForeground(int userHandle) {
+// }
+//
+// /**
+// * Called when a foreground user session has entered the background. If your service deals with
+// * multiple users, this method should be overridden;
+// *
+// * @param userHandle The user who's session entered the background.
+// */
+// public void onUserBackground(int userHandle) {
+// }
+//
+// /**
+// * Called when a user's active session has stopped. If your service deals with multiple users,
+// * this method should be overridden.
+// *
+// * @param userHandle The user who's session has stopped.
+// */
+// public void onUserStopped(int userHandle) {
+// }
+//
+// /**
+// * Called when a user has been removed from the system. If your service deals with multiple
+// * users, this method should be overridden.
+// *
+// * @param userHandle The user who has been removed.
+// */
+// public void onUserRemoved(int userHandle) {
+// }
+}
diff --git a/services/java/com/android/server/SystemServiceManager.java b/services/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..648975a
--- /dev/null
+++ b/services/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of system services.
+ */
+public class SystemServiceManager {
+ private static final String TAG = "SystemServiceManager";
+
+ private final Context mContext;
+
+ // Services that should receive lifecycle events.
+ private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+ private int mCurrentPhase = -1;
+
+ public SystemServiceManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Creates and starts a system service. The class must be a subclass of
+ * {@link com.android.server.SystemService}.
+ *
+ * @param serviceClass A Java class that implements the SystemService interface.
+ * @throws RuntimeException if the service fails to start.
+ */
+ public void startService(Class<?> serviceClass) {
+ final SystemService serviceInstance = createInstance(serviceClass);
+ try {
+ Slog.i(TAG, "Creating " + serviceClass.getSimpleName());
+ serviceInstance.init(mContext, this);
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to create service " + serviceClass.getName(), e);
+ }
+
+ mServices.add(serviceInstance);
+
+ try {
+ Slog.i(TAG, "Starting " + serviceClass.getSimpleName());
+ serviceInstance.onStart();
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to start service " + serviceClass.getName(), e);
+ }
+ }
+
+ /**
+ * Starts the specified boot phase for all system services that have been started up to
+ * this point.
+ *
+ * @param phase The boot phase to start.
+ */
+ public void startBootPhase(final int phase) {
+ if (phase <= mCurrentPhase) {
+ throw new IllegalArgumentException("Next phase must be larger than previous");
+ }
+ mCurrentPhase = phase;
+
+ Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onBootPhase(mCurrentPhase);
+ } catch (Throwable e) {
+ reportWtf("Service " + service.getClass().getName() +
+ " threw an Exception processing boot phase " + mCurrentPhase, e);
+ }
+ }
+ }
+
+ /**
+ * Outputs the state of this manager to the System log.
+ */
+ public void dump() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+ builder.append("Services:\n");
+ final int startedLen = mServices.size();
+ for (int i = 0; i < startedLen; i++) {
+ final SystemService service = mServices.get(i);
+ builder.append("\t")
+ .append(service.getClass().getSimpleName())
+ .append("\n");
+ }
+
+ Slog.e(TAG, builder.toString());
+ }
+
+ private SystemService createInstance(Class<?> clazz) {
+ // Make sure it's a type we expect
+ if (!SystemService.class.isAssignableFrom(clazz)) {
+ reportWtf("Class " + clazz.getName() + " does not extend " +
+ SystemService.class.getName());
+ }
+
+ try {
+ return (SystemService) clazz.newInstance();
+ } catch (InstantiationException e) {
+ reportWtf("Class " + clazz.getName() + " is abstract", e);
+ } catch (IllegalAccessException e) {
+ reportWtf("Class " + clazz.getName() +
+ " must have a public no-arg constructor", e);
+ }
+ return null;
+ }
+
+ private static void reportWtf(String message) {
+ reportWtf(message, null);
+ }
+
+ private static void reportWtf(String message, Throwable e) {
+ Slog.i(TAG, "******************************");
+ Log.wtf(TAG, message, e);
+
+ // Make sure we die
+ throw new RuntimeException(message, e);
+ }
+}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 062be01..de912dc 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -34,9 +34,9 @@ import android.content.res.Configuration;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.Sandman;
@@ -47,9 +47,11 @@ import java.io.PrintWriter;
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
-import com.android.server.TwilightService.TwilightState;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
-final class UiModeManagerService extends IUiModeManager.Stub {
+final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
private static final boolean LOG = false;
@@ -57,40 +59,36 @@ final class UiModeManagerService extends IUiModeManager.Stub {
private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
- private final Context mContext;
- private final TwilightService mTwilightService;
- private final Handler mHandler = new Handler();
-
final Object mLock = new Object();
-
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ int mNightMode = UiModeManager.MODE_NIGHT_NO;
- private int mNightMode = UiModeManager.MODE_NIGHT_NO;
private boolean mCarModeEnabled = false;
private boolean mCharging = false;
- private final int mDefaultUiModeType;
- private final boolean mCarModeKeepsScreenOn;
- private final boolean mDeskModeKeepsScreenOn;
- private final boolean mTelevision;
-
+ private int mDefaultUiModeType;
+ private boolean mCarModeKeepsScreenOn;
+ private boolean mDeskModeKeepsScreenOn;
+ private boolean mTelevision;
private boolean mComputedNightMode;
- private int mCurUiMode = 0;
- private int mSetUiMode = 0;
+ int mCurUiMode = 0;
+ private int mSetUiMode = 0;
private boolean mHoldingConfiguration = false;
+
private Configuration mConfiguration = new Configuration();
+ boolean mSystemReady;
- private boolean mSystemReady;
+ private final Handler mHandler = new Handler();
+ private TwilightManager mTwilightManager;
private NotificationManager mNotificationManager;
-
private StatusBarManager mStatusBarManager;
- private final PowerManager mPowerManager;
- private final PowerManager.WakeLock mWakeLock;
+ private PowerManager.WakeLock mWakeLock;
- static Intent buildHomeIntent(String category) {
+ private static Intent buildHomeIntent(String category) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(category);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -142,28 +140,26 @@ final class UiModeManagerService extends IUiModeManager.Stub {
}
};
- private final TwilightService.TwilightListener mTwilightListener =
- new TwilightService.TwilightListener() {
+ private final TwilightListener mTwilightListener = new TwilightListener() {
@Override
public void onTwilightStateChanged() {
updateTwilight();
}
};
- public UiModeManagerService(Context context, TwilightService twilight) {
- mContext = context;
- mTwilightService = twilight;
-
- ServiceManager.addService(Context.UI_MODE_SERVICE, this);
-
- mContext.registerReceiver(mDockModeReceiver,
+ @Override
+ public void onStart() {
+ final Context context = getContext();
+ mTwilightManager = getLocalService(TwilightManager.class);
+ final PowerManager powerManager =
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+
+ context.registerReceiver(mDockModeReceiver,
new IntentFilter(Intent.ACTION_DOCK_EVENT));
- mContext.registerReceiver(mBatteryReceiver,
+ context.registerReceiver(mBatteryReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
-
mConfiguration.setToDefaults();
mDefaultUiModeType = context.getResources().getInteger(
@@ -175,101 +171,139 @@ final class UiModeManagerService extends IUiModeManager.Stub {
mTelevision = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEVISION);
- mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ mNightMode = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
- mTwilightService.registerListener(mTwilightListener, mHandler);
+ mTwilightManager.registerListener(mTwilightListener, mHandler);
+
+ publishBinderService(Context.UI_MODE_SERVICE, mService);
}
- @Override // Binder call
- public void disableCarMode(int flags) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- setCarModeLocked(false);
- if (mSystemReady) {
- updateLocked(0, flags);
+ private final IBinder mService = new IUiModeManager.Stub() {
+ @Override
+ public void enableCarMode(int flags) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ setCarModeLocked(true);
+ if (mSystemReady) {
+ updateLocked(flags, 0);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
- }
- @Override // Binder call
- public void enableCarMode(int flags) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- setCarModeLocked(true);
- if (mSystemReady) {
- updateLocked(flags, 0);
+ @Override
+ public void disableCarMode(int flags) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ setCarModeLocked(false);
+ if (mSystemReady) {
+ updateLocked(0, flags);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
- }
- @Override // Binder call
- public int getCurrentModeType() {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
+ @Override
+ public int getCurrentModeType() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
- }
- @Override // Binder call
- public void setNightMode(int mode) {
- switch (mode) {
- case UiModeManager.MODE_NIGHT_NO:
- case UiModeManager.MODE_NIGHT_YES:
- case UiModeManager.MODE_NIGHT_AUTO:
- break;
- default:
- throw new IllegalArgumentException("Unknown mode: " + mode);
+ @Override
+ public void setNightMode(int mode) {
+ switch (mode) {
+ case UiModeManager.MODE_NIGHT_NO:
+ case UiModeManager.MODE_NIGHT_YES:
+ case UiModeManager.MODE_NIGHT_AUTO:
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown mode: " + mode);
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (isDoingNightModeLocked() && mNightMode != mode) {
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ Settings.Secure.UI_NIGHT_MODE, mode);
+ mNightMode = mode;
+ updateLocked(0, 0);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
- final long ident = Binder.clearCallingIdentity();
- try {
+ @Override
+ public int getNightMode() {
synchronized (mLock) {
- if (isDoingNightModeLocked() && mNightMode != mode) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.UI_NIGHT_MODE, mode);
- mNightMode = mode;
- updateLocked(0, 0);
- }
+ return mNightMode;
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
- }
- @Override // Binder call
- public int getNightMode() {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump uimode service from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpImpl(pw);
+ }
+ };
+
+ void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
- return mNightMode;
+ pw.println("Current UI Mode Service state:");
+ pw.print(" mDockState="); pw.print(mDockState);
+ pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+ pw.print(" mNightMode="); pw.print(mNightMode);
+ pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
+ pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
+ pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
+ pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+ pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
+ pw.print(" mSystemReady="); pw.println(mSystemReady);
+ pw.print(" mTwilightService.getCurrentState()=");
+ pw.println(mTwilightManager.getCurrentState());
}
}
- void systemReady() {
- synchronized (mLock) {
- mSystemReady = true;
- mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
- updateComputedNightModeLocked();
- updateLocked(0, 0);
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ synchronized (mLock) {
+ mSystemReady = true;
+ mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+ updateComputedNightModeLocked();
+ updateLocked(0, 0);
+ }
}
}
- private boolean isDoingNightModeLocked() {
+ boolean isDoingNightModeLocked() {
return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
}
- private void setCarModeLocked(boolean enabled) {
+ void setCarModeLocked(boolean enabled) {
if (mCarModeEnabled != enabled) {
mCarModeEnabled = enabled;
}
@@ -344,7 +378,7 @@ final class UiModeManagerService extends IUiModeManager.Stub {
}
}
- private void updateLocked(int enableFlags, int disableFlags) {
+ void updateLocked(int enableFlags, int disableFlags) {
String action = null;
String oldAction = null;
if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
@@ -359,7 +393,7 @@ final class UiModeManagerService extends IUiModeManager.Stub {
adjustStatusBarCarModeLocked();
if (oldAction != null) {
- mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+ getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
}
mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
action = UiModeManager.ACTION_ENTER_CAR_MODE;
@@ -367,7 +401,7 @@ final class UiModeManagerService extends IUiModeManager.Stub {
} else if (isDeskDockState(mDockState)) {
if (!isDeskDockState(mLastBroadcastState)) {
if (oldAction != null) {
- mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+ getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
}
mLastBroadcastState = mDockState;
action = UiModeManager.ACTION_ENTER_DESK_MODE;
@@ -393,7 +427,7 @@ final class UiModeManagerService extends IUiModeManager.Stub {
Intent intent = new Intent(action);
intent.putExtra("enableFlags", enableFlags);
intent.putExtra("disableFlags", disableFlags);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+ getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
mResultReceiver, null, Activity.RESULT_OK, null, null);
// Attempting to make this transition a little more clean, we are going
@@ -491,7 +525,7 @@ final class UiModeManagerService extends IUiModeManager.Stub {
// activity manager take care of both the start and config
// change.
Intent homeIntent = buildHomeIntent(category);
- if (Sandman.shouldStartDockApp(mContext, homeIntent)) {
+ if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
int result = ActivityManagerNative.getDefault().startActivityWithConfig(
null, null, homeIntent, null, null, null, 0, 0,
@@ -513,14 +547,15 @@ final class UiModeManagerService extends IUiModeManager.Stub {
// If we did not start a dock app, then start dreaming if supported.
if (category != null && !dockAppStarted) {
- Sandman.startDreamWhenDockedIfAppropriate(mContext);
+ Sandman.startDreamWhenDockedIfAppropriate(getContext());
}
}
private void adjustStatusBarCarModeLocked() {
+ final Context context = getContext();
if (mStatusBarManager == null) {
mStatusBarManager = (StatusBarManager)
- mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+ context.getSystemService(Context.STATUS_BAR_SERVICE);
}
// Fear not: StatusBarManagerService manages a list of requests to disable
@@ -536,12 +571,12 @@ final class UiModeManagerService extends IUiModeManager.Stub {
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ context.getSystemService(Context.NOTIFICATION_SERVICE);
}
if (mNotificationManager != null) {
if (mCarModeEnabled) {
- Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+ Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
Notification n = new Notification();
n.icon = R.drawable.stat_notify_car_mode;
@@ -549,10 +584,10 @@ final class UiModeManagerService extends IUiModeManager.Stub {
n.flags = Notification.FLAG_ONGOING_EVENT;
n.when = 0;
n.setLatestEventInfo(
- mContext,
- mContext.getString(R.string.car_mode_disable_notification_title),
- mContext.getString(R.string.car_mode_disable_notification_message),
- PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0,
+ context,
+ context.getString(R.string.car_mode_disable_notification_title),
+ context.getString(R.string.car_mode_disable_notification_message),
+ PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
null, UserHandle.CURRENT));
mNotificationManager.notifyAsUser(null,
R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
@@ -563,7 +598,7 @@ final class UiModeManagerService extends IUiModeManager.Stub {
}
}
- private void updateTwilight() {
+ void updateTwilight() {
synchronized (mLock) {
if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
updateComputedNightModeLocked();
@@ -573,36 +608,11 @@ final class UiModeManagerService extends IUiModeManager.Stub {
}
private void updateComputedNightModeLocked() {
- TwilightState state = mTwilightService.getCurrentState();
+ TwilightState state = mTwilightManager.getCurrentState();
if (state != null) {
mComputedNightMode = state.isNight();
}
}
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump uimode service from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- synchronized (mLock) {
- pw.println("Current UI Mode Service state:");
- pw.print(" mDockState="); pw.print(mDockState);
- pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
- pw.print(" mNightMode="); pw.print(mNightMode);
- pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
- pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
- pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
- pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
- pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
- pw.print(" mSystemReady="); pw.println(mSystemReady);
- pw.print(" mTwilightService.getCurrentState()=");
- pw.println(mTwilightService.getCurrentState());
- }
- }
}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 3e90078..e0d6505 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -76,9 +76,6 @@ public class Watchdog extends Thread {
final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>();
final HandlerChecker mMonitorChecker;
ContentResolver mResolver;
- BatteryService mBattery;
- PowerManagerService mPower;
- AlarmManagerService mAlarm;
ActivityManagerService mActivity;
int mPhonePid;
@@ -230,13 +227,8 @@ public class Watchdog extends Thread {
"i/o thread", DEFAULT_TIMEOUT));
}
- public void init(Context context, BatteryService battery,
- PowerManagerService power, AlarmManagerService alarm,
- ActivityManagerService activity) {
+ public void init(Context context, ActivityManagerService activity) {
mResolver = context.getContentResolver();
- mBattery = battery;
- mPower = power;
- mAlarm = alarm;
mActivity = activity;
context.registerReceiver(new RebootRequestReceiver(),
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 2e914aa..c3ecf5f 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -39,7 +39,6 @@ import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import android.os.Trace;
import android.util.Log;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.util.Objects;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.wm.AppTransition;
@@ -84,6 +83,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
/**
* State and management of a single stack of activities.
@@ -1769,6 +1769,21 @@ final class ActivityStack {
r.putInHistory();
r.frontOfTask = newTask;
+ if (!r.frontOfTask) {
+ // It is possible that the current frontOfTask activity is finishing. Check for that.
+ ArrayList<ActivityRecord> activities = task.mActivities;
+ for (int activityNdx = 0; activityNdx < activities.size(); ++activityNdx) {
+ final ActivityRecord activity = activities.get(activityNdx);
+ if (activity.finishing) {
+ continue;
+ }
+ if (activity == r) {
+ // All activities before r are finishing.
+ r.frontOfTask = true;
+ }
+ break;
+ }
+ }
if (!isHomeStack() || numActivities() > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
@@ -2377,7 +2392,7 @@ final class ActivityStack {
ArrayList<ActivityRecord> activities = r.task.mActivities;
for (int index = activities.indexOf(r); index >= 0; --index) {
ActivityRecord cur = activities.get(index);
- if (!Objects.equal(cur.taskAffinity, r.taskAffinity)) {
+ if (!Objects.equals(cur.taskAffinity, r.taskAffinity)) {
break;
}
finishActivityLocked(cur, Activity.RESULT_CANCELED, null, "request-affinity", true);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 80e6e94..cb04835 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -18,7 +18,8 @@ package com.android.server.am;
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.NotificationManagerService;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
import android.app.INotificationManager;
import android.app.Notification;
@@ -427,8 +428,8 @@ final class ServiceRecord extends Binder {
final Notification localForegroundNoti = foregroundNoti;
ams.mHandler.post(new Runnable() {
public void run() {
- NotificationManagerService nm =
- (NotificationManagerService) NotificationManager.getService();
+ NotificationManagerInternal nm = LocalServices.getService(
+ NotificationManagerInternal.class);
if (nm == null) {
return;
}
@@ -479,7 +480,7 @@ final class ServiceRecord extends Binder {
throw new RuntimeException("icon must be non-zero");
}
int[] outId = new int[1];
- nm.enqueueNotificationInternal(localPackageName, localPackageName,
+ nm.enqueueNotification(localPackageName, localPackageName,
appUid, appPid, null, localForegroundId, localForegroundNoti,
outId, userId);
} catch (RuntimeException e) {
diff --git a/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 36ce3a4..186fbe1 100644
--- a/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -108,7 +108,7 @@ import java.util.Set;
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
- private static final String TAG = "DevicePolicyManagerService";
+ private static final String LOG_TAG = "DevicePolicyManagerService";
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
@@ -177,7 +177,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
- if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+ if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
mHandler.post(new Runnable() {
public void run() {
@@ -209,6 +209,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
};
static class ActiveAdmin {
+ private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
+ private static final String TAG_DISABLE_CAMERA = "disable-camera";
+ private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
+ private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
+ private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
+ private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list";
+ private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec";
+ private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy";
+ private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
+ private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
+ private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
+ private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
+ private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
+ private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters";
+ private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase";
+ private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase";
+ private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
+ private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
+ private static final String ATTR_VALUE = "value";
+ private static final String TAG_PASSWORD_QUALITY = "password-quality";
+ private static final String TAG_POLICIES = "policies";
+
final DeviceAdminInfo info;
int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -272,103 +294,103 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
void writeToXml(XmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
- out.startTag(null, "policies");
+ out.startTag(null, TAG_POLICIES);
info.writePoliciesToXml(out);
- out.endTag(null, "policies");
+ out.endTag(null, TAG_POLICIES);
if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
- out.startTag(null, "password-quality");
- out.attribute(null, "value", Integer.toString(passwordQuality));
- out.endTag(null, "password-quality");
+ out.startTag(null, TAG_PASSWORD_QUALITY);
+ out.attribute(null, ATTR_VALUE, Integer.toString(passwordQuality));
+ out.endTag(null, TAG_PASSWORD_QUALITY);
if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
- out.startTag(null, "min-password-length");
- out.attribute(null, "value", Integer.toString(minimumPasswordLength));
- out.endTag(null, "min-password-length");
+ out.startTag(null, TAG_MIN_PASSWORD_LENGTH);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLength));
+ out.endTag(null, TAG_MIN_PASSWORD_LENGTH);
}
if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
- out.startTag(null, "password-history-length");
- out.attribute(null, "value", Integer.toString(passwordHistoryLength));
- out.endTag(null, "password-history-length");
+ out.startTag(null, TAG_PASSWORD_HISTORY_LENGTH);
+ out.attribute(null, ATTR_VALUE, Integer.toString(passwordHistoryLength));
+ out.endTag(null, TAG_PASSWORD_HISTORY_LENGTH);
}
if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
- out.startTag(null, "min-password-uppercase");
- out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
- out.endTag(null, "min-password-uppercase");
+ out.startTag(null, TAG_MIN_PASSWORD_UPPERCASE);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordUpperCase));
+ out.endTag(null, TAG_MIN_PASSWORD_UPPERCASE);
}
if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
- out.startTag(null, "min-password-lowercase");
- out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
- out.endTag(null, "min-password-lowercase");
+ out.startTag(null, TAG_MIN_PASSWORD_LOWERCASE);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLowerCase));
+ out.endTag(null, TAG_MIN_PASSWORD_LOWERCASE);
}
if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
- out.startTag(null, "min-password-letters");
- out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
- out.endTag(null, "min-password-letters");
+ out.startTag(null, TAG_MIN_PASSWORD_LETTERS);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLetters));
+ out.endTag(null, TAG_MIN_PASSWORD_LETTERS);
}
if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
- out.startTag(null, "min-password-numeric");
- out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
- out.endTag(null, "min-password-numeric");
+ out.startTag(null, TAG_MIN_PASSWORD_NUMERIC);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNumeric));
+ out.endTag(null, TAG_MIN_PASSWORD_NUMERIC);
}
if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
- out.startTag(null, "min-password-symbols");
- out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
- out.endTag(null, "min-password-symbols");
+ out.startTag(null, TAG_MIN_PASSWORD_SYMBOLS);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordSymbols));
+ out.endTag(null, TAG_MIN_PASSWORD_SYMBOLS);
}
if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
- out.startTag(null, "min-password-nonletter");
- out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
- out.endTag(null, "min-password-nonletter");
+ out.startTag(null, TAG_MIN_PASSWORD_NONLETTER);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNonLetter));
+ out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
}
}
if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
- out.startTag(null, "max-time-to-unlock");
- out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
- out.endTag(null, "max-time-to-unlock");
+ out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
+ out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
+ out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
}
if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
- out.startTag(null, "max-failed-password-wipe");
- out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
- out.endTag(null, "max-failed-password-wipe");
+ out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
+ out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
+ out.endTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
}
if (specifiesGlobalProxy) {
- out.startTag(null, "specifies-global-proxy");
- out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
- out.endTag(null, "specifies_global_proxy");
+ out.startTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(specifiesGlobalProxy));
+ out.endTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
if (globalProxySpec != null) {
- out.startTag(null, "global-proxy-spec");
- out.attribute(null, "value", globalProxySpec);
- out.endTag(null, "global-proxy-spec");
+ out.startTag(null, TAG_GLOBAL_PROXY_SPEC);
+ out.attribute(null, ATTR_VALUE, globalProxySpec);
+ out.endTag(null, TAG_GLOBAL_PROXY_SPEC);
}
if (globalProxyExclusionList != null) {
- out.startTag(null, "global-proxy-exclusion-list");
- out.attribute(null, "value", globalProxyExclusionList);
- out.endTag(null, "global-proxy-exclusion-list");
+ out.startTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
+ out.attribute(null, ATTR_VALUE, globalProxyExclusionList);
+ out.endTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
}
}
if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
- out.startTag(null, "password-expiration-timeout");
- out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
- out.endTag(null, "password-expiration-timeout");
+ out.startTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
+ out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationTimeout));
+ out.endTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
}
if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
- out.startTag(null, "password-expiration-date");
- out.attribute(null, "value", Long.toString(passwordExpirationDate));
- out.endTag(null, "password-expiration-date");
+ out.startTag(null, TAG_PASSWORD_EXPIRATION_DATE);
+ out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationDate));
+ out.endTag(null, TAG_PASSWORD_EXPIRATION_DATE);
}
if (encryptionRequested) {
- out.startTag(null, "encryption-requested");
- out.attribute(null, "value", Boolean.toString(encryptionRequested));
- out.endTag(null, "encryption-requested");
+ out.startTag(null, TAG_ENCRYPTION_REQUESTED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
+ out.endTag(null, TAG_ENCRYPTION_REQUESTED);
}
if (disableCamera) {
- out.startTag(null, "disable-camera");
- out.attribute(null, "value", Boolean.toString(disableCamera));
- out.endTag(null, "disable-camera");
+ out.startTag(null, TAG_DISABLE_CAMERA);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
+ out.endTag(null, TAG_DISABLE_CAMERA);
}
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
- out.startTag(null, "disable-keyguard-features");
- out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
- out.endTag(null, "disable-keyguard-features");
+ out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
+ out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
+ out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
}
}
@@ -382,67 +404,67 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
continue;
}
String tag = parser.getName();
- if ("policies".equals(tag)) {
+ if (TAG_POLICIES.equals(tag)) {
info.readPoliciesFromXml(parser);
- } else if ("password-quality".equals(tag)) {
+ } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
passwordQuality = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-length".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
minimumPasswordLength = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("password-history-length".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
passwordHistoryLength = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-uppercase".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
minimumPasswordUpperCase = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-lowercase".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
minimumPasswordLowerCase = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-letters".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
minimumPasswordLetters = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-numeric".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
minimumPasswordNumeric = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-symbols".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
minimumPasswordSymbols = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-nonletter".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
minimumPasswordNonLetter = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("max-time-to-unlock".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
maximumTimeToUnlock = Long.parseLong(
- parser.getAttributeValue(null, "value"));
- } else if ("max-failed-password-wipe".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
maximumFailedPasswordsForWipe = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("specifies-global-proxy".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) {
specifiesGlobalProxy = Boolean.parseBoolean(
- parser.getAttributeValue(null, "value"));
- } else if ("global-proxy-spec".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) {
globalProxySpec =
- parser.getAttributeValue(null, "value");
- } else if ("global-proxy-exclusion-list".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE);
+ } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) {
globalProxyExclusionList =
- parser.getAttributeValue(null, "value");
- } else if ("password-expiration-timeout".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE);
+ } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) {
passwordExpirationTimeout = Long.parseLong(
- parser.getAttributeValue(null, "value"));
- } else if ("password-expiration-date".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) {
passwordExpirationDate = Long.parseLong(
- parser.getAttributeValue(null, "value"));
- } else if ("encryption-requested".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
encryptionRequested = Boolean.parseBoolean(
- parser.getAttributeValue(null, "value"));
- } else if ("disable-camera".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_DISABLE_CAMERA.equals(tag)) {
disableCamera = Boolean.parseBoolean(
- parser.getAttributeValue(null, "value"));
- } else if ("disable-keyguard-features".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
- Slog.w(TAG, "Unknown admin tag: " + tag);
+ Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
}
XmlUtils.skipCurrentTag(parser);
}
@@ -504,7 +526,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void handlePackagesChanged(int userHandle) {
boolean removed = false;
- if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
+ if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
IPackageManager pm = AppGlobals.getPackageManager();
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -576,7 +598,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
void removeUserData(int userHandle) {
synchronized (this) {
if (userHandle == UserHandle.USER_OWNER) {
- Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
+ Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
DevicePolicyData policy = mUserData.get(userHandle);
@@ -586,7 +608,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML);
policyFile.delete();
- Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+ Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
}
}
@@ -783,10 +805,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
return new DeviceAdminInfo(mContext, infos.get(0));
} catch (XmlPullParserException e) {
- Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+ Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+ e);
return null;
} catch (IOException e) {
- Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+ Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+ e);
return null;
}
}
@@ -913,7 +937,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ComponentName.unflattenFromString(name), userHandle);
if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
!= userHandle)) {
- Slog.w(TAG, "findAdmin returned an incorrect uid "
+ Slog.w(LOG_TAG, "findAdmin returned an incorrect uid "
+ dai.getActivityInfo().applicationInfo.uid + " for user "
+ userHandle);
}
@@ -924,7 +948,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mAdminList.add(ap);
}
} catch (RuntimeException e) {
- Slog.w(TAG, "Failed loading admin " + name, e);
+ Slog.w(LOG_TAG, "Failed loading admin " + name, e);
}
} else if ("failed-password-attempts".equals(tag)) {
policy.mFailedPasswordAttempts = Integer.parseInt(
@@ -953,22 +977,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else {
- Slog.w(TAG, "Unknown tag: " + tag);
+ Slog.w(LOG_TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
}
}
} catch (NullPointerException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (NumberFormatException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (XmlPullParserException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (FileNotFoundException e) {
// Don't be noisy, this is normal if we haven't defined any policies.
} catch (IOException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (IndexOutOfBoundsException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
}
try {
if (stream != null) {
@@ -984,7 +1008,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// never normally happen.
LockPatternUtils utils = new LockPatternUtils(mContext);
if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
- Slog.w(TAG, "Active password quality 0x"
+ Slog.w(LOG_TAG, "Active password quality 0x"
+ Integer.toHexString(policy.mActivePasswordQuality)
+ " does not match actual quality 0x"
+ Integer.toHexString(utils.getActivePasswordQuality()));
@@ -1028,7 +1052,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
if (!haveOwner) {
- Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
+ Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner
+ " no longer active; disabling");
policy.mPasswordOwner = -1;
}
@@ -1048,7 +1072,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long token = Binder.clearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
- if (DBG) Slog.v(TAG, "Change in camera state ["
+ if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
+ SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
} finally {
@@ -1164,7 +1188,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
+ if (!refreshing
+ && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
ActiveAdmin newAdmin = new ActiveAdmin(info);
@@ -1434,7 +1459,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ap.passwordExpirationDate = expiration;
ap.passwordExpirationTimeout = timeout;
if (timeout > 0L) {
- Slog.w(TAG, "setPasswordExpiration(): password will expire on "
+ Slog.w(LOG_TAG, "setPasswordExpiration(): password will expire on "
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
.format(new Date(expiration)));
}
@@ -1780,11 +1805,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return true;
}
return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
- && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
- && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
- && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
- && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
- && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
+ && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
+ && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
+ && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
+ && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
+ && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
}
}
@@ -1862,7 +1887,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int realQuality = LockPatternUtils.computePasswordQuality(password);
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
- Slog.w(TAG, "resetPassword: password quality 0x"
+ Slog.w(LOG_TAG, "resetPassword: password quality 0x"
+ Integer.toHexString(realQuality)
+ " does not meet required quality 0x"
+ Integer.toHexString(quality));
@@ -1872,7 +1897,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
int length = getPasswordMinimumLength(null, userHandle);
if (password.length() < length) {
- Slog.w(TAG, "resetPassword: password length " + password.length()
+ Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
+ " does not meet required length " + length);
return false;
}
@@ -1901,40 +1926,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
int neededLetters = getPasswordMinimumLetters(null, userHandle);
if(letters < neededLetters) {
- Slog.w(TAG, "resetPassword: number of letters " + letters
+ Slog.w(LOG_TAG, "resetPassword: number of letters " + letters
+ " does not meet required number of letters " + neededLetters);
return false;
}
int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
if (numbers < neededNumbers) {
- Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+ Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers
+ " does not meet required number of numerical digits "
+ neededNumbers);
return false;
}
int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
if (lowercase < neededLowerCase) {
- Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+ Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase
+ " does not meet required number of lowercase letters "
+ neededLowerCase);
return false;
}
int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
if (uppercase < neededUpperCase) {
- Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+ Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase
+ " does not meet required number of uppercase letters "
+ neededUpperCase);
return false;
}
int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
if (symbols < neededSymbols) {
- Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+ Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols
+ " does not meet required number of special symbols " + neededSymbols);
return false;
}
int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
if (nonletter < neededNonLetter) {
- Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+ Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter
+ " does not meet required number of non-letter characters "
+ neededNonLetter);
return false;
@@ -1945,7 +1970,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int callingUid = Binder.getCallingUid();
DevicePolicyData policy = getUserData(userHandle);
if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
- Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
+ Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
@@ -2011,7 +2036,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
} catch (RemoteException e) {
- Slog.w(TAG, "Failure talking with power manager", e);
+ Slog.w(LOG_TAG, "Failure talking with power manager", e);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2086,10 +2111,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
X509Certificate cert = parseCert(certBuffer);
pemCert = Credentials.convertToPem(cert);
} catch (CertificateException ce) {
- Log.e(TAG, "Problem converting cert", ce);
+ Log.e(LOG_TAG, "Problem converting cert", ce);
return false;
} catch (IOException ioe) {
- Log.e(TAG, "Problem reading cert", ioe);
+ Log.e(LOG_TAG, "Problem reading cert", ioe);
return false;
}
try {
@@ -2104,7 +2129,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} catch (InterruptedException e1) {
- Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
+ Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
}
return false;
@@ -2125,10 +2150,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
X509Certificate cert = parseCert(certBuffer);
alias = certStore.getCertificateAlias(cert);
} catch (CertificateException ce) {
- Log.e(TAG, "Problem creating X509Certificate", ce);
+ Log.e(LOG_TAG, "Problem creating X509Certificate", ce);
return;
} catch (IOException ioe) {
- Log.e(TAG, "Problem reading certificate", ioe);
+ Log.e(LOG_TAG, "Problem reading certificate", ioe);
return;
}
try {
@@ -2137,13 +2162,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
service.deleteCaCertificate(alias);
} catch (RemoteException e) {
- Log.e(TAG, "from CaCertUninstaller: ", e);
+ Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
} finally {
keyChainConnection.close();
keyChainConnection = null;
}
} catch (InterruptedException ie) {
- Log.w(TAG, "CaCertUninstaller: ", ie);
+ Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
}
}
@@ -2164,7 +2189,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
RecoverySystem.rebootWipeUserData(mContext);
} catch (IOException e) {
- Slog.w(TAG, "Failed requesting data wipe", e);
+ Slog.w(LOG_TAG, "Failed requesting data wipe", e);
}
}
}
@@ -2255,8 +2280,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
|| p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
|| p.mActivePasswordUpperCase != uppercase
- || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
- || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
+ || p.mActivePasswordLowerCase != lowercase
+ || p.mActivePasswordNumeric != numbers
+ || p.mActivePasswordSymbols != symbols
+ || p.mActivePasswordNonLetter != nonletter) {
long ident = Binder.clearCallingIdentity();
try {
p.mActivePasswordQuality = quality;
@@ -2378,7 +2405,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// If the user is not the owner, don't set the global proxy. Fail silently.
if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
- Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+ Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
+ userHandle + " is not permitted.");
return null;
}
@@ -2459,7 +2486,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
if (!proxyProperties.isValid()) {
- Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+ Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
@@ -2485,7 +2512,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Only owner can set storage encryption
if (userHandle != UserHandle.USER_OWNER
|| UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
- Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+ Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User "
+ UserHandle.getCallingUserId() + " is not permitted.");
return 0;
}
@@ -2871,7 +2898,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
} catch (NameNotFoundException nnfe) {
- Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+ Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
}
return false;
}
@@ -2896,9 +2923,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
input.close();
} catch (XmlPullParserException xppe) {
- Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+ Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
} catch (IOException ioe) {
- Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+ Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
}
}
@@ -2926,7 +2953,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.flush();
file.finishWrite(output);
} catch (IOException ioe) {
- Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+ Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
}
}
}
diff --git a/services/java/com/android/server/lights/Light.java b/services/java/com/android/server/lights/Light.java
new file mode 100644
index 0000000..b496b4c
--- /dev/null
+++ b/services/java/com/android/server/lights/Light.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.lights;
+
+public abstract class Light {
+ public static final int LIGHT_FLASH_NONE = 0;
+ public static final int LIGHT_FLASH_TIMED = 1;
+ public static final int LIGHT_FLASH_HARDWARE = 2;
+
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ public static final int BRIGHTNESS_MODE_USER = 0;
+
+ /**
+ * Light brightness is managed by a light sensor.
+ */
+ public static final int BRIGHTNESS_MODE_SENSOR = 1;
+
+ public abstract void setBrightness(int brightness);
+ public abstract void setBrightness(int brightness, int brightnessMode);
+ public abstract void setColor(int color);
+ public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+ public abstract void pulse();
+ public abstract void pulse(int color, int onMS);
+ public abstract void turnOff();
+} \ No newline at end of file
diff --git a/services/java/com/android/server/lights/LightsManager.java b/services/java/com/android/server/lights/LightsManager.java
new file mode 100644
index 0000000..2f20509
--- /dev/null
+++ b/services/java/com/android/server/lights/LightsManager.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.lights;
+
+public abstract class LightsManager {
+ public static final int LIGHT_ID_BACKLIGHT = 0;
+ public static final int LIGHT_ID_KEYBOARD = 1;
+ public static final int LIGHT_ID_BUTTONS = 2;
+ public static final int LIGHT_ID_BATTERY = 3;
+ public static final int LIGHT_ID_NOTIFICATIONS = 4;
+ public static final int LIGHT_ID_ATTENTION = 5;
+ public static final int LIGHT_ID_BLUETOOTH = 6;
+ public static final int LIGHT_ID_WIFI = 7;
+ public static final int LIGHT_ID_COUNT = 8;
+
+ public abstract Light getLight(int id);
+}
diff --git a/services/java/com/android/server/LightsService.java b/services/java/com/android/server/lights/LightsService.java
index 89bfcac..d814785 100644
--- a/services/java/com/android/server/LightsService.java
+++ b/services/java/com/android/server/lights/LightsService.java
@@ -14,59 +14,38 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.lights;
+
+import com.android.server.SystemService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.IHardwareService;
-import android.os.ServiceManager;
import android.os.Message;
import android.util.Slog;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-public class LightsService {
- private static final String TAG = "LightsService";
- private static final boolean DEBUG = false;
-
- public static final int LIGHT_ID_BACKLIGHT = 0;
- public static final int LIGHT_ID_KEYBOARD = 1;
- public static final int LIGHT_ID_BUTTONS = 2;
- public static final int LIGHT_ID_BATTERY = 3;
- public static final int LIGHT_ID_NOTIFICATIONS = 4;
- public static final int LIGHT_ID_ATTENTION = 5;
- public static final int LIGHT_ID_BLUETOOTH = 6;
- public static final int LIGHT_ID_WIFI = 7;
- public static final int LIGHT_ID_COUNT = 8;
-
- public static final int LIGHT_FLASH_NONE = 0;
- public static final int LIGHT_FLASH_TIMED = 1;
- public static final int LIGHT_FLASH_HARDWARE = 2;
-
- /**
- * Light brightness is managed by a user setting.
- */
- public static final int BRIGHTNESS_MODE_USER = 0;
-
- /**
- * Light brightness is managed by a light sensor.
- */
- public static final int BRIGHTNESS_MODE_SENSOR = 1;
+public class LightsService extends SystemService {
+ static final String TAG = "LightsService";
+ static final boolean DEBUG = false;
- private final Light mLights[] = new Light[LIGHT_ID_COUNT];
+ final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
- public final class Light {
+ private final class LightImpl extends Light {
- private Light(int id) {
+ private LightImpl(int id) {
mId = id;
}
+ @Override
public void setBrightness(int brightness) {
setBrightness(brightness, BRIGHTNESS_MODE_USER);
}
+ @Override
public void setBrightness(int brightness, int brightnessMode) {
synchronized (this) {
int color = brightness & 0x000000ff;
@@ -75,23 +54,26 @@ public class LightsService {
}
}
+ @Override
public void setColor(int color) {
synchronized (this) {
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
+ @Override
public void setFlashing(int color, int mode, int onMS, int offMS) {
synchronized (this) {
setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
}
}
-
+ @Override
public void pulse() {
pulse(0x00ffffff, 7);
}
+ @Override
public void pulse(int color, int onMS) {
synchronized (this) {
if (mColor == 0 && !mFlashing) {
@@ -101,6 +83,7 @@ public class LightsService {
}
}
+ @Override
public void turnOff() {
synchronized (this) {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
@@ -153,9 +136,10 @@ public class LightsService {
}
public void setFlashlightEnabled(boolean on) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
+ final Context context = getContext();
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
!= PackageManager.PERMISSION_GRANTED &&
- mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
}
@@ -172,31 +156,41 @@ public class LightsService {
}
};
- LightsService(Context context) {
-
+ @Override
+ public void onCreate(Context context) {
mNativePointer = init_native();
- mContext = context;
-
- ServiceManager.addService("hardware", mLegacyFlashlightHack);
- for (int i = 0; i < LIGHT_ID_COUNT; i++) {
- mLights[i] = new Light(i);
+ for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
+ mLights[i] = new LightImpl(i);
}
}
+ @Override
+ public void onStart() {
+ publishBinderService("hardware", mLegacyFlashlightHack);
+ publishLocalService(LightsManager.class, mService);
+ }
+
+ private final LightsManager mService = new LightsManager() {
+ @Override
+ public com.android.server.lights.Light getLight(int id) {
+ if (id < LIGHT_ID_COUNT) {
+ return mLights[id];
+ } else {
+ return null;
+ }
+ }
+ };
+
protected void finalize() throws Throwable {
finalize_native(mNativePointer);
super.finalize();
}
- public Light getLight(int id) {
- return mLights[id];
- }
-
private Handler mH = new Handler() {
@Override
public void handleMessage(Message msg) {
- Light light = (Light)msg.obj;
+ LightImpl light = (LightImpl)msg.obj;
light.stopFlashing();
}
};
@@ -204,10 +198,8 @@ public class LightsService {
private static native int init_native();
private static native void finalize_native(int ptr);
- private static native void setLight_native(int ptr, int light, int color, int mode,
+ static native void setLight_native(int ptr, int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
- private final Context mContext;
-
- private int mNativePointer;
+ int mNativePointer;
}
diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/java/com/android/server/media/MediaRouterService.java
index a31695b..f91ea8c 100644
--- a/services/java/com/android/server/media/MediaRouterService.java
+++ b/services/java/com/android/server/media/MediaRouterService.java
@@ -16,7 +16,6 @@
package com.android.server.media;
-import com.android.internal.util.Objects;
import com.android.server.Watchdog;
import android.Manifest;
@@ -52,6 +51,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Provides a mechanism for discovering media routes and manages media playback
@@ -384,7 +384,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
if (clientRecord != null) {
final String oldRouteId = clientRecord.mSelectedRouteId;
- if (!Objects.equal(routeId, oldRouteId)) {
+ if (!Objects.equals(routeId, oldRouteId)) {
if (DEBUG) {
Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId
+ ", oldRouteId=" + oldRouteId
@@ -1257,12 +1257,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub
mDescriptor = descriptor;
if (descriptor != null) {
final String name = computeName(descriptor);
- if (!Objects.equal(mMutableInfo.name, name)) {
+ if (!Objects.equals(mMutableInfo.name, name)) {
mMutableInfo.name = name;
changed = true;
}
final String description = computeDescription(descriptor);
- if (!Objects.equal(mMutableInfo.description, description)) {
+ if (!Objects.equals(mMutableInfo.description, description)) {
mMutableInfo.description = description;
changed = true;
}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
index b248ee0..a5fe9f2 100644
--- a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
+++ b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
@@ -16,8 +16,6 @@
package com.android.server.media;
-import com.android.internal.util.Objects;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -35,6 +33,7 @@ import android.util.Slog;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.Objects;
/**
* Maintains a connection to a particular remote display provider service.
@@ -101,7 +100,7 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
}
public void setSelectedDisplay(String id) {
- if (!Objects.equal(mSelectedDisplayId, id)) {
+ if (!Objects.equals(mSelectedDisplayId, id)) {
if (mConnectionReady && mSelectedDisplayId != null) {
mActiveConnection.disconnect(mSelectedDisplayId);
}
@@ -293,7 +292,7 @@ final class RemoteDisplayProviderProxy implements ServiceConnection {
}
private void setDisplayState(RemoteDisplayState state) {
- if (!Objects.equal(mDisplayState, state)) {
+ if (!Objects.equals(mDisplayState, state)) {
mDisplayState = state;
if (!mScheduledDisplayStateChangedCallback) {
mScheduledDisplayStateChangedCallback = true;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index d568b11..eb7cc4c 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -133,7 +133,6 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Objects;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -155,6 +154,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import libcore.io.IoUtils;
@@ -688,7 +688,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// mobile templates are relevant when SIM is ready and
// subscriberId matches.
if (tele.getSimState() == SIM_STATE_READY) {
- return Objects.equal(tele.getSubscriberId(), template.getSubscriberId());
+ return Objects.equals(tele.getSubscriberId(), template.getSubscriberId());
} else {
return false;
}
@@ -946,7 +946,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// TODO: offer more granular control over radio states once
// 4965893 is available.
if (tele.getSimState() == SIM_STATE_READY
- && Objects.equal(tele.getSubscriberId(), template.getSubscriberId())) {
+ && Objects.equals(tele.getSubscriberId(), template.getSubscriberId())) {
setPolicyDataEnable(TYPE_MOBILE, enabled);
setPolicyDataEnable(TYPE_WIMAX, enabled);
}
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
index 3169035..475482f 100644
--- a/services/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -34,7 +34,6 @@ import android.util.AtomicFile;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Objects;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -50,6 +49,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import libcore.io.IoUtils;
@@ -508,7 +508,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
this.uid = uid;
this.set = set;
this.tag = tag;
- hashCode = Objects.hashCode(ident, uid, set, tag);
+ hashCode = Objects.hash(ident, uid, set, tag);
}
@Override
@@ -521,7 +521,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
if (obj instanceof Key) {
final Key key = (Key) obj;
return uid == key.uid && set == key.set && tag == key.tag
- && Objects.equal(ident, key.ident);
+ && Objects.equals(ident, key.ident);
}
return false;
}
diff --git a/services/java/com/android/server/notification/NotificationDelegate.java b/services/java/com/android/server/notification/NotificationDelegate.java
new file mode 100644
index 0000000..df2aaca
--- /dev/null
+++ b/services/java/com/android/server/notification/NotificationDelegate.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+public interface NotificationDelegate {
+ void onSetDisabled(int status);
+ void onClearAll();
+ void onNotificationClick(String pkg, String tag, int id);
+ void onNotificationClear(String pkg, String tag, int id);
+ void onNotificationError(String pkg, String tag, int id,
+ int uid, int initialPid, String message);
+ void onPanelRevealed();
+}
diff --git a/services/java/com/android/server/notification/NotificationManagerInternal.java b/services/java/com/android/server/notification/NotificationManagerInternal.java
new file mode 100644
index 0000000..92ffdcc
--- /dev/null
+++ b/services/java/com/android/server/notification/NotificationManagerInternal.java
@@ -0,0 +1,8 @@
+package com.android.server.notification;
+
+import android.app.Notification;
+
+public interface NotificationManagerInternal {
+ void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int[] idReceived, int userId);
+}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/notification/NotificationManagerService.java
index 0438675..db4cf31d 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/notification/NotificationManagerService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.notification;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -47,7 +47,6 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.media.AudioManager;
-import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
@@ -56,9 +55,7 @@ import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.INotificationListener;
@@ -78,6 +75,12 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.notification.NotificationScorer;
+import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.SystemService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -99,66 +102,61 @@ import java.util.Set;
import libcore.io.IoUtils;
-
/** {@hide} */
-public class NotificationManagerService extends INotificationManager.Stub
-{
- private static final String TAG = "NotificationService";
- private static final boolean DBG = false;
+public class NotificationManagerService extends SystemService {
+ static final String TAG = "NotificationService";
+ static final boolean DBG = false;
- private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
+ static final int MAX_PACKAGE_NOTIFICATIONS = 50;
// message codes
- private static final int MESSAGE_TIMEOUT = 2;
+ static final int MESSAGE_TIMEOUT = 2;
- private static final int LONG_DELAY = 3500; // 3.5 seconds
- private static final int SHORT_DELAY = 2000; // 2 seconds
+ static final int LONG_DELAY = 3500; // 3.5 seconds
+ static final int SHORT_DELAY = 2000; // 2 seconds
- private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
- private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
+ static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
+ static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
- private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
- private static final boolean SCORE_ONGOING_HIGHER = false;
+ static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
+ static final boolean SCORE_ONGOING_HIGHER = false;
- private static final int JUNK_SCORE = -1000;
- private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
- private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
+ static final int JUNK_SCORE = -1000;
+ static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+ static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
// Notifications with scores below this will not interrupt the user, either via LED or
// sound or vibration
- private static final int SCORE_INTERRUPTION_THRESHOLD =
+ static final int SCORE_INTERRUPTION_THRESHOLD =
Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
- private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
- private static final boolean ENABLE_BLOCKED_TOASTS = true;
+ static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
+ static final boolean ENABLE_BLOCKED_TOASTS = true;
- private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
+ static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
- final Context mContext;
- final IActivityManager mAm;
- final UserManager mUserManager;
- final IBinder mForegroundToken = new Binder();
+ private IActivityManager mAm;
+ AudioManager mAudioManager;
+ StatusBarManagerInternal mStatusBar;
+ Vibrator mVibrator;
+ final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
- private StatusBarManagerService mStatusBar;
- private LightsService.Light mNotificationLight;
- private LightsService.Light mAttentionLight;
+ private Light mNotificationLight;
+ Light mAttentionLight;
private int mDefaultNotificationColor;
private int mDefaultNotificationLedOn;
- private int mDefaultNotificationLedOff;
+ private int mDefaultNotificationLedOff;
private long[] mDefaultVibrationPattern;
- private long[] mFallbackVibrationPattern;
-
- private boolean mSystemReady;
- private int mDisabledNotifications;
- private NotificationRecord mSoundNotification;
- private NotificationRecord mVibrateNotification;
+ private long[] mFallbackVibrationPattern;
+ boolean mSystemReady;
- private IAudioService mAudioService;
- private Vibrator mVibrator;
+ int mDisabledNotifications;
+ NotificationRecord mSoundNotification;
+ NotificationRecord mVibrateNotification;
// for enabling and disabling notification pulse behavior
private boolean mScreenOn = true;
@@ -166,15 +164,15 @@ public class NotificationManagerService extends INotificationManager.Stub
private boolean mNotificationPulseEnabled;
// used as a mutex for access to all active notifications & listeners
- private final ArrayList<NotificationRecord> mNotificationList =
+ final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
- private ArrayList<ToastRecord> mToastQueue;
+ final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
- private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
- private NotificationRecord mLedNotification;
+ ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
+ NotificationRecord mLedNotification;
- private final AppOpsManager mAppOps;
+ private AppOpsManager mAppOps;
// contains connections to all connected listeners, including app services
// and system listeners
@@ -202,9 +200,9 @@ public class NotificationManagerService extends INotificationManager.Stub
private static final String TAG_PACKAGE = "package";
private static final String ATTR_NAME = "name";
- private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+ final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
- private class NotificationListenerInfo implements DeathRecipient {
+ private class NotificationListenerInfo implements IBinder.DeathRecipient {
INotificationListener listener;
ComponentName component;
int userid;
@@ -262,7 +260,7 @@ public class NotificationManagerService extends INotificationManager.Stub
public void binderDied() {
if (connection == null) {
// This is not a service; it won't be recreated. We can give up this connection.
- unregisterListener(this.listener, this.userid);
+ unregisterListenerImpl(this.listener, this.userid);
}
}
@@ -400,12 +398,14 @@ public class NotificationManagerService extends INotificationManager.Stub
tag = parser.getName();
if (type == START_TAG) {
if (TAG_BODY.equals(tag)) {
- version = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+ version = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_VERSION));
} else if (TAG_BLOCKED_PKGS.equals(tag)) {
while ((type = parser.next()) != END_DOCUMENT) {
tag = parser.getName();
if (TAG_PACKAGE.equals(tag)) {
- mBlockedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
+ mBlockedPackages.add(
+ parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
break;
}
@@ -428,15 +428,6 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- /**
- * Use this when you just want to know if notifications are OK for this package.
- */
- public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
- checkCallerIsSystem();
- return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
- == AppOpsManager.MODE_ALLOWED);
- }
-
/** Use this when you actually want to post a notification or toast.
*
* Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
@@ -450,21 +441,6 @@ public class NotificationManagerService extends INotificationManager.Stub
return true;
}
- public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
- checkCallerIsSystem();
-
- Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
-
- mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
- enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
-
- // Now, cancel any outstanding notifications that are part of a just-disabled app
- if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
- cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
- }
- }
-
-
private static String idDebugString(Context baseContext, String packageName, int id) {
Context c = null;
@@ -490,57 +466,6 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- /**
- * System-only API for getting a list of current (i.e. not cleared) notifications.
- *
- * Requires ACCESS_NOTIFICATIONS which is signature|system.
- */
- @Override
- public StatusBarNotification[] getActiveNotifications(String callingPkg) {
- // enforce() will ensure the calling uid has the correct permission
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
- "NotificationManagerService.getActiveNotifications");
-
- StatusBarNotification[] tmp = null;
- int uid = Binder.getCallingUid();
-
- // noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
- == AppOpsManager.MODE_ALLOWED) {
- synchronized (mNotificationList) {
- tmp = new StatusBarNotification[mNotificationList.size()];
- final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- tmp[i] = mNotificationList.get(i).sbn;
- }
- }
- }
- return tmp;
- }
-
- /**
- * System-only API for getting a list of recent (cleared, no longer shown) notifications.
- *
- * Requires ACCESS_NOTIFICATIONS which is signature|system.
- */
- @Override
- public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
- // enforce() will ensure the calling uid has the correct permission
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
- "NotificationManagerService.getHistoricalNotifications");
-
- StatusBarNotification[] tmp = null;
- int uid = Binder.getCallingUid();
-
- // noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
- == AppOpsManager.MODE_ALLOWED) {
- synchronized (mArchive) {
- tmp = mArchive.getArray(count);
- }
- }
- return tmp;
- }
/**
* Remove notification access for any services that no longer exist.
@@ -548,12 +473,12 @@ public class NotificationManagerService extends INotificationManager.Stub
void disableNonexistentListeners() {
int currentUser = ActivityManager.getCurrentUser();
String flatIn = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
currentUser);
if (!TextUtils.isEmpty(flatIn)) {
if (DBG) Slog.v(TAG, "flat before: " + flatIn);
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = getContext().getPackageManager();
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
new Intent(NotificationListenerService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -589,7 +514,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
if (DBG) Slog.v(TAG, "flat after: " + flatOut);
if (!flatIn.equals(flatOut)) {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
flatOut, currentUser);
}
@@ -603,7 +528,7 @@ public class NotificationManagerService extends INotificationManager.Stub
void rebindListenerServices() {
final int currentUser = ActivityManager.getCurrentUser();
String flat = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
currentUser);
@@ -652,28 +577,6 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- /**
- * Register a listener binder directly with the notification manager.
- *
- * Only works with system callers. Apps should extend
- * {@link android.service.notification.NotificationListenerService}.
- */
- @Override
- public void registerListener(final INotificationListener listener,
- final ComponentName component, final int userid) {
- checkCallerIsSystem();
-
- synchronized (mNotificationList) {
- try {
- NotificationListenerInfo info
- = new NotificationListenerInfo(listener, component, userid, true);
- listener.asBinder().linkToDeath(info, 0);
- mListeners.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- }
/**
* Version of registerListener that takes the name of a
@@ -703,7 +606,7 @@ public class NotificationManagerService extends INotificationManager.Stub
if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener);
mListeners.remove(i);
if (info.connection != null) {
- mContext.unbindService(info.connection);
+ getContext().unbindService(info.connection);
}
}
}
@@ -713,21 +616,25 @@ public class NotificationManagerService extends INotificationManager.Stub
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
R.string.notification_listener_binding_label);
- intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
- mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
try {
if (DBG) Slog.v(TAG, "binding: " + intent);
- if (!mContext.bindServiceAsUser(intent,
+ if (!getContext().bindServiceAsUser(intent,
new ServiceConnection() {
INotificationListener mListener;
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mNotificationList) {
mServicesBinding.remove(servicesBindingTag);
try {
mListener = INotificationListener.Stub.asInterface(service);
- NotificationListenerInfo info = new NotificationListenerInfo(
+ NotificationListenerInfo info
+ = new NotificationListenerInfo(
mListener, name, userid, this);
service.linkToDeath(info, 0);
mListeners.add(info);
@@ -756,28 +663,6 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- /**
- * Remove a listener binder directly
- */
- @Override
- public void unregisterListener(INotificationListener listener, int userid) {
- // no need to check permissions; if your listener binder is in the list,
- // that's proof that you had permission to add it in the first place
-
- synchronized (mNotificationList) {
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (info.listener.asBinder() == listener.asBinder()
- && info.userid == userid) {
- mListeners.remove(i);
- if (info.connection != null) {
- mContext.unbindService(info.connection);
- }
- }
- }
- }
- }
/**
* Remove a listener service for the given user by ComponentName
@@ -794,7 +679,7 @@ public class NotificationManagerService extends INotificationManager.Stub
mListeners.remove(i);
if (info.connection != null) {
try {
- mContext.unbindService(info.connection);
+ getContext().unbindService(info.connection);
} catch (IllegalArgumentException ex) {
// something happened to the service: we think we have a connection
// but it's bogus.
@@ -809,7 +694,7 @@ public class NotificationManagerService extends INotificationManager.Stub
/**
* asynchronously notify all listeners about a new notification
*/
- private void notifyPostedLocked(NotificationRecord n) {
+ void notifyPostedLocked(NotificationRecord n) {
// make a copy in case changes are made to the underlying Notification object
final StatusBarNotification sbn = n.sbn.clone();
for (final NotificationListenerInfo info : mListeners) {
@@ -824,7 +709,7 @@ public class NotificationManagerService extends INotificationManager.Stub
/**
* asynchronously notify all listeners about a removed notification
*/
- private void notifyRemovedLocked(NotificationRecord n) {
+ void notifyRemovedLocked(NotificationRecord n) {
// make a copy in case changes are made to the underlying Notification object
// NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification
final StatusBarNotification sbn_light = n.sbn.cloneLight();
@@ -850,66 +735,7 @@ public class NotificationManagerService extends INotificationManager.Stub
throw new SecurityException("Disallowed call from unknown listener: " + listener);
}
- /**
- * Allow an INotificationListener to simulate a "clear all" operation.
- *
- * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- public void cancelAllNotificationsFromListener(INotificationListener token) {
- NotificationListenerInfo info = checkListenerToken(token);
- long identity = Binder.clearCallingIdentity();
- try {
- cancelAll(info.userid);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
- * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
- *
- * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- public void cancelNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
- NotificationListenerInfo info = checkListenerToken(token);
- long identity = Binder.clearCallingIdentity();
- try {
- cancelNotification(pkg, tag, id, 0,
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
- true,
- info.userid);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- /**
- * Allow an INotificationListener to request the list of outstanding notifications seen by
- * the current user. Useful when starting up, after which point the listener callbacks should
- * be used.
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- public StatusBarNotification[] getActiveNotificationsFromListener(INotificationListener token) {
- NotificationListenerInfo info = checkListenerToken(token);
-
- StatusBarNotification[] result = new StatusBarNotification[0];
- ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
- synchronized (mNotificationList) {
- final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn)) {
- list.add(sbn);
- }
- }
- }
- return list.toArray(result);
- }
// -- end of listener APIs --
@@ -992,8 +818,8 @@ public class NotificationManagerService extends INotificationManager.Stub
return String.format(
"NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d: %s)",
System.identityHashCode(this),
- this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), this.sbn.getTag(),
- this.sbn.getScore(), this.sbn.getNotification());
+ this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
+ this.sbn.getTag(), this.sbn.getScore(), this.sbn.getNotification());
}
}
@@ -1031,9 +857,9 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
- = new StatusBarManagerService.NotificationCallbacks() {
+ private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
+ @Override
public void onSetDisabled(int status) {
synchronized (mNotificationList) {
mDisabledNotifications = status;
@@ -1041,7 +867,7 @@ public class NotificationManagerService extends INotificationManager.Stub
// cancel whatever's going on
long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
@@ -1060,12 +886,14 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ @Override
public void onClearAll() {
// XXX to be totally correct, the caller should tell us which user
// this is for.
cancelAll(ActivityManager.getCurrentUser());
}
+ @Override
public void onNotificationClick(String pkg, String tag, int id) {
// XXX to be totally correct, the caller should tell us which user
// this is for.
@@ -1074,6 +902,7 @@ public class NotificationManagerService extends INotificationManager.Stub
ActivityManager.getCurrentUser());
}
+ @Override
public void onNotificationClear(String pkg, String tag, int id) {
// XXX to be totally correct, the caller should tell us which user
// this is for.
@@ -1082,6 +911,7 @@ public class NotificationManagerService extends INotificationManager.Stub
true, ActivityManager.getCurrentUser());
}
+ @Override
public void onPanelRevealed() {
synchronized (mNotificationList) {
// sound
@@ -1089,7 +919,7 @@ public class NotificationManagerService extends INotificationManager.Stub
long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
@@ -1114,6 +944,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ @Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message) {
Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
@@ -1168,7 +999,7 @@ public class NotificationManagerService extends INotificationManager.Stub
if (packageChanged) {
// We cancel notifications for packages which have just been disabled
try {
- final int enabled = mContext.getPackageManager()
+ final int enabled = getContext().getPackageManager()
.getApplicationEnabledSetting(pkgName);
if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
@@ -1244,7 +1075,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
void observe() {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = getContext().getContentResolver();
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
@@ -1257,7 +1088,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
public void update(Uri uri) {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = getContext().getContentResolver();
if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
boolean pulseEnabled = Settings.System.getInt(resolver,
Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
@@ -1287,28 +1118,24 @@ public class NotificationManagerService extends INotificationManager.Stub
return out;
}
- NotificationManagerService(Context context, StatusBarManagerService statusBar,
- LightsService lights)
- {
- super();
- mContext = context;
- mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+ @Override
+ public void onStart() {
mAm = ActivityManagerNative.getDefault();
- mUserManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
- mToastQueue = new ArrayList<ToastRecord>();
- mHandler = new WorkerHandler();
+ mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
- mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mHandler = new WorkerHandler();
importOldBlockDb();
- mStatusBar = statusBar;
- statusBar.setNotificationCallbacks(mNotificationCallbacks);
+ mStatusBar = getLocalService(StatusBarManagerInternal.class);
+ mStatusBar.setNotificationDelegate(mNotificationDelegate);
- mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
- mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+ final LightsManager lights = getLocalService(LightsManager.class);
+ mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
+ mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
- Resources resources = mContext.getResources();
+ Resources resources = getContext().getResources();
mDefaultNotificationColor = resources.getColor(
R.color.config_defaultNotificationColor);
mDefaultNotificationLedOn = resources.getInteger(
@@ -1330,7 +1157,7 @@ public class NotificationManagerService extends INotificationManager.Stub
// After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this
// flag at least once and we'll go back to 0 after that.
- if (0 == Settings.Global.getInt(mContext.getContentResolver(),
+ if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0)) {
mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
}
@@ -1343,7 +1170,7 @@ public class NotificationManagerService extends INotificationManager.Stub
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiver(mIntentReceiver, filter);
+ getContext().registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -1351,9 +1178,9 @@ public class NotificationManagerService extends INotificationManager.Stub
pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
pkgFilter.addDataScheme("package");
- mContext.registerReceiver(mIntentReceiver, pkgFilter);
+ getContext().registerReceiver(mIntentReceiver, pkgFilter);
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mIntentReceiver, sdFilter);
+ getContext().registerReceiver(mIntentReceiver, sdFilter);
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
@@ -1363,9 +1190,9 @@ public class NotificationManagerService extends INotificationManager.Stub
R.array.config_notificationScorers);
for (String scorerName : notificationScorerNames) {
try {
- Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName);
+ Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName);
NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
- scorer.initialize(mContext);
+ scorer.initialize(getContext());
mScorers.add(scorer);
} catch (ClassNotFoundException e) {
Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
@@ -1375,6 +1202,9 @@ public class NotificationManagerService extends INotificationManager.Stub
Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
}
}
+
+ publishBinderService(Context.NOTIFICATION_SERVICE, mService);
+ publishLocalService(NotificationManagerInternal.class, mInternalService);
}
/**
@@ -1383,12 +1213,12 @@ public class NotificationManagerService extends INotificationManager.Stub
private void importOldBlockDb() {
loadBlockDb();
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = getContext().getPackageManager();
for (String pkg : mBlockedPackages) {
PackageInfo info = null;
try {
info = pm.getPackageInfo(pkg, 0);
- setNotificationsEnabledForPackage(pkg, info.applicationInfo.uid, false);
+ setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
} catch (NameNotFoundException e) {
// forget you
}
@@ -1399,244 +1229,421 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- void systemReady() {
- mAudioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ // no beeping until we're basically done booting
+ mSystemReady = true;
- // no beeping until we're basically done booting
- mSystemReady = true;
+ // Grab our optional AudioService
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
- // make sure our listener services are properly bound
- rebindListenerServices();
+ // make sure our listener services are properly bound
+ rebindListenerServices();
+ }
}
- // Toasts
- // ============================================================================
- public void enqueueToast(String pkg, ITransientNotification callback, int duration)
- {
- if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
+ void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
+ Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
+
+ mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
+ enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
- if (pkg == null || callback == null) {
- Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
- return ;
+ // Now, cancel any outstanding notifications that are part of a just-disabled app
+ if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+ cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
}
+ }
- final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+ private final IBinder mService = new INotificationManager.Stub() {
+ // Toasts
+ // ============================================================================
- if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
- if (!isSystemToast) {
- Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
- return;
+ @Override
+ public void enqueueToast(String pkg, ITransientNotification callback, int duration)
+ {
+ if (DBG) {
+ Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+ + " duration=" + duration);
}
- }
- synchronized (mToastQueue) {
- int callingPid = Binder.getCallingPid();
- long callingId = Binder.clearCallingIdentity();
- try {
- ToastRecord record;
- int index = indexOfToastLocked(pkg, callback);
- // If it's already in the queue, we update it in place, we don't
- // move it to the end of the queue.
- if (index >= 0) {
- record = mToastQueue.get(index);
- record.update(duration);
- } else {
- // Limit the number of toasts that any given package except the android
- // package can enqueue. Prevents DOS attacks and deals with leaks.
- if (!isSystemToast) {
- int count = 0;
- final int N = mToastQueue.size();
- for (int i=0; i<N; i++) {
- final ToastRecord r = mToastQueue.get(i);
- if (r.pkg.equals(pkg)) {
- count++;
- if (count >= MAX_PACKAGE_NOTIFICATIONS) {
- Slog.e(TAG, "Package has already posted " + count
- + " toasts. Not showing more. Package=" + pkg);
- return;
+ if (pkg == null || callback == null) {
+ Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
+ return ;
+ }
+
+ final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+
+ if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
+ if (!isSystemToast) {
+ Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
+ return;
+ }
+ }
+
+ synchronized (mToastQueue) {
+ int callingPid = Binder.getCallingPid();
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ ToastRecord record;
+ int index = indexOfToastLocked(pkg, callback);
+ // If it's already in the queue, we update it in place, we don't
+ // move it to the end of the queue.
+ if (index >= 0) {
+ record = mToastQueue.get(index);
+ record.update(duration);
+ } else {
+ // Limit the number of toasts that any given package except the android
+ // package can enqueue. Prevents DOS attacks and deals with leaks.
+ if (!isSystemToast) {
+ int count = 0;
+ final int N = mToastQueue.size();
+ for (int i=0; i<N; i++) {
+ final ToastRecord r = mToastQueue.get(i);
+ if (r.pkg.equals(pkg)) {
+ count++;
+ if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+ Slog.e(TAG, "Package has already posted " + count
+ + " toasts. Not showing more. Package=" + pkg);
+ return;
+ }
}
- }
+ }
}
+
+ record = new ToastRecord(callingPid, pkg, callback, duration);
+ mToastQueue.add(record);
+ index = mToastQueue.size() - 1;
+ keepProcessAliveLocked(callingPid);
+ }
+ // If it's at index 0, it's the current toast. It doesn't matter if it's
+ // new or just been updated. Call back and tell it to show itself.
+ // If the callback fails, this will remove it from the list, so don't
+ // assume that it's valid after this.
+ if (index == 0) {
+ showNextToastLocked();
}
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+ }
+
+ @Override
+ public void cancelToast(String pkg, ITransientNotification callback) {
+ Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+
+ if (pkg == null || callback == null) {
+ Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
+ return ;
+ }
- record = new ToastRecord(callingPid, pkg, callback, duration);
- mToastQueue.add(record);
- index = mToastQueue.size() - 1;
- keepProcessAliveLocked(callingPid);
+ synchronized (mToastQueue) {
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ int index = indexOfToastLocked(pkg, callback);
+ if (index >= 0) {
+ cancelToastLocked(index);
+ } else {
+ Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
+ + " callback=" + callback);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
- // If it's at index 0, it's the current toast. It doesn't matter if it's
- // new or just been updated. Call back and tell it to show itself.
- // If the callback fails, this will remove it from the list, so don't
- // assume that it's valid after this.
- if (index == 0) {
- showNextToastLocked();
+ }
+ }
+
+ @Override
+ public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
+ Notification notification, int[] idOut, int userId) throws RemoteException {
+ enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(),
+ Binder.getCallingPid(), tag, id, notification, idOut, userId);
+ }
+
+ @Override
+ public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
+ checkCallerIsSystemOrSameApp(pkg);
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
+ // Don't allow client applications to cancel foreground service notis.
+ cancelNotification(pkg, tag, id, 0,
+ Binder.getCallingUid() == Process.SYSTEM_UID
+ ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
+ }
+
+ @Override
+ public void cancelAllNotifications(String pkg, int userId) {
+ checkCallerIsSystemOrSameApp(pkg);
+
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
+
+ // Calling from user space, don't allow the canceling of actively
+ // running foreground services.
+ cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
+ }
+
+ @Override
+ public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
+ checkCallerIsSystem();
+
+ setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
+ }
+
+ /**
+ * Use this when you just want to know if notifications are OK for this package.
+ */
+ @Override
+ public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
+ checkCallerIsSystem();
+ return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
+ == AppOpsManager.MODE_ALLOWED);
+ }
+
+ /**
+ * System-only API for getting a list of current (i.e. not cleared) notifications.
+ *
+ * Requires ACCESS_NOTIFICATIONS which is signature|system.
+ */
+ @Override
+ public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+ // enforce() will ensure the calling uid has the correct permission
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ "NotificationManagerService.getActiveNotifications");
+
+ StatusBarNotification[] tmp = null;
+ int uid = Binder.getCallingUid();
+
+ // noteOp will check to make sure the callingPkg matches the uid
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ synchronized (mNotificationList) {
+ tmp = new StatusBarNotification[mNotificationList.size()];
+ final int N = mNotificationList.size();
+ for (int i=0; i<N; i++) {
+ tmp[i] = mNotificationList.get(i).sbn;
+ }
}
- } finally {
- Binder.restoreCallingIdentity(callingId);
}
+ return tmp;
}
- }
- public void cancelToast(String pkg, ITransientNotification callback) {
- Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+ /**
+ * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+ *
+ * Requires ACCESS_NOTIFICATIONS which is signature|system.
+ */
+ @Override
+ public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+ // enforce() will ensure the calling uid has the correct permission
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ "NotificationManagerService.getHistoricalNotifications");
+
+ StatusBarNotification[] tmp = null;
+ int uid = Binder.getCallingUid();
+
+ // noteOp will check to make sure the callingPkg matches the uid
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ synchronized (mArchive) {
+ tmp = mArchive.getArray(count);
+ }
+ }
+ return tmp;
+ }
- if (pkg == null || callback == null) {
- Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
- return ;
+ /**
+ * Register a listener binder directly with the notification manager.
+ *
+ * Only works with system callers. Apps should extend
+ * {@link android.service.notification.NotificationListenerService}.
+ */
+ @Override
+ public void registerListener(final INotificationListener listener,
+ final ComponentName component, final int userid) {
+ checkCallerIsSystem();
+ registerListenerImpl(listener, component, userid);
}
- synchronized (mToastQueue) {
- long callingId = Binder.clearCallingIdentity();
+ /**
+ * Remove a listener binder directly
+ */
+ @Override
+ public void unregisterListener(INotificationListener listener, int userid) {
+ // no need to check permissions; if your listener binder is in the list,
+ // that's proof that you had permission to add it in the first place
+ unregisterListenerImpl(listener, userid);
+ }
+
+ /**
+ * Allow an INotificationListener to simulate a "clear all" operation.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void cancelAllNotificationsFromListener(INotificationListener token) {
+ NotificationListenerInfo info = checkListenerToken(token);
+ long identity = Binder.clearCallingIdentity();
try {
- int index = indexOfToastLocked(pkg, callback);
- if (index >= 0) {
- cancelToastLocked(index);
- } else {
- Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
- }
+ cancelAll(info.userid);
} finally {
- Binder.restoreCallingIdentity(callingId);
+ Binder.restoreCallingIdentity(identity);
}
}
- }
- private void showNextToastLocked() {
- ToastRecord record = mToastQueue.get(0);
- while (record != null) {
- if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
+ /**
+ * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void cancelNotificationFromListener(INotificationListener token, String pkg,
+ String tag, int id) {
+ NotificationListenerInfo info = checkListenerToken(token);
+ long identity = Binder.clearCallingIdentity();
try {
- record.callback.show();
- scheduleTimeoutLocked(record);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "Object died trying to show notification " + record.callback
- + " in package " + record.pkg);
- // remove it from the list and let the process die
- int index = mToastQueue.indexOf(record);
- if (index >= 0) {
- mToastQueue.remove(index);
- }
- keepProcessAliveLocked(record.pid);
- if (mToastQueue.size() > 0) {
- record = mToastQueue.get(0);
- } else {
- record = null;
+ cancelNotification(pkg, tag, id, 0,
+ Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ true,
+ info.userid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Allow an INotificationListener to request the list of outstanding notifications seen by
+ * the current user. Useful when starting up, after which point the listener callbacks
+ * should be used.
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public StatusBarNotification[] getActiveNotificationsFromListener(
+ INotificationListener token) {
+ NotificationListenerInfo info = checkListenerToken(token);
+
+ StatusBarNotification[] result = new StatusBarNotification[0];
+ ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
+ synchronized (mNotificationList) {
+ final int N = mNotificationList.size();
+ for (int i=0; i<N; i++) {
+ StatusBarNotification sbn = mNotificationList.get(i).sbn;
+ if (info.enabledAndUserMatches(sbn)) {
+ list.add(sbn);
+ }
}
}
+ return list.toArray(result);
}
- }
- private void cancelToastLocked(int index) {
- ToastRecord record = mToastQueue.get(index);
- try {
- record.callback.hide();
- } catch (RemoteException e) {
- Slog.w(TAG, "Object died trying to hide notification " + record.callback
- + " in package " + record.pkg);
- // don't worry about this, we're about to remove it from
- // the list anyway
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump NotificationManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpImpl(pw);
}
- mToastQueue.remove(index);
- keepProcessAliveLocked(record.pid);
- if (mToastQueue.size() > 0) {
- // Show the next one. If the callback fails, this will remove
- // it from the list, so don't assume that the list hasn't changed
- // after this point.
- showNextToastLocked();
+ };
+
+ void dumpImpl(PrintWriter pw) {
+ pw.println("Current Notification Manager state:");
+
+ pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size()
+ + ") enabled for current user:");
+ for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
+ pw.println(" " + cmpt);
}
- }
- private void scheduleTimeoutLocked(ToastRecord r)
- {
- mHandler.removeCallbacksAndMessages(r);
- Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
- long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
- mHandler.sendMessageDelayed(m, delay);
- }
+ pw.println(" Live listeners (" + mListeners.size() + "):");
+ for (NotificationListenerInfo info : mListeners) {
+ pw.println(" " + info.component
+ + " (user " + info.userid + "): " + info.listener
+ + (info.isSystem?" SYSTEM":""));
+ }
+
+ int N;
- private void handleTimeout(ToastRecord record)
- {
- if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
synchronized (mToastQueue) {
- int index = indexOfToastLocked(record.pkg, record.callback);
- if (index >= 0) {
- cancelToastLocked(index);
+ N = mToastQueue.size();
+ if (N > 0) {
+ pw.println(" Toast Queue:");
+ for (int i=0; i<N; i++) {
+ mToastQueue.get(i).dump(pw, " ");
+ }
+ pw.println(" ");
}
+
}
- }
- // lock on mToastQueue
- private int indexOfToastLocked(String pkg, ITransientNotification callback)
- {
- IBinder cbak = callback.asBinder();
- ArrayList<ToastRecord> list = mToastQueue;
- int len = list.size();
- for (int i=0; i<len; i++) {
- ToastRecord r = list.get(i);
- if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
- return i;
+ synchronized (mNotificationList) {
+ N = mNotificationList.size();
+ if (N > 0) {
+ pw.println(" Notification List:");
+ for (int i=0; i<N; i++) {
+ mNotificationList.get(i).dump(pw, " ", getContext());
+ }
+ pw.println(" ");
}
- }
- return -1;
- }
- // lock on mToastQueue
- private void keepProcessAliveLocked(int pid)
- {
- int toastCount = 0; // toasts from this pid
- ArrayList<ToastRecord> list = mToastQueue;
- int N = list.size();
- for (int i=0; i<N; i++) {
- ToastRecord r = list.get(i);
- if (r.pid == pid) {
- toastCount++;
+ N = mLights.size();
+ if (N > 0) {
+ pw.println(" Lights List:");
+ for (int i=0; i<N; i++) {
+ pw.println(" " + mLights.get(i));
+ }
+ pw.println(" ");
}
- }
- try {
- mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
- } catch (RemoteException e) {
- // Shouldn't happen.
- }
- }
- private final class WorkerHandler extends Handler
- {
- @Override
- public void handleMessage(Message msg)
- {
- switch (msg.what)
- {
- case MESSAGE_TIMEOUT:
- handleTimeout((ToastRecord)msg.obj);
+ pw.println(" mSoundNotification=" + mSoundNotification);
+ pw.println(" mVibrateNotification=" + mVibrateNotification);
+ pw.println(" mDisabledNotifications=0x"
+ + Integer.toHexString(mDisabledNotifications));
+ pw.println(" mSystemReady=" + mSystemReady);
+ pw.println(" mArchive=" + mArchive.toString());
+ Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
+ int i=0;
+ while (iter.hasNext()) {
+ pw.println(" " + iter.next());
+ if (++i >= 5) {
+ if (iter.hasNext()) pw.println(" ...");
break;
+ }
}
- }
- }
-
- // Notifications
- // ============================================================================
- public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
- Notification notification, int[] idOut, int userId)
- {
- enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(),
- tag, id, notification, idOut, userId);
- }
-
- private final static int clamp(int x, int low, int high) {
- return (x < low) ? low : ((x > high) ? high : x);
+ }
}
- // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
- // uid/pid of another application)
+ /**
+ * The private API only accessible to the system process.
+ */
+ private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
+ @Override
+ public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int[] idReceived, int userId) {
+ enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification,
+ idReceived, userId);
+ }
+ };
- public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
+ void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int[] idOut, int incomingUserId)
- {
+ int[] idOut, int incomingUserId) {
if (DBG) {
- Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
+ Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ + " notification=" + notification);
}
checkCallerIsSystemOrSameApp(pkg);
final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
@@ -1787,23 +1794,21 @@ public class NotificationManagerService extends INotificationManager.Stub
if (notification.icon != 0) {
if (old != null && old.statusBarKey != null) {
r.statusBarKey = old.statusBarKey;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mStatusBar.updateNotification(r.statusBarKey, n);
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
} else {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
r.statusBarKey = mStatusBar.addNotification(n);
if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
&& canInterrupt) {
mAttentionLight.pulse();
}
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
}
@@ -1816,33 +1821,32 @@ public class NotificationManagerService extends INotificationManager.Stub
} else {
Slog.e(TAG, "Not posting notification with icon==0: " + notification);
if (old != null && old.statusBarKey != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mStatusBar.removeNotification(old.statusBarKey);
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
notifyRemovedLocked(r);
}
// ATTENTION: in a future release we will bail out here
- // so that we do not play sounds, show lights, etc. for invalid notifications
+ // so that we do not play sounds, show lights, etc. for invalid
+ // notifications
Slog.e(TAG, "WARNING: In a future release this will crash the app: "
+ n.getPackageName());
}
// If we're not supposed to beep, vibrate, etc. then don't.
- if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
+ if (((mDisabledNotifications
+ & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (r.getUserId() == UserHandle.USER_ALL ||
(r.getUserId() == userId && r.getUserId() == currentUser))
&& canInterrupt
- && mSystemReady) {
-
- final AudioManager audioManager = (AudioManager) mContext
- .getSystemService(Context.AUDIO_SERVICE);
+ && mSystemReady
+ && mAudioManager != null) {
// sound
@@ -1861,7 +1865,7 @@ public class NotificationManagerService extends INotificationManager.Stub
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
// check to see if the default notification sound is silent
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = getContext().getContentResolver();
hasValidSound = Settings.System.getString(resolver,
Settings.System.NOTIFICATION_SOUND) != null;
} else if (notification.sound != null) {
@@ -1870,7 +1874,8 @@ public class NotificationManagerService extends INotificationManager.Stub
}
if (hasValidSound) {
- boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
+ boolean looping =
+ (notification.flags & Notification.FLAG_INSISTENT) != 0;
int audioStreamType;
if (notification.audioStreamType >= 0) {
audioStreamType = notification.audioStreamType;
@@ -1880,11 +1885,12 @@ public class NotificationManagerService extends INotificationManager.Stub
mSoundNotification = r;
// do not play notifications if stream volume is 0 (typically because
// ringer mode is silent) or if there is a user of exclusive audio focus
- if ((audioManager.getStreamVolume(audioStreamType) != 0)
- && !audioManager.isAudioFocusExclusive()) {
+ if ((mAudioManager.getStreamVolume(audioStreamType) != 0)
+ && !mAudioManager.isAudioFocusExclusive()) {
final long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player =
+ mAudioManager.getRingtonePlayer();
if (player != null) {
player.playAsync(soundUri, user, looping, audioStreamType);
}
@@ -1904,7 +1910,7 @@ public class NotificationManagerService extends INotificationManager.Stub
final boolean convertSoundToVibration =
!hasCustomVibrate
&& hasValidSound
- && (audioManager.getRingerMode()
+ && (mAudioManager.getRingerMode()
== AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
@@ -1912,7 +1918,7 @@ public class NotificationManagerService extends INotificationManager.Stub
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
- && !(audioManager.getRingerMode()
+ && !(mAudioManager.getRingerMode()
== AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotification = r;
@@ -1966,8 +1972,158 @@ public class NotificationManagerService extends INotificationManager.Stub
idOut[0] = id;
}
- private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
- AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+ void registerListenerImpl(final INotificationListener listener,
+ final ComponentName component, final int userid) {
+ synchronized (mNotificationList) {
+ try {
+ NotificationListenerInfo info
+ = new NotificationListenerInfo(listener, component, userid, true);
+ listener.asBinder().linkToDeath(info, 0);
+ mListeners.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ }
+
+ void unregisterListenerImpl(final INotificationListener listener, final int userid) {
+ synchronized (mNotificationList) {
+ final int N = mListeners.size();
+ for (int i=N-1; i>=0; i--) {
+ final NotificationListenerInfo info = mListeners.get(i);
+ if (info.listener.asBinder() == listener.asBinder()
+ && info.userid == userid) {
+ mListeners.remove(i);
+ if (info.connection != null) {
+ getContext().unbindService(info.connection);
+ }
+ }
+ }
+ }
+ }
+
+ void showNextToastLocked() {
+ ToastRecord record = mToastQueue.get(0);
+ while (record != null) {
+ if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
+ try {
+ record.callback.show();
+ scheduleTimeoutLocked(record);
+ return;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Object died trying to show notification " + record.callback
+ + " in package " + record.pkg);
+ // remove it from the list and let the process die
+ int index = mToastQueue.indexOf(record);
+ if (index >= 0) {
+ mToastQueue.remove(index);
+ }
+ keepProcessAliveLocked(record.pid);
+ if (mToastQueue.size() > 0) {
+ record = mToastQueue.get(0);
+ } else {
+ record = null;
+ }
+ }
+ }
+ }
+
+ void cancelToastLocked(int index) {
+ ToastRecord record = mToastQueue.get(index);
+ try {
+ record.callback.hide();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Object died trying to hide notification " + record.callback
+ + " in package " + record.pkg);
+ // don't worry about this, we're about to remove it from
+ // the list anyway
+ }
+ mToastQueue.remove(index);
+ keepProcessAliveLocked(record.pid);
+ if (mToastQueue.size() > 0) {
+ // Show the next one. If the callback fails, this will remove
+ // it from the list, so don't assume that the list hasn't changed
+ // after this point.
+ showNextToastLocked();
+ }
+ }
+
+ private void scheduleTimeoutLocked(ToastRecord r)
+ {
+ mHandler.removeCallbacksAndMessages(r);
+ Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
+ long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+ mHandler.sendMessageDelayed(m, delay);
+ }
+
+ private void handleTimeout(ToastRecord record)
+ {
+ if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
+ synchronized (mToastQueue) {
+ int index = indexOfToastLocked(record.pkg, record.callback);
+ if (index >= 0) {
+ cancelToastLocked(index);
+ }
+ }
+ }
+
+ // lock on mToastQueue
+ int indexOfToastLocked(String pkg, ITransientNotification callback)
+ {
+ IBinder cbak = callback.asBinder();
+ ArrayList<ToastRecord> list = mToastQueue;
+ int len = list.size();
+ for (int i=0; i<len; i++) {
+ ToastRecord r = list.get(i);
+ if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // lock on mToastQueue
+ void keepProcessAliveLocked(int pid)
+ {
+ int toastCount = 0; // toasts from this pid
+ ArrayList<ToastRecord> list = mToastQueue;
+ int N = list.size();
+ for (int i=0; i<N; i++) {
+ ToastRecord r = list.get(i);
+ if (r.pid == pid) {
+ toastCount++;
+ }
+ }
+ try {
+ mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ }
+
+ private final class WorkerHandler extends Handler
+ {
+ @Override
+ public void handleMessage(Message msg)
+ {
+ switch (msg.what)
+ {
+ case MESSAGE_TIMEOUT:
+ handleTimeout((ToastRecord)msg.obj);
+ break;
+ }
+ }
+ }
+
+
+ // Notifications
+ // ============================================================================
+ static int clamp(int x, int low, int high) {
+ return (x < low) ? low : ((x > high) ? high : x);
+ }
+
+ void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+ AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
if (!manager.isEnabled()) {
return;
}
@@ -2001,11 +2157,10 @@ public class NotificationManagerService extends INotificationManager.Stub
// status bar
if (r.getNotification().icon != 0) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mStatusBar.removeNotification(r.statusBarKey);
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
r.statusBarKey = null;
@@ -2017,7 +2172,7 @@ public class NotificationManagerService extends INotificationManager.Stub
mSoundNotification = null;
final long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
@@ -2053,7 +2208,7 @@ public class NotificationManagerService extends INotificationManager.Stub
* Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
* and none of the {@code mustNotHaveFlags}.
*/
- private void cancelNotification(final String pkg, final String tag, final int id,
+ void cancelNotification(final String pkg, final String tag, final int id,
final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
final int userId) {
// In enqueueNotificationInternal notifications are added by scheduling the
@@ -2146,26 +2301,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
- checkCallerIsSystemOrSameApp(pkg);
- userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
- // Don't allow client applications to cancel foreground service notis.
- cancelNotification(pkg, tag, id, 0,
- Binder.getCallingUid() == Process.SYSTEM_UID
- ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
- }
-
- public void cancelAllNotifications(String pkg, int userId) {
- checkCallerIsSystemOrSameApp(pkg);
-
- userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
- // Calling from user space, don't allow the canceling of actively
- // running foreground services.
- cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
- }
// Return true if the UID is a system or phone UID and therefore should not have
// any notifications or toasts blocked.
@@ -2225,7 +2361,7 @@ public class NotificationManagerService extends INotificationManager.Stub
}
// lock on mNotificationList
- private void updateLightsLocked()
+ void updateLightsLocked()
{
// handle notification lights
if (mLedNotification == null) {
@@ -2251,14 +2387,14 @@ public class NotificationManagerService extends INotificationManager.Stub
}
if (mNotificationPulseEnabled) {
// pulse repeatedly
- mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
+ mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
ledOnMS, ledOffMS);
}
}
}
// lock on mNotificationList
- private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
+ int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
{
ArrayList<NotificationRecord> list = mNotificationList;
final int len = list.size();
@@ -2288,81 +2424,4 @@ public class NotificationManagerService extends INotificationManager.Stub
updateLightsLocked();
}
}
-
- // ======================================================================
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump NotificationManager from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- pw.println("Current Notification Manager state:");
-
- pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size()
- + ") enabled for current user:");
- for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
- pw.println(" " + cmpt);
- }
-
- pw.println(" Live listeners (" + mListeners.size() + "):");
- for (NotificationListenerInfo info : mListeners) {
- pw.println(" " + info.component
- + " (user " + info.userid + "): " + info.listener
- + (info.isSystem?" SYSTEM":""));
- }
-
- int N;
-
- synchronized (mToastQueue) {
- N = mToastQueue.size();
- if (N > 0) {
- pw.println(" Toast Queue:");
- for (int i=0; i<N; i++) {
- mToastQueue.get(i).dump(pw, " ");
- }
- pw.println(" ");
- }
-
- }
-
- synchronized (mNotificationList) {
- N = mNotificationList.size();
- if (N > 0) {
- pw.println(" Notification List:");
- for (int i=0; i<N; i++) {
- mNotificationList.get(i).dump(pw, " ", mContext);
- }
- pw.println(" ");
- }
-
- N = mLights.size();
- if (N > 0) {
- pw.println(" Lights List:");
- for (int i=0; i<N; i++) {
- pw.println(" " + mLights.get(i));
- }
- pw.println(" ");
- }
-
- pw.println(" mSoundNotification=" + mSoundNotification);
- pw.println(" mVibrateNotification=" + mVibrateNotification);
- pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
- pw.println(" mSystemReady=" + mSystemReady);
- pw.println(" mArchive=" + mArchive.toString());
- Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
- int i=0;
- while (iter.hasNext()) {
- pw.println(" " + iter.next());
- if (++i >= 5) {
- if (iter.hasNext()) pw.println(" ...");
- break;
- }
- }
-
- }
- }
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 5761f6c..b11ebf5 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -38,10 +38,10 @@ import com.android.internal.content.PackageHelper;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
-import com.android.server.DeviceStorageMonitorService;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
+import com.android.server.LocalServices;
import com.android.server.Watchdog;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -92,6 +92,7 @@ import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -127,7 +128,6 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
-import android.view.WindowManager;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -162,6 +162,7 @@ import libcore.io.Libcore;
import libcore.io.StructStat;
import com.android.internal.R;
+import com.android.server.storage.DeviceStorageMonitorInternal;
/**
* Keep track of all those .apks everywhere.
@@ -1067,6 +1068,12 @@ public class PackageManagerService extends IPackageManager.Stub {
return res;
}
+ private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
+ DisplayManager displayManager = (DisplayManager) context.getSystemService(
+ Context.DISPLAY_SERVICE);
+ displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
+ }
+
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -1114,9 +1121,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mInstaller = installer;
- WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- Display d = wm.getDefaultDisplay();
- d.getMetrics(mMetrics);
+ getDefaultDisplayMetrics(context, mMetrics);
synchronized (mInstallLock) {
// writer
@@ -7339,6 +7344,15 @@ public class PackageManagerService extends IPackageManager.Stub {
return pkgLite.recommendedInstallLocation;
}
+ private long getMemoryLowThreshold() {
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+ if (dsm == null) {
+ return 0L;
+ }
+ return dsm.getMemoryLowThreshold();
+ }
+
/*
* Invoke remote method to get package information and install
* location values. Override install location based on default
@@ -7356,15 +7370,9 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
- final long lowThreshold;
-
- final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
- .getService(DeviceStorageMonitorService.SERVICE);
- if (dsm == null) {
+ final long lowThreshold = getMemoryLowThreshold();
+ if (lowThreshold == 0L) {
Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
- lowThreshold = 0L;
- } else {
- lowThreshold = dsm.getMemoryLowThreshold();
}
try {
@@ -7922,8 +7930,8 @@ public class PackageManagerService extends IPackageManager.Stub {
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
final long lowThreshold;
- final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
- .getService(DeviceStorageMonitorService.SERVICE);
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
if (dsm == null) {
Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
lowThreshold = 0L;
@@ -9738,10 +9746,10 @@ public class PackageManagerService extends IPackageManager.Stub {
clearExternalStorageDataSync(packageName, userId, true);
if (succeeded) {
// invoke DeviceStorageMonitor's update method to clear any notifications
- DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
- ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
+ DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
if (dsm != null) {
- dsm.updateMemory();
+ dsm.checkMemory();
}
}
if(observer != null) {
@@ -11566,12 +11574,17 @@ public class PackageManagerService extends IPackageManager.Stub {
return true;
}
+ @Override
public boolean isStorageLow() {
final long token = Binder.clearCallingIdentity();
try {
- final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
- .getService(DeviceStorageMonitorService.SERVICE);
- return dsm.isMemoryLow();
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+ if (dsm != null) {
+ return dsm.isMemoryLow();
+ } else {
+ return false;
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 60d44c7..b8a78e3 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -16,10 +16,11 @@
package com.android.server.power;
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
-import com.android.server.TwilightService.TwilightState;
+import com.android.server.lights.LightsManager;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
import com.android.server.display.DisplayManagerService;
+import com.android.server.twilight.TwilightState;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -179,10 +180,10 @@ final class DisplayPowerController {
private Handler mCallbackHandler;
// The lights service.
- private final LightsService mLights;
+ private final LightsManager mLights;
// The twilight service.
- private final TwilightService mTwilight;
+ private final TwilightManager mTwilight;
// The display manager.
private final DisplayManagerService mDisplayManager;
@@ -351,7 +352,7 @@ final class DisplayPowerController {
* Creates the display power controller.
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
- LightsService lights, TwilightService twilight, SensorManager sensorManager,
+ LightsManager lights, TwilightManager twilight, SensorManager sensorManager,
DisplayManagerService displayManager,
SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
@@ -528,7 +529,7 @@ final class DisplayPowerController {
private void initialize() {
mPowerState = new DisplayPowerState(
new ElectronBeam(mDisplayManager), mDisplayBlanker,
- mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
+ mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -1368,8 +1369,7 @@ final class DisplayPowerController {
}
};
- private final TwilightService.TwilightListener mTwilightListener =
- new TwilightService.TwilightListener() {
+ private final TwilightListener mTwilightListener = new TwilightListener() {
@Override
public void onTwilightStateChanged() {
mTwilightChanged = true;
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index fa318f8..42af4b4 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -16,7 +16,7 @@
package com.android.server.power;
-import com.android.server.LightsService;
+import com.android.server.lights.Light;
import android.os.AsyncTask;
import android.os.Handler;
@@ -56,7 +56,7 @@ final class DisplayPowerState {
private final Choreographer mChoreographer;
private final ElectronBeam mElectronBeam;
private final DisplayBlanker mDisplayBlanker;
- private final LightsService.Light mBacklight;
+ private final Light mBacklight;
private final PhotonicModulator mPhotonicModulator;
private boolean mScreenOn;
@@ -72,7 +72,7 @@ final class DisplayPowerState {
private Runnable mCleanListener;
public DisplayPowerState(ElectronBeam electronBean,
- DisplayBlanker displayBlanker, LightsService.Light backlight) {
+ DisplayBlanker displayBlanker, Light backlight) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mElectronBeam = electronBean;
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index da9548f..13f55e2 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -20,10 +20,11 @@ import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.server.BatteryService;
import com.android.server.EventLogTags;
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
+import com.android.server.lights.LightsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+import com.android.server.twilight.TwilightManager;
import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
@@ -168,7 +169,7 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
private Context mContext;
- private LightsService mLightsService;
+ private LightsManager mLightsManager;
private BatteryService mBatteryService;
private DisplayManagerService mDisplayManagerService;
private IBatteryStats mBatteryStats;
@@ -181,7 +182,7 @@ public final class PowerManagerService extends IPowerManager.Stub
private WirelessChargerDetector mWirelessChargerDetector;
private SettingsObserver mSettingsObserver;
private DreamManagerService mDreamManager;
- private LightsService.Light mAttentionLight;
+ private Light mAttentionLight;
private final Object mLock = new Object();
@@ -396,11 +397,11 @@ public final class PowerManagerService extends IPowerManager.Stub
* Initialize the power manager.
* Must be called before any other functions within the power manager are called.
*/
- public void init(Context context, LightsService ls,
- ActivityManagerService am, BatteryService bs, IBatteryStats bss,
+ public void init(Context context, LightsManager ls,
+ BatteryService bs, IBatteryStats bss,
IAppOpsService appOps, DisplayManagerService dm) {
mContext = context;
- mLightsService = ls;
+ mLightsManager = ls;
mBatteryService = bs;
mBatteryStats = bss;
mAppOps = appOps;
@@ -427,12 +428,12 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
- public void systemReady(TwilightService twilight, DreamManagerService dreamManager) {
+ public void systemReady(TwilightManager twilight, DreamManagerService dreamManager) {
synchronized (mLock) {
mSystemReady = true;
mDreamManager = dreamManager;
- PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
@@ -448,7 +449,7 @@ public final class PowerManagerService extends IPowerManager.Stub
// The display power controller runs on the power manager service's
// own handler thread to ensure timely operation.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
- mContext, mNotifier, mLightsService, twilight, sensorManager,
+ mContext, mNotifier, mLightsManager, twilight, sensorManager,
mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
mDisplayPowerControllerCallbacks, mHandler);
@@ -456,7 +457,7 @@ public final class PowerManagerService extends IPowerManager.Stub
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
- mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
+ mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
// Register for broadcasts from other components of the system.
IntentFilter filter = new IntentFilter();
@@ -2061,7 +2062,7 @@ public final class PowerManagerService extends IPowerManager.Stub
}
private void setAttentionLightInternal(boolean on, int color) {
- LightsService.Light light;
+ Light light;
synchronized (mLock) {
if (!mSystemReady) {
return;
@@ -2070,7 +2071,7 @@ public final class PowerManagerService extends IPowerManager.Stub
}
// Control light outside of lock.
- light.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+ light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
}
/**
diff --git a/services/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/java/com/android/server/statusbar/StatusBarManagerInternal.java
new file mode 100644
index 0000000..4f75189
--- /dev/null
+++ b/services/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.statusbar;
+
+import com.android.server.notification.NotificationDelegate;
+
+import android.os.IBinder;
+import android.service.notification.StatusBarNotification;
+
+public interface StatusBarManagerInternal {
+ void setNotificationDelegate(NotificationDelegate delegate);
+ IBinder addNotification(StatusBarNotification notification);
+ void updateNotification(IBinder key, StatusBarNotification notification);
+ void removeNotification(IBinder key);
+}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/statusbar/StatusBarManagerService.java
index f207c08..2ae467e 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -14,26 +14,28 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.statusbar;
import android.app.StatusBarManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationDelegate;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
@@ -51,31 +53,31 @@ import java.util.Map;
public class StatusBarManagerService extends IStatusBarService.Stub
implements WindowManagerService.OnHardKeyboardStatusChangeListener
{
- static final String TAG = "StatusBarManagerService";
- static final boolean SPEW = false;
-
- final Context mContext;
- final WindowManagerService mWindowManager;
- Handler mHandler = new Handler();
- NotificationCallbacks mNotificationCallbacks;
- volatile IStatusBar mBar;
- StatusBarIconList mIcons = new StatusBarIconList();
- HashMap<IBinder,StatusBarNotification> mNotifications
+ private static final String TAG = "StatusBarManagerService";
+ private static final boolean SPEW = false;
+
+ private final Context mContext;
+ private final WindowManagerService mWindowManager;
+ private Handler mHandler = new Handler();
+ private NotificationDelegate mNotificationDelegate;
+ private volatile IStatusBar mBar;
+ private StatusBarIconList mIcons = new StatusBarIconList();
+ private HashMap<IBinder,StatusBarNotification> mNotifications
= new HashMap<IBinder,StatusBarNotification>();
// for disabling the status bar
- final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
- IBinder mSysUiVisToken = new Binder();
- int mDisabled = 0;
+ private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+ private IBinder mSysUiVisToken = new Binder();
+ private int mDisabled = 0;
- Object mLock = new Object();
+ private Object mLock = new Object();
// encompasses lights-out mode and other flags defined on View
- int mSystemUiVisibility = 0;
- boolean mMenuVisible = false;
- int mImeWindowVis = 0;
- int mImeBackDisposition;
- IBinder mImeToken = null;
- int mCurrentUserId;
+ private int mSystemUiVisibility = 0;
+ private boolean mMenuVisible = false;
+ private int mImeWindowVis = 0;
+ private int mImeBackDisposition;
+ private IBinder mImeToken = null;
+ private int mCurrentUserId;
private class DisableRecord implements IBinder.DeathRecipient {
int userId;
@@ -90,16 +92,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
- public interface NotificationCallbacks {
- void onSetDisabled(int status);
- void onClearAll();
- void onNotificationClick(String pkg, String tag, int id);
- void onNotificationClear(String pkg, String tag, int id);
- void onPanelRevealed();
- void onNotificationError(String pkg, String tag, int id,
- int uid, int initialPid, String message);
- }
-
/**
* Construct the service, add the status bar view to the window manager
*/
@@ -110,15 +102,74 @@ public class StatusBarManagerService extends IStatusBarService.Stub
final Resources res = context.getResources();
mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
- }
- public void setNotificationCallbacks(NotificationCallbacks listener) {
- mNotificationCallbacks = listener;
+ LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
}
+ /**
+ * Private API used by NotificationManagerService.
+ */
+ private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
+ @Override
+ public void setNotificationDelegate(NotificationDelegate delegate) {
+ synchronized (mNotifications) {
+ mNotificationDelegate = delegate;
+ }
+ }
+
+ @Override
+ public IBinder addNotification(StatusBarNotification notification) {
+ synchronized (mNotifications) {
+ IBinder key = new Binder();
+ mNotifications.put(key, notification);
+ if (mBar != null) {
+ try {
+ mBar.addNotification(key, notification);
+ } catch (RemoteException ex) {
+ }
+ }
+ return key;
+ }
+ }
+
+ @Override
+ public void updateNotification(IBinder key, StatusBarNotification notification) {
+ synchronized (mNotifications) {
+ if (!mNotifications.containsKey(key)) {
+ throw new IllegalArgumentException("updateNotification key not found: " + key);
+ }
+ mNotifications.put(key, notification);
+ if (mBar != null) {
+ try {
+ mBar.updateNotification(key, notification);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void removeNotification(IBinder key) {
+ synchronized (mNotifications) {
+ final StatusBarNotification n = mNotifications.remove(key);
+ if (n == null) {
+ Slog.e(TAG, "removeNotification key not found: " + key);
+ return;
+ }
+ if (mBar != null) {
+ try {
+ mBar.removeNotification(key);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+ };
+
// ================================================================================
// From IStatusBarService
// ================================================================================
+ @Override
public void expandNotificationsPanel() {
enforceExpandStatusBar();
@@ -130,6 +181,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void collapsePanels() {
enforceExpandStatusBar();
@@ -141,6 +193,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void expandSettingsPanel() {
enforceExpandStatusBar();
@@ -152,6 +205,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void disable(int what, IBinder token, String pkg) {
disableInternal(mCurrentUserId, what, token, pkg);
}
@@ -177,7 +231,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
mDisabled = net;
mHandler.post(new Runnable() {
public void run() {
- mNotificationCallbacks.onSetDisabled(net);
+ mNotificationDelegate.onSetDisabled(net);
}
});
if (mBar != null) {
@@ -189,6 +243,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
String contentDescription) {
enforceStatusBar();
@@ -214,6 +269,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void setIconVisibility(String slot, boolean visible) {
enforceStatusBar();
@@ -241,6 +297,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void removeIcon(String slot) {
enforceStatusBar();
@@ -265,6 +322,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
* Hide or show the on-screen Menu key. Only call this from the window manager, typically in
* response to a window with FLAG_NEEDS_MENU_KEY set.
*/
+ @Override
public void topAppWindowChanged(final boolean menuVisible) {
enforceStatusBar();
@@ -285,6 +343,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
enforceStatusBar();
@@ -312,6 +371,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void setSystemUiVisibility(int vis, int mask) {
// also allows calls from window manager which is in this process.
enforceStatusBarService();
@@ -344,6 +404,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
}
+ @Override
public void setHardKeyboardEnabled(final boolean enabled) {
mHandler.post(new Runnable() {
public void run() {
@@ -426,6 +487,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
// ================================================================================
// Callbacks from the status bar service.
// ================================================================================
+ @Override
public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
int switches[], List<IBinder> binders) {
@@ -458,86 +520,64 @@ public class StatusBarManagerService extends IStatusBarService.Stub
* The status bar service should call this each time the user brings the panel from
* invisible to visible in order to clear the notification light.
*/
+ @Override
public void onPanelRevealed() {
enforceStatusBarService();
-
- // tell the notification manager to turn off the lights.
- mNotificationCallbacks.onPanelRevealed();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // tell the notification manager to turn off the lights.
+ mNotificationDelegate.onPanelRevealed();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onNotificationClick(String pkg, String tag, int id) {
enforceStatusBarService();
-
- mNotificationCallbacks.onNotificationClick(pkg, tag, id);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onNotificationClick(pkg, tag, id);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message) {
enforceStatusBarService();
-
- // WARNING: this will call back into us to do the remove. Don't hold any locks.
- mNotificationCallbacks.onNotificationError(pkg, tag, id, uid, initialPid, message);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // WARNING: this will call back into us to do the remove. Don't hold any locks.
+ mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onNotificationClear(String pkg, String tag, int id) {
enforceStatusBarService();
-
- mNotificationCallbacks.onNotificationClear(pkg, tag, id);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onNotificationClear(pkg, tag, id);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onClearAllNotifications() {
enforceStatusBarService();
-
- mNotificationCallbacks.onClearAll();
- }
-
- // ================================================================================
- // Callbacks for NotificationManagerService.
- // ================================================================================
- public IBinder addNotification(StatusBarNotification notification) {
- synchronized (mNotifications) {
- IBinder key = new Binder();
- mNotifications.put(key, notification);
- if (mBar != null) {
- try {
- mBar.addNotification(key, notification);
- } catch (RemoteException ex) {
- }
- }
- return key;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onClearAll();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
- public void updateNotification(IBinder key, StatusBarNotification notification) {
- synchronized (mNotifications) {
- if (!mNotifications.containsKey(key)) {
- throw new IllegalArgumentException("updateNotification key not found: " + key);
- }
- mNotifications.put(key, notification);
- if (mBar != null) {
- try {
- mBar.updateNotification(key, notification);
- } catch (RemoteException ex) {
- }
- }
- }
- }
-
- public void removeNotification(IBinder key) {
- synchronized (mNotifications) {
- final StatusBarNotification n = mNotifications.remove(key);
- if (n == null) {
- Slog.e(TAG, "removeNotification key not found: " + key);
- return;
- }
- if (mBar != null) {
- try {
- mBar.removeNotification(key);
- } catch (RemoteException ex) {
- }
- }
- }
- }
// ================================================================================
// Can be called from any thread
diff --git a/services/java/com/android/server/storage/DeviceStorageMonitorInternal.java b/services/java/com/android/server/storage/DeviceStorageMonitorInternal.java
new file mode 100644
index 0000000..a91a81b
--- /dev/null
+++ b/services/java/com/android/server/storage/DeviceStorageMonitorInternal.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.storage;
+
+public interface DeviceStorageMonitorInternal {
+ boolean isMemoryLow();
+ long getMemoryLowThreshold();
+ void checkMemory();
+}
+
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/storage/DeviceStorageMonitorService.java
index 016c561..8805084 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.storage;
+
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
import android.app.Notification;
import android.app.NotificationManager;
@@ -29,8 +32,8 @@ import android.os.Binder;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
@@ -66,13 +69,13 @@ import java.io.PrintWriter;
* settings parameter with a default value of 2MB), the free memory is
* logged to the event log.
*/
-public class DeviceStorageMonitorService extends Binder {
- private static final String TAG = "DeviceStorageMonitorService";
+public class DeviceStorageMonitorService extends SystemService {
+ static final String TAG = "DeviceStorageMonitorService";
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = false;
+ static final boolean DEBUG = false;
+ static final boolean localLOGV = false;
- private static final int DEVICE_MEMORY_WHAT = 1;
+ static final int DEVICE_MEMORY_WHAT = 1;
private static final int MONITOR_INTERVAL = 1; //in minutes
private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
@@ -84,9 +87,8 @@ public class DeviceStorageMonitorService extends Binder {
private long mFreeMemAfterLastCacheClear; // on /data
private long mLastReportedFreeMem;
private long mLastReportedFreeMemTime;
- private boolean mLowMemFlag=false;
+ boolean mLowMemFlag=false;
private boolean mMemFullFlag=false;
- private Context mContext;
private ContentResolver mResolver;
private long mTotalMemory; // on /data
private StatFs mDataFileStats;
@@ -98,19 +100,19 @@ public class DeviceStorageMonitorService extends Binder {
private static final File CACHE_PATH = Environment.getDownloadCacheDirectory();
private long mThreadStartTime = -1;
- private boolean mClearSucceeded = false;
- private boolean mClearingCache;
+ boolean mClearSucceeded = false;
+ boolean mClearingCache;
private Intent mStorageLowIntent;
private Intent mStorageOkIntent;
private Intent mStorageFullIntent;
private Intent mStorageNotFullIntent;
private CachePackageDataObserver mClearCacheObserver;
- private final CacheFileDeletedObserver mCacheFileDeletedObserver;
+ private CacheFileDeletedObserver mCacheFileDeletedObserver;
private static final int _TRUE = 1;
private static final int _FALSE = 0;
// This is the raw threshold that has been set at which we consider
// storage to be low.
- private long mMemLowThreshold;
+ long mMemLowThreshold;
// This is the threshold at which we start trying to flush caches
// to get below the low threshold limit. It is less than the low
// threshold; we will allow storage to get a bit beyond the limit
@@ -126,13 +128,13 @@ public class DeviceStorageMonitorService extends Binder {
/**
* This string is used for ServiceManager access to this class.
*/
- public static final String SERVICE = "devicestoragemonitor";
+ static final String SERVICE = "devicestoragemonitor";
/**
* Handler that checks the amount of disk space on the device and sends a
* notification if the device runs low on disk space
*/
- Handler mHandler = new Handler() {
+ private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//don't handle an invalid message
@@ -144,7 +146,7 @@ public class DeviceStorageMonitorService extends Binder {
}
};
- class CachePackageDataObserver extends IPackageDataObserver.Stub {
+ private class CachePackageDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(String packageName, boolean succeeded) {
mClearSucceeded = succeeded;
mClearingCache = false;
@@ -154,7 +156,7 @@ public class DeviceStorageMonitorService extends Binder {
}
}
- private final void restatDataDir() {
+ private void restatDataDir() {
try {
mDataFileStats.restat(DATA_PATH.getAbsolutePath());
mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
@@ -206,7 +208,7 @@ public class DeviceStorageMonitorService extends Binder {
}
}
- private final void clearCache() {
+ private void clearCache() {
if (mClearCacheObserver == null) {
// Lazy instantiation
mClearCacheObserver = new CachePackageDataObserver();
@@ -223,7 +225,7 @@ public class DeviceStorageMonitorService extends Binder {
}
}
- private final void checkMemory(boolean checkCache) {
+ void checkMemory(boolean checkCache) {
//if the thread that was started to clear cache is still running do nothing till its
//finished clearing cache. Ideally this flag could be modified by clearCache
// and should be accessed via a lock but even if it does this test will fail now and
@@ -300,7 +302,7 @@ public class DeviceStorageMonitorService extends Binder {
postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
}
- private void postCheckMemoryMsg(boolean clearCache, long delay) {
+ void postCheckMemoryMsg(boolean clearCache, long delay) {
// Remove queued messages
mHandler.removeMessages(DEVICE_MEMORY_WHAT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
@@ -312,10 +314,10 @@ public class DeviceStorageMonitorService extends Binder {
* Constructor to run service. initializes the disk space threshold value
* and posts an empty message to kickstart the process.
*/
- public DeviceStorageMonitorService(Context context) {
+ @Override
+ public void onCreate(Context context) {
mLastReportedFreeMemTime = 0;
- mContext = context;
- mResolver = mContext.getContentResolver();
+ mResolver = context.getContentResolver();
//create StatFs object
mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
@@ -331,9 +333,12 @@ public class DeviceStorageMonitorService extends Binder {
mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ }
+ @Override
+ public void onStart() {
// cache storage thresholds
- final StorageManager sm = StorageManager.from(context);
+ final StorageManager sm = StorageManager.from(getContext());
mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
@@ -345,6 +350,78 @@ public class DeviceStorageMonitorService extends Binder {
mCacheFileDeletedObserver = new CacheFileDeletedObserver();
mCacheFileDeletedObserver.startWatching();
+
+ publishBinderService(SERVICE, mRemoteService);
+ publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
+ }
+
+ private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
+ @Override
+ public void checkMemory() {
+ // force an early check
+ postCheckMemoryMsg(true, 0);
+ }
+
+ @Override
+ public boolean isMemoryLow() {
+ return mLowMemFlag;
+ }
+
+ @Override
+ public long getMemoryLowThreshold() {
+ return mMemLowThreshold;
+ }
+ };
+
+ private final IBinder mRemoteService = new Binder() {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpImpl(pw);
+ }
+ };
+
+ void dumpImpl(PrintWriter pw) {
+ final Context context = getContext();
+
+ pw.println("Current DeviceStorageMonitor state:");
+
+ pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(context, mFreeMem));
+ pw.print(" mTotalMemory=");
+ pw.println(Formatter.formatFileSize(context, mTotalMemory));
+
+ pw.print(" mFreeMemAfterLastCacheClear=");
+ pw.println(Formatter.formatFileSize(context, mFreeMemAfterLastCacheClear));
+
+ pw.print(" mLastReportedFreeMem=");
+ pw.print(Formatter.formatFileSize(context, mLastReportedFreeMem));
+ pw.print(" mLastReportedFreeMemTime=");
+ TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
+ pw.println();
+
+ pw.print(" mLowMemFlag="); pw.print(mLowMemFlag);
+ pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
+
+ pw.print(" mClearSucceeded="); pw.print(mClearSucceeded);
+ pw.print(" mClearingCache="); pw.println(mClearingCache);
+
+ pw.print(" mMemLowThreshold=");
+ pw.print(Formatter.formatFileSize(context, mMemLowThreshold));
+ pw.print(" mMemFullThreshold=");
+ pw.println(Formatter.formatFileSize(context, mMemFullThreshold));
+
+ pw.print(" mMemCacheStartTrimThreshold=");
+ pw.print(Formatter.formatFileSize(context, mMemCacheStartTrimThreshold));
+ pw.print(" mMemCacheTrimToThreshold=");
+ pw.println(Formatter.formatFileSize(context, mMemCacheTrimToThreshold));
}
/**
@@ -352,7 +429,8 @@ public class DeviceStorageMonitorService extends Binder {
* an error dialog indicating low disk space and launch the Installer
* application
*/
- private final void sendNotification() {
+ private void sendNotification() {
+ final Context context = getContext();
if(localLOGV) Slog.i(TAG, "Sending low memory notification");
//log the event to event log with the amount of free storage(in bytes) left on the device
EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
@@ -363,86 +441,58 @@ public class DeviceStorageMonitorService extends Binder {
lowMemIntent.putExtra("memory", mFreeMem);
lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager mNotificationMgr =
- (NotificationManager)mContext.getSystemService(
+ (NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
- CharSequence title = mContext.getText(
+ CharSequence title = context.getText(
com.android.internal.R.string.low_internal_storage_view_title);
- CharSequence details = mContext.getText(
+ CharSequence details = context.getText(
com.android.internal.R.string.low_internal_storage_view_text);
- PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0, lowMemIntent, 0,
+ PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0,
null, UserHandle.CURRENT);
Notification notification = new Notification();
notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
notification.tickerText = title;
notification.flags |= Notification.FLAG_NO_CLEAR;
- notification.setLatestEventInfo(mContext, title, details, intent);
+ notification.setLatestEventInfo(context, title, details, intent);
mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
- mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+ context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
}
/**
* Cancels low storage notification and sends OK intent.
*/
- private final void cancelNotification() {
+ private void cancelNotification() {
+ final Context context = getContext();
if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
NotificationManager mNotificationMgr =
- (NotificationManager)mContext.getSystemService(
+ (NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
//cancel notification since memory has been freed
mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL);
- mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
- mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
+ context.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+ context.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
}
/**
* Send a notification when storage is full.
*/
- private final void sendFullNotification() {
+ private void sendFullNotification() {
if(localLOGV) Slog.i(TAG, "Sending memory full notification");
- mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+ getContext().sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
}
/**
* Cancels memory full notification and sends "not full" intent.
*/
- private final void cancelFullNotification() {
+ private void cancelFullNotification() {
if(localLOGV) Slog.i(TAG, "Canceling memory full notification");
- mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
- mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
+ getContext().removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+ getContext().sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
}
- public void updateMemory() {
- int callingUid = getCallingUid();
- if(callingUid != Process.SYSTEM_UID) {
- return;
- }
- // force an early check
- postCheckMemoryMsg(true, 0);
- }
-
- /**
- * Callable from other things in the system service to obtain the low memory
- * threshold.
- *
- * @return low memory threshold in bytes
- */
- public long getMemoryLowThreshold() {
- return mMemLowThreshold;
- }
-
- /**
- * Callable from other things in the system process to check whether memory
- * is low.
- *
- * @return true is memory is low
- */
- public boolean isMemoryLow() {
- return mLowMemFlag;
- }
-
- public static class CacheFileDeletedObserver extends FileObserver {
+ private static class CacheFileDeletedObserver extends FileObserver {
public CacheFileDeletedObserver() {
super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE);
}
@@ -452,40 +502,4 @@ public class DeviceStorageMonitorService extends Binder {
EventLogTags.writeCacheFileDeleted(path);
}
}
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
-
- pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- pw.println("Current DeviceStorageMonitor state:");
- pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem));
- pw.print(" mTotalMemory=");
- pw.println(Formatter.formatFileSize(mContext, mTotalMemory));
- pw.print(" mFreeMemAfterLastCacheClear=");
- pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear));
- pw.print(" mLastReportedFreeMem=");
- pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem));
- pw.print(" mLastReportedFreeMemTime=");
- TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
- pw.println();
- pw.print(" mLowMemFlag="); pw.print(mLowMemFlag);
- pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
- pw.print(" mClearSucceeded="); pw.print(mClearSucceeded);
- pw.print(" mClearingCache="); pw.println(mClearingCache);
- pw.print(" mMemLowThreshold=");
- pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold));
- pw.print(" mMemFullThreshold=");
- pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold));
- pw.print(" mMemCacheStartTrimThreshold=");
- pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold));
- pw.print(" mMemCacheTrimToThreshold=");
- pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold));
- }
}
diff --git a/services/java/com/android/server/twilight/TwilightListener.java b/services/java/com/android/server/twilight/TwilightListener.java
new file mode 100644
index 0000000..29ead44
--- /dev/null
+++ b/services/java/com/android/server/twilight/TwilightListener.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.twilight;
+
+public interface TwilightListener {
+ void onTwilightStateChanged();
+} \ No newline at end of file
diff --git a/services/java/com/android/server/twilight/TwilightManager.java b/services/java/com/android/server/twilight/TwilightManager.java
new file mode 100644
index 0000000..b3de58b
--- /dev/null
+++ b/services/java/com/android/server/twilight/TwilightManager.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.twilight;
+
+import android.os.Handler;
+
+public interface TwilightManager {
+ void registerListener(TwilightListener listener, Handler handler);
+ TwilightState getCurrentState();
+}
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/twilight/TwilightService.java
index 0356faa..8feb97b 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/java/com/android/server/twilight/TwilightService.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.twilight;
+
+import com.android.server.SystemService;
+import com.android.server.TwilightCalculator;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -34,9 +37,7 @@ import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Slog;
-import java.text.DateFormat;
import java.util.ArrayList;
-import java.util.Date;
import java.util.Iterator;
import libcore.util.Objects;
@@ -47,78 +48,88 @@ import libcore.util.Objects;
* Used by the UI mode manager and other components to adjust night mode
* effects based on sunrise and sunset.
*/
-public final class TwilightService {
- private static final String TAG = "TwilightService";
-
- private static final boolean DEBUG = false;
-
- private static final String ACTION_UPDATE_TWILIGHT_STATE =
+public final class TwilightService extends SystemService {
+ static final String TAG = "TwilightService";
+ static final boolean DEBUG = false;
+ static final String ACTION_UPDATE_TWILIGHT_STATE =
"com.android.server.action.UPDATE_TWILIGHT_STATE";
- private final Context mContext;
- private final AlarmManager mAlarmManager;
- private final LocationManager mLocationManager;
- private final LocationHandler mLocationHandler;
+ final Object mLock = new Object();
- private final Object mLock = new Object();
+ AlarmManager mAlarmManager;
+ LocationManager mLocationManager;
+ LocationHandler mLocationHandler;
- private final ArrayList<TwilightListenerRecord> mListeners =
+ final ArrayList<TwilightListenerRecord> mListeners =
new ArrayList<TwilightListenerRecord>();
- private boolean mSystemReady;
+ TwilightState mTwilightState;
- private TwilightState mTwilightState;
+ @Override
+ public void onStart() {
+ mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ mLocationManager = (LocationManager) getContext().getSystemService(
+ Context.LOCATION_SERVICE);
+ mLocationHandler = new LocationHandler();
- public TwilightService(Context context) {
- mContext = context;
+ IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
+ getContext().registerReceiver(mUpdateLocationReceiver, filter);
- mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
- mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
- mLocationHandler = new LocationHandler();
+ publishLocalService(TwilightManager.class, mService);
}
- void systemReady() {
- synchronized (mLock) {
- mSystemReady = true;
+ private static class TwilightListenerRecord implements Runnable {
+ private final TwilightListener mListener;
+ private final Handler mHandler;
- IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
- mContext.registerReceiver(mUpdateLocationReceiver, filter);
+ public TwilightListenerRecord(TwilightListener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
- if (!mListeners.isEmpty()) {
- mLocationHandler.enableLocationUpdates();
- }
+ public void postUpdate() {
+ mHandler.post(this);
}
- }
- /**
- * Gets the current twilight state.
- *
- * @return The current twilight state, or null if no information is available.
- */
- public TwilightState getCurrentState() {
- synchronized (mLock) {
- return mTwilightState;
+ @Override
+ public void run() {
+ mListener.onTwilightStateChanged();
}
+
}
- /**
- * Listens for twilight time.
- *
- * @param listener The listener.
- * @param handler The handler on which to post calls into the listener.
- */
- public void registerListener(TwilightListener listener, Handler handler) {
- synchronized (mLock) {
- mListeners.add(new TwilightListenerRecord(listener, handler));
+ private final TwilightManager mService = new TwilightManager() {
+ /**
+ * Gets the current twilight state.
+ *
+ * @return The current twilight state, or null if no information is available.
+ */
+ @Override
+ public TwilightState getCurrentState() {
+ synchronized (mLock) {
+ return mTwilightState;
+ }
+ }
- if (mSystemReady && mListeners.size() == 1) {
- mLocationHandler.enableLocationUpdates();
+ /**
+ * Listens for twilight time.
+ *
+ * @param listener The listener.
+ */
+ @Override
+ public void registerListener(TwilightListener listener, Handler handler) {
+ synchronized (mLock) {
+ mListeners.add(new TwilightListenerRecord(listener, handler));
+
+ if (mListeners.size() == 1) {
+ mLocationHandler.enableLocationUpdates();
+ }
}
}
- }
+ };
private void setTwilightState(TwilightState state) {
synchronized (mLock) {
@@ -128,9 +139,10 @@ public final class TwilightService {
}
mTwilightState = state;
- int count = mListeners.size();
- for (int i = 0; i < count; i++) {
- mListeners.get(i).post();
+
+ final int listenerLen = mListeners.size();
+ for (int i = 0; i < listenerLen; i++) {
+ mListeners.get(i).postUpdate();
}
}
}
@@ -162,124 +174,6 @@ public final class TwilightService {
return distance >= totalAccuracy;
}
- /**
- * Describes whether it is day or night.
- * This object is immutable.
- */
- public static final class TwilightState {
- private final boolean mIsNight;
- private final long mYesterdaySunset;
- private final long mTodaySunrise;
- private final long mTodaySunset;
- private final long mTomorrowSunrise;
-
- TwilightState(boolean isNight,
- long yesterdaySunset,
- long todaySunrise, long todaySunset,
- long tomorrowSunrise) {
- mIsNight = isNight;
- mYesterdaySunset = yesterdaySunset;
- mTodaySunrise = todaySunrise;
- mTodaySunset = todaySunset;
- mTomorrowSunrise = tomorrowSunrise;
- }
-
- /**
- * Returns true if it is currently night time.
- */
- public boolean isNight() {
- return mIsNight;
- }
-
- /**
- * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
- */
- public long getYesterdaySunset() {
- return mYesterdaySunset;
- }
-
- /**
- * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTodaySunrise() {
- return mTodaySunrise;
- }
-
- /**
- * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
- */
- public long getTodaySunset() {
- return mTodaySunset;
- }
-
- /**
- * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTomorrowSunrise() {
- return mTomorrowSunrise;
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof TwilightState && equals((TwilightState)o);
- }
-
- public boolean equals(TwilightState other) {
- return other != null
- && mIsNight == other.mIsNight
- && mYesterdaySunset == other.mYesterdaySunset
- && mTodaySunrise == other.mTodaySunrise
- && mTodaySunset == other.mTodaySunset
- && mTomorrowSunrise == other.mTomorrowSunrise;
- }
-
- @Override
- public int hashCode() {
- return 0; // don't care
- }
-
- @Override
- public String toString() {
- DateFormat f = DateFormat.getDateTimeInstance();
- return "{TwilightState: isNight=" + mIsNight
- + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
- + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
- + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
- + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
- + "}";
- }
- }
-
- /**
- * Listener for changes in twilight state.
- */
- public interface TwilightListener {
- public void onTwilightStateChanged();
- }
-
- private static final class TwilightListenerRecord implements Runnable {
- private final TwilightListener mListener;
- private final Handler mHandler;
-
- public TwilightListenerRecord(TwilightListener listener, Handler handler) {
- mListener = listener;
- mHandler = handler;
- }
-
- public void post() {
- mHandler.post(this);
- }
-
- @Override
- public void run() {
- mListener.onTwilightStateChanged();
- }
- }
-
private final class LocationHandler extends Handler {
private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
@@ -518,11 +412,12 @@ public final class TwilightService {
}
Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ getContext(), 0, updateIntent, 0);
mAlarmManager.cancel(pendingIntent);
mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent);
}
- };
+ }
private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
@Override
diff --git a/services/java/com/android/server/twilight/TwilightState.java b/services/java/com/android/server/twilight/TwilightState.java
new file mode 100644
index 0000000..91e24d7
--- /dev/null
+++ b/services/java/com/android/server/twilight/TwilightState.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.twilight;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+/**
+ * Describes whether it is day or night.
+ * This object is immutable.
+ */
+public class TwilightState {
+ private final boolean mIsNight;
+ private final long mYesterdaySunset;
+ private final long mTodaySunrise;
+ private final long mTodaySunset;
+ private final long mTomorrowSunrise;
+
+ TwilightState(boolean isNight,
+ long yesterdaySunset,
+ long todaySunrise, long todaySunset,
+ long tomorrowSunrise) {
+ mIsNight = isNight;
+ mYesterdaySunset = yesterdaySunset;
+ mTodaySunrise = todaySunrise;
+ mTodaySunset = todaySunset;
+ mTomorrowSunrise = tomorrowSunrise;
+ }
+
+ /**
+ * Returns true if it is currently night time.
+ */
+ public boolean isNight() {
+ return mIsNight;
+ }
+
+ /**
+ * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never sets.
+ */
+ public long getYesterdaySunset() {
+ return mYesterdaySunset;
+ }
+
+ /**
+ * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never rises.
+ */
+ public long getTodaySunrise() {
+ return mTodaySunrise;
+ }
+
+ /**
+ * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never sets.
+ */
+ public long getTodaySunset() {
+ return mTodaySunset;
+ }
+
+ /**
+ * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never rises.
+ */
+ public long getTomorrowSunrise() {
+ return mTomorrowSunrise;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof TwilightState && equals((TwilightState)o);
+ }
+
+ public boolean equals(TwilightState other) {
+ return other != null
+ && mIsNight == other.mIsNight
+ && mYesterdaySunset == other.mYesterdaySunset
+ && mTodaySunrise == other.mTodaySunrise
+ && mTodaySunset == other.mTodaySunset
+ && mTomorrowSunrise == other.mTomorrowSunrise;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0; // don't care
+ }
+
+ @Override
+ public String toString() {
+ DateFormat f = DateFormat.getDateTimeInstance();
+ return "{TwilightState: isNight=" + mIsNight
+ + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
+ + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
+ + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
+ + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+ + "}";
+ }
+}
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 5a60de0..c1a3646 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -53,6 +53,7 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -287,12 +288,7 @@ public class UsbDeviceManager {
}
private static boolean containsFunction(String functions, String function) {
- int index = functions.indexOf(function);
- if (index < 0) return false;
- if (index > 0 && functions.charAt(index - 1) != ',') return false;
- int charAfter = index + function.length();
- if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
- return true;
+ return Arrays.asList(functions.split(",")).contains(function);
}
private final class UsbHandler extends Handler {
diff --git a/wifi/java/android/net/wifi/NetworkUpdateResult.java b/services/java/com/android/server/wifi/NetworkUpdateResult.java
index 234bbe1..63cc33f 100644
--- a/wifi/java/android/net/wifi/NetworkUpdateResult.java
+++ b/services/java/com/android/server/wifi/NetworkUpdateResult.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
diff --git a/wifi/java/android/net/wifi/StateChangeResult.java b/services/java/com/android/server/wifi/StateChangeResult.java
index c334b91..7d2f2b4 100644
--- a/wifi/java/android/net/wifi/StateChangeResult.java
+++ b/services/java/com/android/server/wifi/StateChangeResult.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
- package android.net.wifi;
+package com.android.server.wifi;
+
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiSsid;
/**
* Stores supplicant state change information passed from WifiMonitor to
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/services/java/com/android/server/wifi/SupplicantStateTracker.java
index e76eb17..f8048ff 100644
--- a/wifi/java/android/net/wifi/SupplicantStateTracker.java
+++ b/services/java/com/android/server/wifi/SupplicantStateTracker.java
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import android.net.wifi.StateChangeResult;
import android.content.Context;
import android.content.Intent;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
diff --git a/wifi/java/android/net/wifi/WifiApConfigStore.java b/services/java/com/android/server/wifi/WifiApConfigStore.java
index e675ad4..5e28fcf 100644
--- a/wifi/java/android/net/wifi/WifiApConfigStore.java
+++ b/services/java/com/android/server/wifi/WifiApConfigStore.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import android.content.Context;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
import android.os.Handler;
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/services/java/com/android/server/wifi/WifiConfigStore.java
index e45c2e7..6ce4732 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/services/java/com/android/server/wifi/WifiConfigStore.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import android.content.Context;
import android.content.Intent;
@@ -24,13 +24,18 @@ import android.net.NetworkUtils;
import android.net.NetworkInfo.DetailedState;
import android.net.ProxyProperties;
import android.net.RouteInfo;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.IpAssignment;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.ProxySettings;
import android.net.wifi.WifiConfiguration.Status;
-import android.net.wifi.NetworkUpdateResult;
import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
+import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.WpsResult;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
@@ -113,7 +118,7 @@ import java.util.List;
* - Maintain a list of configured networks for quick access
*
*/
-class WifiConfigStore {
+public class WifiConfigStore {
private Context mContext;
private static final String TAG = "WifiConfigStore";
@@ -167,50 +172,19 @@ class WifiConfigStore {
*/
public static final String OLD_PRIVATE_KEY_NAME = "private_key";
- /**
- * String representing the keystore OpenSSL ENGINE's ID.
- */
- public static final String ENGINE_ID_KEYSTORE = "keystore";
-
- /**
- * String representing the keystore URI used for wpa_supplicant.
- */
- public static final String KEYSTORE_URI = "keystore://";
-
- /**
- * String to set the engine value to when it should be enabled.
- */
- public static final String ENGINE_ENABLE = "1";
-
- /**
- * String to set the engine value to when it should be disabled.
- */
- public static final String ENGINE_DISABLE = "0";
-
- public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
- public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE;
- public static final String EAP_KEY = "eap";
- public static final String PHASE2_KEY = "phase2";
- public static final String IDENTITY_KEY = "identity";
- public static final String ANON_IDENTITY_KEY = "anonymous_identity";
- public static final String PASSWORD_KEY = "password";
- public static final String CLIENT_CERT_KEY = "client_cert";
- public static final String CA_CERT_KEY = "ca_cert";
- public static final String SUBJECT_MATCH_KEY = "subject_match";
- public static final String ENGINE_KEY = "engine";
- public static final String ENGINE_ID_KEY = "engine_id";
- public static final String PRIVATE_KEY_ID_KEY = "key_id";
- public static final String OPP_KEY_CACHING = "proactive_key_caching";
-
/** This represents an empty value of an enterprise field.
* NULL is used at wpa_supplicant to indicate an empty value
*/
static final String EMPTY_VALUE = "NULL";
/** Internal use only */
- private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] { EAP_KEY,
- PHASE2_KEY, IDENTITY_KEY, ANON_IDENTITY_KEY, PASSWORD_KEY, CLIENT_CERT_KEY,
- CA_CERT_KEY, SUBJECT_MATCH_KEY, ENGINE_KEY, ENGINE_ID_KEY, PRIVATE_KEY_ID_KEY };
+ private static final String[] ENTERPRISE_CONFIG_SUPPLICANT_KEYS = new String[] {
+ WifiEnterpriseConfig.EAP_KEY, WifiEnterpriseConfig.PHASE2_KEY,
+ WifiEnterpriseConfig.IDENTITY_KEY, WifiEnterpriseConfig.ANON_IDENTITY_KEY,
+ WifiEnterpriseConfig.PASSWORD_KEY, WifiEnterpriseConfig.CLIENT_CERT_KEY,
+ WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY,
+ WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY,
+ WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY };
private final LocalLog mLocalLog;
private final WpaConfigFileObserver mFileObserver;
@@ -1663,7 +1637,7 @@ class WifiConfigStore {
// initializeSoftwareKeystoreFlag(config.enterpriseConfig, mKeyStore);
}
- private String removeDoubleQuotes(String string) {
+ private static String removeDoubleQuotes(String string) {
int length = string.length();
if ((length > 1) && (string.charAt(0) == '"')
&& (string.charAt(length - 1) == '"')) {
@@ -1672,11 +1646,11 @@ class WifiConfigStore {
return string;
}
- private String convertToQuotedString(String string) {
+ private static String convertToQuotedString(String string) {
return "\"" + string + "\"";
}
- private String makeString(BitSet set, String[] strings) {
+ private static String makeString(BitSet set, String[] strings) {
StringBuffer buf = new StringBuffer();
int nextSetBit = -1;
@@ -1782,8 +1756,8 @@ class WifiConfigStore {
}
}
- // Certificate and privake key management for EnterpriseConfig
- boolean needsKeyStore(WifiEnterpriseConfig config) {
+ // Certificate and private key management for EnterpriseConfig
+ static boolean needsKeyStore(WifiEnterpriseConfig config) {
// Has no keys to be installed
if (config.getClientCertificate() == null && config.getCaCertificate() == null)
return false;
@@ -1798,7 +1772,7 @@ class WifiConfigStore {
return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm());
}
- boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) {
+ static boolean needsSoftwareBackedKeyStore(WifiEnterpriseConfig config) {
String client = config.getClientCertificateAlias();
if (!TextUtils.isEmpty(client)) {
// a valid client certificate is configured
@@ -1968,28 +1942,31 @@ class WifiConfigStore {
}
}
- config.setFieldValue(ENGINE_KEY, ENGINE_ENABLE);
- config.setFieldValue(ENGINE_ID_KEY, ENGINE_ID_KEYSTORE);
+ config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ENABLE);
+ config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY,
+ WifiEnterpriseConfig.ENGINE_ID_KEYSTORE);
/*
* The old key started with the keystore:// URI prefix, but we don't
* need that anymore. Trim it off if it exists.
*/
final String keyName;
- if (oldPrivateKey.startsWith(KEYSTORE_URI)) {
- keyName = new String(oldPrivateKey.substring(KEYSTORE_URI.length()));
+ if (oldPrivateKey.startsWith(WifiEnterpriseConfig.KEYSTORE_URI)) {
+ keyName = new String(
+ oldPrivateKey.substring(WifiEnterpriseConfig.KEYSTORE_URI.length()));
} else {
keyName = oldPrivateKey;
}
- config.setFieldValue(PRIVATE_KEY_ID_KEY, keyName);
+ config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, keyName);
- mWifiNative.setNetworkVariable(netId, ENGINE_KEY, config.getFieldValue(ENGINE_KEY, ""));
+ mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_KEY,
+ config.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY, ""));
- mWifiNative.setNetworkVariable(netId, ENGINE_ID_KEY,
- config.getFieldValue(ENGINE_ID_KEY, ""));
+ mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.ENGINE_ID_KEY,
+ config.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, ""));
- mWifiNative.setNetworkVariable(netId, PRIVATE_KEY_ID_KEY,
- config.getFieldValue(PRIVATE_KEY_ID_KEY, ""));
+ mWifiNative.setNetworkVariable(netId, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY,
+ config.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, ""));
// Remove old private_key string so we don't run this again.
mWifiNative.setNetworkVariable(netId, OLD_PRIVATE_KEY_NAME, EMPTY_VALUE);
@@ -2019,4 +1996,6 @@ class WifiConfigStore {
}
}
}
+
}
+
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java
index a3d514e..8766826 100644
--- a/services/java/com/android/server/wifi/WifiController.java
+++ b/services/java/com/android/server/wifi/WifiController.java
@@ -30,7 +30,6 @@ import android.net.wifi.WifiManager;
import static android.net.wifi.WifiManager.WIFI_MODE_FULL;
import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF;
import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY;
-import android.net.wifi.WifiStateMachine;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/services/java/com/android/server/wifi/WifiMonitor.java
index a18954c..0761c11 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/services/java/com/android/server/wifi/WifiMonitor.java
@@ -14,18 +14,22 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import android.net.NetworkInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pProvDiscEvent;
-import android.net.wifi.p2p.WifiP2pService.P2pStatus;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.os.Message;
import android.util.Log;
+import com.android.server.wifi.p2p.WifiP2pService.P2pStatus;
+
import com.android.internal.util.Protocol;
import com.android.internal.util.StateMachine;
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/services/java/com/android/server/wifi/WifiNative.java
index c2f278a..49c6d7d 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/services/java/com/android/server/wifi/WifiNative.java
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
+import android.net.wifi.BatchedScanSettings;
+import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pGroup;
import android.text.TextUtils;
diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/java/com/android/server/wifi/WifiNotificationController.java
index a9206e0..ec6aa37 100644
--- a/services/java/com/android/server/wifi/WifiNotificationController.java
+++ b/services/java/com/android/server/wifi/WifiNotificationController.java
@@ -28,7 +28,6 @@ import android.database.ContentObserver;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateMachine;
import android.os.Handler;
import android.os.Message;
import android.os.UserHandle;
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index 4b5c567..4342272 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -38,8 +38,6 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.ProxySettings;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.net.wifi.WifiStateMachine;
-import android.net.wifi.WifiWatchdogStateMachine;
import android.os.Binder;
import android.os.Handler;
import android.os.Messenger;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/services/java/com/android/server/wifi/WifiStateMachine.java
index 149f08d..4f68a54 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/services/java/com/android/server/wifi/WifiStateMachine.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
@@ -52,9 +52,19 @@ import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.wifi.BatchedScanResult;
+import android.net.wifi.BatchedScanSettings;
+import android.net.wifi.RssiPacketCountInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.WpsResult;
import android.net.wifi.WpsResult.Status;
import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.p2p.WifiP2pService;
import android.os.BatteryStats;
import android.os.Bundle;
import android.os.IBinder;
@@ -80,6 +90,7 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.net.BaseNetworkObserver;
+import com.android.server.wifi.p2p.WifiP2pService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/services/java/com/android/server/wifi/WifiWatchdogStateMachine.java
index c2823e8..725036a 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/services/java/com/android/server/wifi/WifiWatchdogStateMachine.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net.wifi;
+package com.android.server.wifi;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -26,6 +26,9 @@ import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.wifi.RssiPacketCountInfo;
+import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
@@ -94,8 +97,6 @@ public class WifiWatchdogStateMachine extends StateMachine {
static final int POOR_LINK_DETECTED = BASE + 21;
static final int GOOD_LINK_DETECTED = BASE + 22;
- public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
-
/*
* RSSI levels as used by notification icon
* Level 4 -55 <= RSSI
@@ -440,7 +441,7 @@ public class WifiWatchdogStateMachine extends StateMachine {
} else {
mPoorNetworkDetectionEnabled = getSettingsGlobalBoolean(mContentResolver,
Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
- DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED);
+ WifiManager.DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED);
}
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/services/java/com/android/server/wifi/p2p/WifiP2pService.java
index 7803f7d..a00882d 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/services/java/com/android/server/wifi/p2p/WifiP2pService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.net.wifi.p2p;
+package com.android.server.wifi.p2p;
import android.app.AlertDialog;
import android.app.Notification;
@@ -32,11 +32,18 @@ import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.NetworkInfo;
import android.net.NetworkUtils;
-import android.net.wifi.WifiMonitor;
-import android.net.wifi.WifiNative;
-import android.net.wifi.WifiStateMachine;
import android.net.wifi.WpsInfo;
+import android.net.wifi.p2p.IWifiP2pManager;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pGroupList;
import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pProvDiscEvent;
+import android.net.wifi.p2p.WifiP2pWfdInfo;
import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
@@ -66,6 +73,9 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.server.wifi.WifiMonitor;
+import com.android.server.wifi.WifiNative;
+import com.android.server.wifi.WifiStateMachine;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 98e9b30..a98b1c3 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES:= \
com_android_server_input_InputApplicationHandle.cpp \
com_android_server_input_InputManagerService.cpp \
com_android_server_input_InputWindowHandle.cpp \
- com_android_server_LightsService.cpp \
+ com_android_server_lights_LightsService.cpp \
com_android_server_power_PowerManagerService.cpp \
com_android_server_SerialService.cpp \
com_android_server_SystemServer.cpp \
diff --git a/services/jni/com_android_server_LightsService.cpp b/services/jni/com_android_server_lights_LightsService.cpp
index 401e1aa..ea03cfa 100644
--- a/services/jni/com_android_server_LightsService.cpp
+++ b/services/jni/com_android_server_lights_LightsService.cpp
@@ -134,7 +134,7 @@ static JNINativeMethod method_table[] = {
int register_android_server_LightsService(JNIEnv *env)
{
- return jniRegisterNativeMethods(env, "com/android/server/LightsService",
+ return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
method_table, NELEM(method_table));
}
diff --git a/wifi/java/android/net/wifi/SupplicantState.java b/wifi/java/android/net/wifi/SupplicantState.java
index 4a2037d..369d3a8 100644
--- a/wifi/java/android/net/wifi/SupplicantState.java
+++ b/wifi/java/android/net/wifi/SupplicantState.java
@@ -194,7 +194,8 @@ public enum SupplicantState implements Parcelable {
}
}
- static boolean isConnecting(SupplicantState state) {
+ /** @hide */
+ public static boolean isConnecting(SupplicantState state) {
switch(state) {
case AUTHENTICATING:
case ASSOCIATING:
@@ -216,7 +217,8 @@ public enum SupplicantState implements Parcelable {
}
}
- static boolean isDriverActive(SupplicantState state) {
+ /** @hide */
+ public static boolean isDriverActive(SupplicantState state) {
switch(state) {
case DISCONNECTED:
case DORMANT:
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 87afa88..6562462 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -499,7 +499,7 @@ public class WifiConfiguration implements Parcelable {
* @throws IllegalStateException if config is invalid for key id generation
* @hide
*/
- String getKeyIdForCredentials(WifiConfiguration current) {
+ public String getKeyIdForCredentials(WifiConfiguration current) {
String keyMgmt = null;
try {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 452d84b..69be2cf 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -33,12 +33,67 @@ import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
-/**
+/**
* Enterprise configuration details for Wi-Fi. Stores details about the EAP method
* and any associated credentials.
*/
public class WifiEnterpriseConfig implements Parcelable {
+ /** @hide */
+ public static final String EMPTY_VALUE = "NULL";
+ /** @hide */
+ public static final String EAP_KEY = "eap";
+ /** @hide */
+ public static final String PHASE2_KEY = "phase2";
+ /** @hide */
+ public static final String IDENTITY_KEY = "identity";
+ /** @hide */
+ public static final String ANON_IDENTITY_KEY = "anonymous_identity";
+ /** @hide */
+ public static final String PASSWORD_KEY = "password";
+ /** @hide */
+ public static final String SUBJECT_MATCH_KEY = "subject_match";
+ /** @hide */
+ public static final String OPP_KEY_CACHING = "proactive_key_caching";
+ /**
+ * String representing the keystore OpenSSL ENGINE's ID.
+ * @hide
+ */
+ public static final String ENGINE_ID_KEYSTORE = "keystore";
+
+ /**
+ * String representing the keystore URI used for wpa_supplicant.
+ * @hide
+ */
+ public static final String KEYSTORE_URI = "keystore://";
+
+ /**
+ * String to set the engine value to when it should be enabled.
+ * @hide
+ */
+ public static final String ENGINE_ENABLE = "1";
+
+ /**
+ * String to set the engine value to when it should be disabled.
+ * @hide
+ */
+ public static final String ENGINE_DISABLE = "0";
+
+ /** @hide */
+ public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+ /** @hide */
+ public static final String CLIENT_CERT_PREFIX = KEYSTORE_URI + Credentials.USER_CERTIFICATE;
+ /** @hide */
+ public static final String CLIENT_CERT_KEY = "client_cert";
+ /** @hide */
+ public static final String CA_CERT_KEY = "ca_cert";
+ /** @hide */
+ public static final String ENGINE_KEY = "engine";
+ /** @hide */
+ public static final String ENGINE_ID_KEY = "engine_id";
+ /** @hide */
+ public static final String PRIVATE_KEY_ID_KEY = "key_id";
+
private HashMap<String, String> mFields = new HashMap<String, String>();
private X509Certificate mCaCert;
private PrivateKey mClientPrivateKey;
@@ -189,15 +244,17 @@ public class WifiEnterpriseConfig implements Parcelable {
public static final int GTC = 4;
private static final String PREFIX = "auth=";
/** @hide */
- public static final String[] strings = {WifiConfigStore.EMPTY_VALUE, "PAP", "MSCHAP",
+ public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
"MSCHAPV2", "GTC" };
/** Prevent initialization */
private Phase2() {}
}
- /** Internal use only */
- HashMap<String, String> getFields() {
+ /** Internal use only
+ * @hide
+ */
+ public HashMap<String, String> getFields() {
return mFields;
}
@@ -214,8 +271,8 @@ public class WifiEnterpriseConfig implements Parcelable {
case Eap.PWD:
case Eap.TLS:
case Eap.TTLS:
- mFields.put(WifiConfigStore.EAP_KEY, Eap.strings[eapMethod]);
- mFields.put(WifiConfigStore.OPP_KEY_CACHING, "1");
+ mFields.put(EAP_KEY, Eap.strings[eapMethod]);
+ mFields.put(OPP_KEY_CACHING, "1");
break;
default:
throw new IllegalArgumentException("Unknown EAP method");
@@ -227,7 +284,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return eap method configured
*/
public int getEapMethod() {
- String eapMethod = mFields.get(WifiConfigStore.EAP_KEY);
+ String eapMethod = mFields.get(EAP_KEY);
return getStringIndex(Eap.strings, eapMethod, Eap.NONE);
}
@@ -243,14 +300,14 @@ public class WifiEnterpriseConfig implements Parcelable {
public void setPhase2Method(int phase2Method) {
switch (phase2Method) {
case Phase2.NONE:
- mFields.put(WifiConfigStore.PHASE2_KEY, WifiConfigStore.EMPTY_VALUE);
+ mFields.put(PHASE2_KEY, EMPTY_VALUE);
break;
/** Valid methods */
case Phase2.PAP:
case Phase2.MSCHAP:
case Phase2.MSCHAPV2:
case Phase2.GTC:
- mFields.put(WifiConfigStore.PHASE2_KEY, convertToQuotedString(
+ mFields.put(PHASE2_KEY, convertToQuotedString(
Phase2.PREFIX + Phase2.strings[phase2Method]));
break;
default:
@@ -263,7 +320,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return a phase 2 method defined at {@link Phase2}
* */
public int getPhase2Method() {
- String phase2Method = removeDoubleQuotes(mFields.get(WifiConfigStore.PHASE2_KEY));
+ String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY));
// Remove auth= prefix
if (phase2Method.startsWith(Phase2.PREFIX)) {
phase2Method = phase2Method.substring(Phase2.PREFIX.length());
@@ -276,7 +333,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @param identity
*/
public void setIdentity(String identity) {
- setFieldValue(WifiConfigStore.IDENTITY_KEY, identity, "");
+ setFieldValue(IDENTITY_KEY, identity, "");
}
/**
@@ -284,7 +341,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return the identity
*/
public String getIdentity() {
- return getFieldValue(WifiConfigStore.IDENTITY_KEY, "");
+ return getFieldValue(IDENTITY_KEY, "");
}
/**
@@ -293,14 +350,14 @@ public class WifiEnterpriseConfig implements Parcelable {
* @param anonymousIdentity the anonymous identity
*/
public void setAnonymousIdentity(String anonymousIdentity) {
- setFieldValue(WifiConfigStore.ANON_IDENTITY_KEY, anonymousIdentity, "");
+ setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, "");
}
/** Get the anonymous identity
* @return anonymous identity
*/
public String getAnonymousIdentity() {
- return getFieldValue(WifiConfigStore.ANON_IDENTITY_KEY, "");
+ return getFieldValue(ANON_IDENTITY_KEY, "");
}
/**
@@ -308,7 +365,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @param password the password
*/
public void setPassword(String password) {
- setFieldValue(WifiConfigStore.PASSWORD_KEY, password, "");
+ setFieldValue(PASSWORD_KEY, password, "");
}
/**
@@ -318,7 +375,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* framework, returns "*".
*/
public String getPassword() {
- return getFieldValue(WifiConfigStore.PASSWORD_KEY, "");
+ return getFieldValue(PASSWORD_KEY, "");
}
/**
@@ -331,7 +388,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @hide
*/
public void setCaCertificateAlias(String alias) {
- setFieldValue(WifiConfigStore.CA_CERT_KEY, alias, WifiConfigStore.CA_CERT_PREFIX);
+ setFieldValue(CA_CERT_KEY, alias, CA_CERT_PREFIX);
}
/**
@@ -340,7 +397,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @hide
*/
public String getCaCertificateAlias() {
- return getFieldValue(WifiConfigStore.CA_CERT_KEY, WifiConfigStore.CA_CERT_PREFIX);
+ return getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
}
/**
@@ -381,8 +438,7 @@ public class WifiEnterpriseConfig implements Parcelable {
mCaCert = null;
}
- /**
- * Set Client certificate alias.
+ /** Set Client certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
* a certificate
@@ -391,16 +447,15 @@ public class WifiEnterpriseConfig implements Parcelable {
* @hide
*/
public void setClientCertificateAlias(String alias) {
- setFieldValue(WifiConfigStore.CLIENT_CERT_KEY, alias, WifiConfigStore.CLIENT_CERT_PREFIX);
- setFieldValue(WifiConfigStore.PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
+ setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX);
+ setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY);
// Also, set engine parameters
if (TextUtils.isEmpty(alias)) {
- mFields.put(WifiConfigStore.ENGINE_KEY, WifiConfigStore.ENGINE_DISABLE);
- mFields.put(WifiConfigStore.ENGINE_ID_KEY, WifiConfigStore.EMPTY_VALUE);
+ mFields.put(ENGINE_KEY, ENGINE_DISABLE);
+ mFields.put(ENGINE_ID_KEY, EMPTY_VALUE);
} else {
- mFields.put(WifiConfigStore.ENGINE_KEY, WifiConfigStore.ENGINE_ENABLE);
- mFields.put(WifiConfigStore.ENGINE_ID_KEY,
- convertToQuotedString(WifiConfigStore.ENGINE_ID_KEYSTORE));
+ mFields.put(ENGINE_KEY, ENGINE_ENABLE);
+ mFields.put(ENGINE_ID_KEY, convertToQuotedString(ENGINE_ID_KEYSTORE));
}
}
@@ -410,7 +465,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @hide
*/
public String getClientCertificateAlias() {
- return getFieldValue(WifiConfigStore.CLIENT_CERT_KEY, WifiConfigStore.CLIENT_CERT_PREFIX);
+ return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
}
/**
@@ -472,7 +527,7 @@ public class WifiEnterpriseConfig implements Parcelable {
* @param subjectMatch substring to be matched
*/
public void setSubjectMatch(String subjectMatch) {
- setFieldValue(WifiConfigStore.SUBJECT_MATCH_KEY, subjectMatch, "");
+ setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, "");
}
/**
@@ -480,20 +535,20 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return the subject match string
*/
public String getSubjectMatch() {
- return getFieldValue(WifiConfigStore.SUBJECT_MATCH_KEY, "");
+ return getFieldValue(SUBJECT_MATCH_KEY, "");
}
/** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
String getKeyId(WifiEnterpriseConfig current) {
- String eap = mFields.get(WifiConfigStore.EAP_KEY);
- String phase2 = mFields.get(WifiConfigStore.PHASE2_KEY);
+ String eap = mFields.get(EAP_KEY);
+ String phase2 = mFields.get(PHASE2_KEY);
// If either eap or phase2 are not initialized, use current config details
if (TextUtils.isEmpty((eap))) {
- eap = current.mFields.get(WifiConfigStore.EAP_KEY);
+ eap = current.mFields.get(EAP_KEY);
}
if (TextUtils.isEmpty(phase2)) {
- phase2 = current.mFields.get(WifiConfigStore.PHASE2_KEY);
+ phase2 = current.mFields.get(PHASE2_KEY);
}
return eap + "_" + phase2;
}
@@ -532,10 +587,10 @@ public class WifiEnterpriseConfig implements Parcelable {
* @return value
* @hide
*/
- String getFieldValue(String key, String prefix) {
+ public String getFieldValue(String key, String prefix) {
String value = mFields.get(key);
// Uninitialized or known to be empty after reading from supplicant
- if (TextUtils.isEmpty(value) || WifiConfigStore.EMPTY_VALUE.equals(value)) return "";
+ if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
value = removeDoubleQuotes(value);
if (value.startsWith(prefix)) {
@@ -549,10 +604,11 @@ public class WifiEnterpriseConfig implements Parcelable {
* @param key into the hash
* @param value to be set
* @param prefix an optional value to be prefixed to actual value
+ * @hide
*/
- private void setFieldValue(String key, String value, String prefix) {
+ public void setFieldValue(String key, String value, String prefix) {
if (TextUtils.isEmpty(value)) {
- mFields.put(key, WifiConfigStore.EMPTY_VALUE);
+ mFields.put(key, EMPTY_VALUE);
} else {
mFields.put(key, convertToQuotedString(prefix + value));
}
@@ -567,7 +623,7 @@ public class WifiEnterpriseConfig implements Parcelable {
*/
public void setFieldValue(String key, String value) {
if (TextUtils.isEmpty(value)) {
- mFields.put(key, WifiConfigStore.EMPTY_VALUE);
+ mFields.put(key, EMPTY_VALUE);
} else {
mFields.put(key, convertToQuotedString(value));
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index dea0c6c..6a13067 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -78,7 +78,8 @@ public class WifiInfo implements Parcelable {
*/
private boolean mMeteredHint;
- WifiInfo() {
+ /** @hide */
+ public WifiInfo() {
mWifiSsid = null;
mBSSID = null;
mNetworkId = -1;
@@ -105,7 +106,8 @@ public class WifiInfo implements Parcelable {
}
}
- void setSSID(WifiSsid wifiSsid) {
+ /** @hide */
+ public void setSSID(WifiSsid wifiSsid) {
mWifiSsid = wifiSsid;
}
@@ -133,7 +135,8 @@ public class WifiInfo implements Parcelable {
return mWifiSsid;
}
- void setBSSID(String BSSID) {
+ /** @hide */
+ public void setBSSID(String BSSID) {
mBSSID = BSSID;
}
@@ -156,7 +159,8 @@ public class WifiInfo implements Parcelable {
return mRssi;
}
- void setRssi(int rssi) {
+ /** @hide */
+ public void setRssi(int rssi) {
mRssi = rssi;
}
@@ -169,15 +173,17 @@ public class WifiInfo implements Parcelable {
return mLinkSpeed;
}
- void setLinkSpeed(int linkSpeed) {
+ /** @hide */
+ public void setLinkSpeed(int linkSpeed) {
this.mLinkSpeed = linkSpeed;
}
/**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
+ * @hide
*/
- void setMacAddress(String macAddress) {
+ public void setMacAddress(String macAddress) {
this.mMacAddress = macAddress;
}
@@ -195,7 +201,8 @@ public class WifiInfo implements Parcelable {
return mMeteredHint;
}
- void setNetworkId(int id) {
+ /** @hide */
+ public void setNetworkId(int id) {
mNetworkId = id;
}
@@ -218,11 +225,13 @@ public class WifiInfo implements Parcelable {
return mSupplicantState;
}
- void setSupplicantState(SupplicantState state) {
+ /** @hide */
+ public void setSupplicantState(SupplicantState state) {
mSupplicantState = state;
}
- void setInetAddress(InetAddress address) {
+ /** @hide */
+ public void setInetAddress(InetAddress address) {
mIpAddress = address;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ae1fbf7..aabe007 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -522,6 +522,9 @@ public class WifiManager {
/** @hide */
public static final int DATA_ACTIVITY_INOUT = 0x03;
+ /** @hide */
+ public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
+
/* Maximum number of active locks we allow.
* This limit was added to prevent apps from creating a ridiculous number
* of locks and crashing the system by overflowing the global ref table.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 482d9cb..b019fd7 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -60,7 +60,8 @@ public class WifiP2pConfig implements Parcelable {
wps.setup = WpsInfo.PBC;
}
- void invalidate() {
+ /** @hide */
+ public void invalidate() {
deviceAddress = "";
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 7196c1b..a0cb035 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -126,7 +126,7 @@ public class WifiP2pDevice implements Parcelable {
"config_methods=(0x[0-9a-fA-F]+) " +
"dev_capab=(0x[0-9a-fA-F]+) " +
"group_capab=(0x[0-9a-fA-F]+)" +
- "( wfd_dev_info=0x000006([0-9a-fA-F]{12}))?"
+ "( wfd_dev_info=0x([0-9a-fA-F]{12}))?"
);
/** 2 token device address pattern
@@ -274,7 +274,7 @@ public class WifiP2pDevice implements Parcelable {
}
/** Updates details obtained from supplicant @hide */
- void updateSupplicantDetails(WifiP2pDevice device) {
+ public void updateSupplicantDetails(WifiP2pDevice device) {
if (device == null) {
throw new IllegalArgumentException("device is null");
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index fbcf09b..3d0bb3d 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -89,7 +89,7 @@ public class WifiP2pDeviceList implements Parcelable {
}
/** Only updates details fetched from the supplicant @hide */
- void updateSupplicantDetails(WifiP2pDevice device) {
+ public void updateSupplicantDetails(WifiP2pDevice device) {
validateDevice(device);
WifiP2pDevice d = mDevices.get(device.deviceAddress);
if (d != null) {
@@ -107,7 +107,7 @@ public class WifiP2pDeviceList implements Parcelable {
}
/** @hide */
- void updateGroupCapability(String deviceAddress, int groupCapab) {
+ public void updateGroupCapability(String deviceAddress, int groupCapab) {
validateDeviceAddress(deviceAddress);
WifiP2pDevice d = mDevices.get(deviceAddress);
if (d != null) {
@@ -116,7 +116,7 @@ public class WifiP2pDeviceList implements Parcelable {
}
/** @hide */
- void updateStatus(String deviceAddress, int status) {
+ public void updateStatus(String deviceAddress, int status) {
validateDeviceAddress(deviceAddress);
WifiP2pDevice d = mDevices.get(deviceAddress);
if (d != null) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
index 98f0972..64bb00b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
@@ -42,11 +42,13 @@ public class WifiP2pGroupList implements Parcelable {
public void onDeleteGroup(int netId);
}
- WifiP2pGroupList() {
+ /** @hide */
+ public WifiP2pGroupList() {
this(null, null);
}
- WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) {
+ /** @hide */
+ public WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) {
mListener = listener;
mGroups = new LruCache<Integer, WifiP2pGroup>(CREDENTIAL_MAX_NUM) {
@Override
@@ -78,8 +80,9 @@ public class WifiP2pGroupList implements Parcelable {
* Add the specified group to this group list.
*
* @param group
+ * @hide
*/
- void add(WifiP2pGroup group) {
+ public void add(WifiP2pGroup group) {
mGroups.put(group.getNetworkId(), group);
}
@@ -87,8 +90,9 @@ public class WifiP2pGroupList implements Parcelable {
* Remove the group with the specified network id from this group list.
*
* @param netId
+ * @hide
*/
- void remove(int netId) {
+ public void remove(int netId) {
mGroups.remove(netId);
}
@@ -103,8 +107,9 @@ public class WifiP2pGroupList implements Parcelable {
/**
* Clear the group.
+ * @hide
*/
- boolean clear() {
+ public boolean clear() {
if (mGroups.size() == 0) return false;
isClearCalled = true;
mGroups.evictAll();
@@ -120,8 +125,9 @@ public class WifiP2pGroupList implements Parcelable {
*
* @param deviceAddress p2p device address.
* @return the network id. if not found, return -1.
+ * @hide
*/
- int getNetworkId(String deviceAddress) {
+ public int getNetworkId(String deviceAddress) {
if (deviceAddress == null) return -1;
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
@@ -142,8 +148,9 @@ public class WifiP2pGroupList implements Parcelable {
* @param deviceAddress p2p device address.
* @param ssid ssid.
* @return the network id. if not found, return -1.
+ * @hide
*/
- int getNetworkId(String deviceAddress, String ssid) {
+ public int getNetworkId(String deviceAddress, String ssid) {
if (deviceAddress == null || ssid == null) {
return -1;
}
@@ -166,8 +173,9 @@ public class WifiP2pGroupList implements Parcelable {
*
* @param netId network id.
* @return the address. if not found, return null.
+ * @hide
*/
- String getOwnerAddr(int netId) {
+ public String getOwnerAddr(int netId) {
WifiP2pGroup grp = mGroups.get(netId);
if (grp != null) {
return grp.getOwner().deviceAddress;
@@ -182,8 +190,9 @@ public class WifiP2pGroupList implements Parcelable {
*
* @param netId network id.
* @return true if the specified network id is present in this group list.
+ * @hide
*/
- boolean contains(int netId) {
+ public boolean contains(int netId) {
final Collection<WifiP2pGroup> groups = mGroups.snapshot().values();
for (WifiP2pGroup grp: groups) {
if (netId == grp.getNetworkId()) {