Merge "Remove blocking from SM before boot completed." into klp-dev
diff --git a/Android.mk b/Android.mk
index 13b717a..49dc6af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -433,6 +433,7 @@
non_base_dirs := \
../../external/apache-http/src/org/apache/http \
+ ../opt/telephony/src/java/android/provider \
../opt/telephony/src/java/android/telephony \
../opt/telephony/src/java/android/telephony/gsm \
../opt/net/voip/src/java/android/net/rtp \
diff --git a/api/current.txt b/api/current.txt
index 77df600..ff72c4a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33,6 +33,7 @@
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
+ field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
field public static final java.lang.String BRICK = "android.permission.BRICK";
field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -5103,6 +5104,7 @@
public final class BluetoothDevice implements android.os.Parcelable {
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
+ method public boolean createBond();
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public int describeContents();
@@ -5113,6 +5115,8 @@
method public java.lang.String getName();
method public int getType();
method public android.os.ParcelUuid[] getUuids();
+ method public boolean setPairingConfirmation(boolean);
+ method public boolean setPin(byte[]);
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
field public static final java.lang.String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
@@ -5121,6 +5125,7 @@
field public static final java.lang.String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
field public static final java.lang.String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
field public static final java.lang.String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
+ field public static final java.lang.String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
field public static final java.lang.String ACTION_UUID = "android.bluetooth.device.action.UUID";
field public static final int BOND_BONDED = 12; // 0xc
field public static final int BOND_BONDING = 11; // 0xb
@@ -5135,9 +5140,13 @@
field public static final java.lang.String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
field public static final java.lang.String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
field public static final java.lang.String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
+ field public static final java.lang.String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
+ field public static final java.lang.String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
field public static final java.lang.String EXTRA_PREVIOUS_BOND_STATE = "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
field public static final java.lang.String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+ field public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; // 0x2
+ field public static final int PAIRING_VARIANT_PIN = 0; // 0x0
}
public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
@@ -10904,7 +10913,6 @@
method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
method public abstract void flush() throws android.hardware.camera2.CameraAccessException;
method public abstract java.lang.String getId();
- method public abstract android.hardware.camera2.CameraCharacteristics getProperties() throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
@@ -20989,7 +20997,6 @@
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
field public static final java.lang.String COLUMN_SIZE = "_size";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
- field public static final int FLAG_DIR_HIDE_GRID_TITLES = 64; // 0x40
field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
@@ -21006,18 +21013,12 @@
field public static final java.lang.String COLUMN_ICON = "icon";
field public static final java.lang.String COLUMN_MIME_TYPES = "mime_types";
field public static final java.lang.String COLUMN_ROOT_ID = "root_id";
- field public static final java.lang.String COLUMN_ROOT_TYPE = "root_type";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
field public static final java.lang.String COLUMN_TITLE = "title";
- field public static final int FLAG_ADVANCED = 4; // 0x4
- field public static final int FLAG_EMPTY = 32; // 0x20
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
- field public static final int FLAG_SUPPORTS_RECENTS = 8; // 0x8
- field public static final int FLAG_SUPPORTS_SEARCH = 16; // 0x10
- field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
- field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
- field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
+ field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
+ field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
}
public abstract class DocumentsProvider extends android.content.ContentProvider {
@@ -21735,6 +21736,277 @@
method public static void update(android.content.ContentProviderClient, android.net.Uri, byte[]) throws android.os.RemoteException;
}
+ public final class Telephony {
+ }
+
+ public static abstract interface Telephony.BaseMmsColumns implements android.provider.BaseColumns {
+ field public static final java.lang.String CONTENT_CLASS = "ct_cls";
+ field public static final java.lang.String CONTENT_LOCATION = "ct_l";
+ field public static final java.lang.String CONTENT_TYPE = "ct_t";
+ field public static final java.lang.String DATE = "date";
+ field public static final java.lang.String DATE_SENT = "date_sent";
+ field public static final java.lang.String DELIVERY_REPORT = "d_rpt";
+ field public static final java.lang.String DELIVERY_TIME = "d_tm";
+ field public static final java.lang.String EXPIRY = "exp";
+ field public static final java.lang.String LOCKED = "locked";
+ field public static final java.lang.String MESSAGE_BOX = "msg_box";
+ field public static final int MESSAGE_BOX_ALL = 0; // 0x0
+ field public static final int MESSAGE_BOX_DRAFTS = 3; // 0x3
+ field public static final int MESSAGE_BOX_INBOX = 1; // 0x1
+ field public static final int MESSAGE_BOX_OUTBOX = 4; // 0x4
+ field public static final int MESSAGE_BOX_SENT = 2; // 0x2
+ field public static final java.lang.String MESSAGE_CLASS = "m_cls";
+ field public static final java.lang.String MESSAGE_ID = "m_id";
+ field public static final java.lang.String MESSAGE_SIZE = "m_size";
+ field public static final java.lang.String MESSAGE_TYPE = "m_type";
+ field public static final java.lang.String MMS_VERSION = "v";
+ field public static final java.lang.String PRIORITY = "pri";
+ field public static final java.lang.String READ = "read";
+ field public static final java.lang.String READ_REPORT = "rr";
+ field public static final java.lang.String READ_STATUS = "read_status";
+ field public static final java.lang.String REPORT_ALLOWED = "rpt_a";
+ field public static final java.lang.String RESPONSE_STATUS = "resp_st";
+ field public static final java.lang.String RESPONSE_TEXT = "resp_txt";
+ field public static final java.lang.String RETRIEVE_STATUS = "retr_st";
+ field public static final java.lang.String RETRIEVE_TEXT = "retr_txt";
+ field public static final java.lang.String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
+ field public static final java.lang.String SEEN = "seen";
+ field public static final java.lang.String STATUS = "st";
+ field public static final java.lang.String SUBJECT = "sub";
+ field public static final java.lang.String SUBJECT_CHARSET = "sub_cs";
+ field public static final java.lang.String TEXT_ONLY = "text_only";
+ field public static final java.lang.String THREAD_ID = "thread_id";
+ field public static final java.lang.String TRANSACTION_ID = "tr_id";
+ }
+
+ public static abstract interface Telephony.CanonicalAddressesColumns implements android.provider.BaseColumns {
+ field public static final java.lang.String ADDRESS = "address";
+ }
+
+ public static final class Telephony.Carriers implements android.provider.BaseColumns {
+ field public static final java.lang.String APN = "apn";
+ field public static final java.lang.String AUTH_TYPE = "authtype";
+ field public static final java.lang.String BEARER = "bearer";
+ field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String CURRENT = "current";
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
+ field public static final java.lang.String MCC = "mcc";
+ field public static final java.lang.String MMSC = "mmsc";
+ field public static final java.lang.String MMSPORT = "mmsport";
+ field public static final java.lang.String MMSPROXY = "mmsproxy";
+ field public static final java.lang.String MNC = "mnc";
+ field public static final java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
+ field public static final java.lang.String MVNO_TYPE = "mvno_type";
+ field public static final java.lang.String NAME = "name";
+ field public static final java.lang.String NUMERIC = "numeric";
+ field public static final java.lang.String PASSWORD = "password";
+ field public static final java.lang.String PORT = "port";
+ field public static final java.lang.String PROTOCOL = "protocol";
+ field public static final java.lang.String PROXY = "proxy";
+ field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
+ field public static final java.lang.String SERVER = "server";
+ field public static final java.lang.String TYPE = "type";
+ field public static final java.lang.String USER = "user";
+ }
+
+ public static final class Telephony.Mms implements android.provider.Telephony.BaseMmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ field public static final android.net.Uri REPORT_REQUEST_URI;
+ field public static final android.net.Uri REPORT_STATUS_URI;
+ }
+
+ public static final class Telephony.Mms.Addr implements android.provider.BaseColumns {
+ field public static final java.lang.String ADDRESS = "address";
+ field public static final java.lang.String CHARSET = "charset";
+ field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String MSG_ID = "msg_id";
+ field public static final java.lang.String TYPE = "type";
+ }
+
+ public static final class Telephony.Mms.Draft implements android.provider.Telephony.BaseMmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Mms.Inbox implements android.provider.Telephony.BaseMmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Mms.Intents {
+ field public static final java.lang.String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED";
+ field public static final java.lang.String DELETED_CONTENTS = "deleted_contents";
+ }
+
+ public static final class Telephony.Mms.Outbox implements android.provider.Telephony.BaseMmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Mms.Part implements android.provider.BaseColumns {
+ field public static final java.lang.String CHARSET = "chset";
+ field public static final java.lang.String CONTENT_DISPOSITION = "cd";
+ field public static final java.lang.String CONTENT_ID = "cid";
+ field public static final java.lang.String CONTENT_LOCATION = "cl";
+ field public static final java.lang.String CONTENT_TYPE = "ct";
+ field public static final java.lang.String CT_START = "ctt_s";
+ field public static final java.lang.String CT_TYPE = "ctt_t";
+ field public static final java.lang.String FILENAME = "fn";
+ field public static final java.lang.String MSG_ID = "mid";
+ field public static final java.lang.String NAME = "name";
+ field public static final java.lang.String SEQ = "seq";
+ field public static final java.lang.String TEXT = "text";
+ field public static final java.lang.String _DATA = "_data";
+ }
+
+ public static final class Telephony.Mms.Rate {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String SENT_TIME = "sent_time";
+ }
+
+ public static final class Telephony.Mms.Sent implements android.provider.Telephony.BaseMmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.MmsSms implements android.provider.BaseColumns {
+ field public static final android.net.Uri CONTENT_CONVERSATIONS_URI;
+ field public static final android.net.Uri CONTENT_DRAFT_URI;
+ field public static final android.net.Uri CONTENT_FILTER_BYPHONE_URI;
+ field public static final android.net.Uri CONTENT_LOCKED_URI;
+ field public static final android.net.Uri CONTENT_UNDELIVERED_URI;
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final int ERR_TYPE_GENERIC = 1; // 0x1
+ field public static final int ERR_TYPE_GENERIC_PERMANENT = 10; // 0xa
+ field public static final int ERR_TYPE_MMS_PROTO_PERMANENT = 12; // 0xc
+ field public static final int ERR_TYPE_MMS_PROTO_TRANSIENT = 3; // 0x3
+ field public static final int ERR_TYPE_SMS_PROTO_PERMANENT = 11; // 0xb
+ field public static final int ERR_TYPE_SMS_PROTO_TRANSIENT = 2; // 0x2
+ field public static final int ERR_TYPE_TRANSPORT_FAILURE = 4; // 0x4
+ field public static final int MMS_PROTO = 1; // 0x1
+ field public static final int NO_ERROR = 0; // 0x0
+ field public static final android.net.Uri SEARCH_URI;
+ field public static final int SMS_PROTO = 0; // 0x0
+ field public static final java.lang.String TYPE_DISCRIMINATOR_COLUMN = "transport_type";
+ }
+
+ public static final class Telephony.MmsSms.PendingMessages implements android.provider.BaseColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DUE_TIME = "due_time";
+ field public static final java.lang.String ERROR_CODE = "err_code";
+ field public static final java.lang.String ERROR_TYPE = "err_type";
+ field public static final java.lang.String LAST_TRY = "last_try";
+ field public static final java.lang.String MSG_ID = "msg_id";
+ field public static final java.lang.String MSG_TYPE = "msg_type";
+ field public static final java.lang.String PROTO_TYPE = "proto_type";
+ field public static final java.lang.String RETRY_INDEX = "retry_index";
+ }
+
+ public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+ method public static java.lang.String getDefaultSmsPackage(android.content.Context);
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Sms.Conversations implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ field public static final java.lang.String MESSAGE_COUNT = "msg_count";
+ field public static final java.lang.String SNIPPET = "snippet";
+ }
+
+ public static final class Telephony.Sms.Draft implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Sms.Inbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Sms.Intents {
+ method public static android.telephony.SmsMessage[] getMessagesFromIntent(android.content.Intent);
+ field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
+ field public static final java.lang.String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+ field public static final int RESULT_SMS_DUPLICATED = 5; // 0x5
+ field public static final int RESULT_SMS_GENERIC_ERROR = 2; // 0x2
+ field public static final int RESULT_SMS_HANDLED = 1; // 0x1
+ field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
+ field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
+ field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+ field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
+ field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
+ field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
+ field public static final java.lang.String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
+ field public static final java.lang.String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED";
+ field public static final java.lang.String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
+ field public static final java.lang.String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER";
+ field public static final java.lang.String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
+ }
+
+ public static final class Telephony.Sms.Outbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static final class Telephony.Sms.Sent implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+ }
+
+ public static abstract interface Telephony.TextBasedSmsColumns {
+ field public static final java.lang.String ADDRESS = "address";
+ field public static final java.lang.String BODY = "body";
+ field public static final java.lang.String DATE = "date";
+ field public static final java.lang.String DATE_SENT = "date_sent";
+ field public static final java.lang.String ERROR_CODE = "error_code";
+ field public static final java.lang.String LOCKED = "locked";
+ field public static final int MESSAGE_TYPE_ALL = 0; // 0x0
+ field public static final int MESSAGE_TYPE_DRAFT = 3; // 0x3
+ field public static final int MESSAGE_TYPE_FAILED = 5; // 0x5
+ field public static final int MESSAGE_TYPE_INBOX = 1; // 0x1
+ field public static final int MESSAGE_TYPE_OUTBOX = 4; // 0x4
+ field public static final int MESSAGE_TYPE_QUEUED = 6; // 0x6
+ field public static final int MESSAGE_TYPE_SENT = 2; // 0x2
+ field public static final java.lang.String PERSON = "person";
+ field public static final java.lang.String PROTOCOL = "protocol";
+ field public static final java.lang.String READ = "read";
+ field public static final java.lang.String REPLY_PATH_PRESENT = "reply_path_present";
+ field public static final java.lang.String SEEN = "seen";
+ field public static final java.lang.String SERVICE_CENTER = "service_center";
+ field public static final java.lang.String STATUS = "status";
+ field public static final int STATUS_COMPLETE = 0; // 0x0
+ field public static final int STATUS_FAILED = 64; // 0x40
+ field public static final int STATUS_NONE = -1; // 0xffffffff
+ field public static final int STATUS_PENDING = 32; // 0x20
+ field public static final java.lang.String SUBJECT = "subject";
+ field public static final java.lang.String THREAD_ID = "thread_id";
+ field public static final java.lang.String TYPE = "type";
+ }
+
+ public static final class Telephony.Threads implements android.provider.Telephony.ThreadsColumns {
+ field public static final int BROADCAST_THREAD = 1; // 0x1
+ field public static final int COMMON_THREAD = 0; // 0x0
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final android.net.Uri OBSOLETE_THREADS_URI;
+ }
+
+ public static abstract interface Telephony.ThreadsColumns implements android.provider.BaseColumns {
+ field public static final java.lang.String DATE = "date";
+ field public static final java.lang.String ERROR = "error";
+ field public static final java.lang.String HAS_ATTACHMENT = "has_attachment";
+ field public static final java.lang.String MESSAGE_COUNT = "message_count";
+ field public static final java.lang.String READ = "read";
+ field public static final java.lang.String RECIPIENT_IDS = "recipient_ids";
+ field public static final java.lang.String SNIPPET = "snippet";
+ field public static final java.lang.String SNIPPET_CHARSET = "snippet_cs";
+ field public static final java.lang.String TYPE = "type";
+ }
+
public class UserDictionary {
ctor public UserDictionary();
field public static final java.lang.String AUTHORITY = "user_dictionary";
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 2c85382..1efdc81 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -219,7 +219,7 @@
* {@link #BOND_NONE},
* {@link #BOND_BONDING},
* {@link #BOND_BONDED}.
- */
+ */
public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
/**
* Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
@@ -228,7 +228,7 @@
* {@link #BOND_NONE},
* {@link #BOND_BONDING},
* {@link #BOND_BONDED}.
- */
+ */
public static final String EXTRA_PREVIOUS_BOND_STATE =
"android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
/**
@@ -253,12 +253,26 @@
*/
public static final int BOND_BONDED = 12;
- /** @hide */
+ /**
+ * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
+ * intents for unbond reason.
+ * @hide
+ */
public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
- /** @hide */
+
+ /**
+ * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
+ * intents to indicate pairing method used. Possible values are:
+ * {@link #PAIRING_VARIANT_PIN},
+ * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
+ */
public static final String EXTRA_PAIRING_VARIANT =
"android.bluetooth.device.extra.PAIRING_VARIANT";
- /** @hide */
+
+ /**
+ * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
+ * intents as the value of passkey.
+ */
public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
/**
@@ -306,7 +320,10 @@
public static final String ACTION_NAME_FAILED =
"android.bluetooth.device.action.NAME_FAILED";
- /** @hide */
+ /**
+ * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PAIRING_REQUEST =
"android.bluetooth.device.action.PAIRING_REQUEST";
@@ -446,8 +463,8 @@
public static final int UNBOND_REASON_REMOVED = 9;
/**
- * The user will be prompted to enter a pin
- * @hide
+ * The user will be prompted to enter a pin or
+ * a privileged app will enter a pin for user.
*/
public static final int PAIRING_VARIANT_PIN = 0;
@@ -458,8 +475,8 @@
public static final int PAIRING_VARIANT_PASSKEY = 1;
/**
- * The user will be prompted to confirm the passkey displayed on the screen
- * @hide
+ * The user will be prompted to confirm the passkey displayed on the screen or
+ * a privileged app will confirm the passkey for the user.
*/
public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
@@ -707,10 +724,9 @@
* the bonding process completes, and its result.
* <p>Android system services will handle the necessary user interactions
* to confirm and complete the bonding process.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
* @return false on immediate error, true if bonding will begin
- * @hide
*/
public boolean createBond() {
if (sService == null) {
@@ -946,7 +962,13 @@
return BluetoothDevice.ERROR;
}
- /** @hide */
+ /**
+ * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ *
+ * @return true pin has been set
+ * false for error
+ */
public boolean setPin(byte[] pin) {
if (sService == null) {
Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
@@ -968,7 +990,13 @@
return false;
}
- /** @hide */
+ /**
+ * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ *
+ * @return true confirmation has been sent out
+ * false for error
+ */
public boolean setPairingConfirmation(boolean confirm) {
if (sService == null) {
Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index ec89041..a9a72b0 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -16,11 +16,9 @@
package android.hardware.camera2;
-import android.view.Surface;
import android.os.Handler;
-import android.util.Log;
+import android.view.Surface;
-import java.lang.AutoCloseable;
import java.util.List;
/**
@@ -127,24 +125,11 @@
* @return the ID for this camera device
*
* @see CameraManager#getCameraCharacteristics
- * @see CameraManager#getDeviceIdList
+ * @see CameraManager#getCameraIdList
*/
public String getId();
/**
- * Get the static properties for this camera. These are identical to the
- * properties returned by {@link CameraManager#getCameraCharacteristics}.
- *
- * @return the static properties of the camera
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera device has been closed
- *
- * @see CameraManager#getCameraCharacteristics
- */
- public CameraCharacteristics getProperties() throws CameraAccessException;
- /**
* <p>Set up a new output set of Surfaces for the camera device.</p>
*
* <p>The configuration determines the set of potential output Surfaces for
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index f126472..70a6f44 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -88,24 +88,6 @@
}
@Override
- public CameraCharacteristics getProperties() throws CameraAccessException {
-
- CameraMetadataNative info = new CameraMetadataNative();
-
- try {
- mRemoteDevice.getCameraInfo(/*out*/info);
- } catch(CameraRuntimeException e) {
- throw e.asChecked();
- } catch(RemoteException e) {
- // impossible
- return null;
- }
-
- CameraCharacteristics properties = new CameraCharacteristics(info);
- return properties;
- }
-
- @Override
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
synchronized (mLock) {
HashSet<Surface> addSet = new HashSet<Surface>(outputs); // Streams to create
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 4044b31..3bd515b 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -45,6 +45,7 @@
void removePrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
int userId);
+ List<PrintServiceInfo> getInstalledPrintServices(int userId);
List<PrintServiceInfo> getEnabledPrintServices(int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index 291e81f..96b168d 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -36,7 +36,6 @@
*/
oneway interface IPrintSpooler {
void removeObsoletePrintJobs();
- void forgetPrintJobs(in List<PrintJobId> printJob);
void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName,
int state, int appId, int sequence);
void getPrintJobInfo(in PrintJobId printJobId, IPrintSpoolerCallbacks callback,
diff --git a/core/java/android/print/IPrintSpoolerClient.aidl b/core/java/android/print/IPrintSpoolerClient.aidl
index 0cf00cc..8270812 100644
--- a/core/java/android/print/IPrintSpoolerClient.aidl
+++ b/core/java/android/print/IPrintSpoolerClient.aidl
@@ -29,5 +29,5 @@
void onPrintJobQueued(in PrintJobInfo printJob);
void onAllPrintJobsForServiceHandled(in ComponentName printService);
void onAllPrintJobsHandled();
- void onPrintJobStateChanged(in PrintJobId printJobId, int appId);
+ void onPrintJobStateChanged(in PrintJobInfo printJob);
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index a015388..0859fdd 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -289,7 +289,26 @@
return enabledServices;
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting the enalbed print services", re);
+ Log.e(LOG_TAG, "Error getting the enabled print services", re);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Gets the list of installed print services.
+ *
+ * @return The installed service list or an empty list.
+ *
+ * @hide
+ */
+ public List<PrintServiceInfo> getInstalledPrintServices() {
+ try {
+ List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
+ if (installedServices != null) {
+ return installedServices;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error getting the installed print services", re);
}
return Collections.emptyList();
}
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 6432a37..d32b71b 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -28,6 +28,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
/**
@@ -40,8 +41,8 @@
private static final int MSG_PRINTERS_ADDED = 1;
private static final int MSG_PRINTERS_REMOVED = 2;
- private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
- new ArrayMap<PrinterId, PrinterInfo>();
+ private final LinkedHashMap<PrinterId, PrinterInfo> mPrinters =
+ new LinkedHashMap<PrinterId, PrinterInfo>();
private final IPrintManager mPrintManager;
@@ -218,9 +219,7 @@
}
// Update printers we already have.
- final int oldPrinterCount = mPrinters.size();
- for (int i = 0; i < oldPrinterCount; i++) {
- PrinterId oldPrinterId = mPrinters.keyAt(i);
+ for (PrinterId oldPrinterId : mPrinters.keySet()) {
PrinterInfo updatedPrinter = addedPrintersMap.remove(oldPrinterId);
if (updatedPrinter != null) {
mPrinters.put(oldPrinterId, updatedPrinter);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4c9af19..85ec803 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -99,7 +99,7 @@
/**
* Unique ID of a document. This ID is both provided by and interpreted
* by a {@link DocumentsProvider}, and should be treated as an opaque
- * value by client applications.
+ * value by client applications. This column is required.
* <p>
* Each document must have a unique ID within a provider, but that
* single document may be included as a child of multiple directories.
@@ -117,7 +117,7 @@
* Concrete MIME type of a document. For example, "image/png" or
* "application/pdf" for openable files. A document can also be a
* directory containing additional documents, which is represented with
- * the {@link #MIME_TYPE_DIR} MIME type.
+ * the {@link #MIME_TYPE_DIR} MIME type. This column is required.
* <p>
* Type: STRING
*
@@ -127,15 +127,15 @@
/**
* Display name of a document, used as the primary title displayed to a
- * user.
+ * user. This column is required.
* <p>
* Type: STRING
*/
public static final String COLUMN_DISPLAY_NAME = OpenableColumns.DISPLAY_NAME;
/**
- * Summary of a document, which may be shown to a user. The summary may
- * be {@code null}.
+ * Summary of a document, which may be shown to a user. This column is
+ * optional, and may be {@code null}.
* <p>
* Type: STRING
*/
@@ -143,9 +143,9 @@
/**
* Timestamp when a document was last modified, in milliseconds since
- * January 1, 1970 00:00:00.0 UTC, or {@code null} if unknown. A
- * {@link DocumentsProvider} can update this field using events from
- * {@link OnCloseListener} or other reliable
+ * January 1, 1970 00:00:00.0 UTC. This column is required, and may be
+ * {@code null} if unknown. A {@link DocumentsProvider} can update this
+ * field using events from {@link OnCloseListener} or other reliable
* {@link ParcelFileDescriptor} transports.
* <p>
* Type: INTEGER (long)
@@ -155,15 +155,16 @@
public static final String COLUMN_LAST_MODIFIED = "last_modified";
/**
- * Specific icon resource ID for a document, or {@code null} to use
- * platform default icon based on {@link #COLUMN_MIME_TYPE}.
+ * Specific icon resource ID for a document. This column is optional,
+ * and may be {@code null} to use a platform-provided default icon based
+ * on {@link #COLUMN_MIME_TYPE}.
* <p>
* Type: INTEGER (int)
*/
public static final String COLUMN_ICON = "icon";
/**
- * Flags that apply to a document.
+ * Flags that apply to a document. This column is required.
* <p>
* Type: INTEGER (int)
*
@@ -171,12 +172,13 @@
* @see #FLAG_SUPPORTS_DELETE
* @see #FLAG_SUPPORTS_THUMBNAIL
* @see #FLAG_DIR_PREFERS_GRID
- * @see #FLAG_DIR_SUPPORTS_CREATE
+ * @see #FLAG_DIR_PREFERS_LAST_MODIFIED
*/
public static final String COLUMN_FLAGS = "flags";
/**
- * Size of a document, in bytes, or {@code null} if unknown.
+ * Size of a document, in bytes, or {@code null} if unknown. This column
+ * is required.
* <p>
* Type: INTEGER (long)
*/
@@ -211,7 +213,7 @@
* writability of a document may change over time, for example due to
* remote access changes. This flag indicates that a document client can
* expect {@link ContentResolver#openOutputStream(Uri)} to succeed.
- *
+ *
* @see #COLUMN_FLAGS
*/
public static final int FLAG_SUPPORTS_WRITE = 1 << 1;
@@ -265,8 +267,9 @@
*
* @see #COLUMN_FLAGS
* @see #FLAG_DIR_PREFERS_GRID
+ * @hide
*/
- public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 6;
+ public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 16;
}
/**
@@ -282,31 +285,17 @@
/**
* Unique ID of a root. This ID is both provided by and interpreted by a
* {@link DocumentsProvider}, and should be treated as an opaque value
- * by client applications.
+ * by client applications. This column is required.
* <p>
* Type: STRING
*/
public static final String COLUMN_ROOT_ID = "root_id";
/**
- * Type of a root, used for clustering when presenting multiple roots to
- * a user.
+ * Flags that apply to a root. This column is required.
* <p>
* Type: INTEGER (int)
*
- * @see #ROOT_TYPE_SERVICE
- * @see #ROOT_TYPE_SHORTCUT
- * @see #ROOT_TYPE_DEVICE
- */
- public static final String COLUMN_ROOT_TYPE = "root_type";
-
- /**
- * Flags that apply to a root.
- * <p>
- * Type: INTEGER (int)
- *
- * @see #FLAG_ADVANCED
- * @see #FLAG_EMPTY
* @see #FLAG_LOCAL_ONLY
* @see #FLAG_SUPPORTS_CREATE
* @see #FLAG_SUPPORTS_RECENTS
@@ -315,22 +304,23 @@
public static final String COLUMN_FLAGS = "flags";
/**
- * Icon resource ID for a root.
+ * Icon resource ID for a root. This column is required.
* <p>
* Type: INTEGER (int)
*/
public static final String COLUMN_ICON = "icon";
/**
- * Title for a root, which will be shown to a user.
+ * Title for a root, which will be shown to a user. This column is
+ * required.
* <p>
* Type: STRING
*/
public static final String COLUMN_TITLE = "title";
/**
- * Summary for this root, which may be shown to a user. The summary may
- * be {@code null}.
+ * Summary for this root, which may be shown to a user. This column is
+ * optional, and may be {@code null}.
* <p>
* Type: STRING
*/
@@ -338,7 +328,7 @@
/**
* Document which is a directory that represents the top directory of
- * this root.
+ * this root. This column is required.
* <p>
* Type: STRING
*
@@ -347,20 +337,20 @@
public static final String COLUMN_DOCUMENT_ID = "document_id";
/**
- * Number of bytes available in this root, or {@code null} if unknown or
- * unbounded.
+ * Number of bytes available in this root. This column is optional, and
+ * may be {@code null} if unknown or unbounded.
* <p>
* Type: INTEGER (long)
*/
public static final String COLUMN_AVAILABLE_BYTES = "available_bytes";
/**
- * MIME types supported by this root, or {@code null} if the root
- * supports all MIME types. Multiple MIME types can be separated by a
- * newline. For example, a root supporting audio might use
- * "audio/*\napplication/x-flac".
+ * MIME types supported by this root. This column is optional, and if
+ * {@code null} the root is assumed to support all MIME types. Multiple
+ * MIME types can be separated by a newline. For example, a root
+ * supporting audio might return "audio/*\napplication/x-flac".
* <p>
- * Type: String
+ * Type: STRING
*/
public static final String COLUMN_MIME_TYPES = "mime_types";
@@ -368,29 +358,6 @@
public static final String MIME_TYPE_ITEM = "vnd.android.document/root";
/**
- * Type of root that represents a storage service, such as a cloud-based
- * service.
- *
- * @see #COLUMN_ROOT_TYPE
- */
- public static final int ROOT_TYPE_SERVICE = 1;
-
- /**
- * Type of root that represents a shortcut to content that may be
- * available elsewhere through another storage root.
- *
- * @see #COLUMN_ROOT_TYPE
- */
- public static final int ROOT_TYPE_SHORTCUT = 2;
-
- /**
- * Type of root that represents a physical storage device.
- *
- * @see #COLUMN_ROOT_TYPE
- */
- public static final int ROOT_TYPE_DEVICE = 3;
-
- /**
* Flag indicating that at least one directory under this root supports
* creating content. Roots with this flag will be shown when an
* application interacts with {@link Intent#ACTION_CREATE_DOCUMENT}.
@@ -409,21 +376,13 @@
public static final int FLAG_LOCAL_ONLY = 1 << 1;
/**
- * Flag indicating that this root should only be visible to advanced
- * users.
- *
- * @see #COLUMN_FLAGS
- */
- public static final int FLAG_ADVANCED = 1 << 2;
-
- /**
* Flag indicating that this root can report recently modified
* documents.
*
* @see #COLUMN_FLAGS
* @see DocumentsContract#buildRecentDocumentsUri(String, String)
*/
- public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
+ public static final int FLAG_SUPPORTS_RECENTS = 1 << 2;
/**
* Flag indicating that this root supports search.
@@ -432,19 +391,31 @@
* @see DocumentsProvider#querySearchDocuments(String, String,
* String[])
*/
- public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
+ public static final int FLAG_SUPPORTS_SEARCH = 1 << 3;
/**
* Flag indicating that this root is currently empty. This may be used
* to hide the root when opening documents, but the root will still be
* shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
- * also set.
+ * also set. If the value of this flag changes, such as when a root
+ * becomes non-empty, you must send a content changed notification for
+ * {@link DocumentsContract#buildRootsUri(String)}.
*
* @see #COLUMN_FLAGS
- * @see DocumentsProvider#querySearchDocuments(String, String,
- * String[])
+ * @see ContentResolver#notifyChange(Uri,
+ * android.database.ContentObserver, boolean)
+ * @hide
*/
- public static final int FLAG_EMPTY = 1 << 5;
+ public static final int FLAG_EMPTY = 1 << 16;
+
+ /**
+ * Flag indicating that this root should only be visible to advanced
+ * users.
+ *
+ * @see #COLUMN_FLAGS
+ * @hide
+ */
+ public static final int FLAG_ADVANCED = 1 << 17;
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6c6635d..b8cccb1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2797,7 +2797,6 @@
MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
- MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_IDLE_MS);
@@ -5208,12 +5207,6 @@
"wifi_networks_available_repeat_delay";
/**
- * 802.11 country code in ISO 3166 format
- * @hide
- */
- public static final String WIFI_COUNTRY_CODE = "wifi_country_code";
-
- /**
* The interval in milliseconds to issue wake up scans when wifi needs
* to connect. This is necessary to connect to an access point when
* device is on the move and the screen is off.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index aea2799c..caf9c8b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -249,12 +249,6 @@
boolean isSafeModeEnabled();
/**
- * Tell keyguard to show the assistant (Intent.ACTION_ASSIST) after asking for the user's
- * credentials.
- */
- void showAssistant();
-
- /**
* Sets the display magnification callbacks. These callbacks notify
* the client for contextual changes related to display magnification.
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 38f28ae..28f7480 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4825,8 +4825,8 @@
enqueueInputEvent(new KeyEvent(event.getDownTime(), event.getEventTime(),
event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(),
- event.getScanCode(), event.getFlags() | KeyEvent.FLAG_FALLBACK,
- event.getSource()));
+ event.getDeviceId(), event.getScanCode(),
+ event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource()));
return true;
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index e116662..79c0b3c 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1176,12 +1176,6 @@
public void dump(String prefix, PrintWriter writer, String[] args);
/**
- * Ask keyguard to invoke the assist intent after dismissing keyguard
- * {@link android.content.Intent#ACTION_ASSIST}
- */
- public void showAssistant();
-
- /**
* Returns whether a given window type can be magnified.
*
* @param windowType The window type.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 41a8fd1..6f832cfd 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2231,12 +2231,10 @@
View scrapView;
scrapView = mRecycler.getTransientStateView(position);
- if (scrapView != null) {
- return scrapView;
+ if (scrapView == null) {
+ scrapView = mRecycler.getScrapView(position);
}
- scrapView = mRecycler.getScrapView(position);
-
View child;
if (scrapView != null) {
child = mAdapter.getView(position, scrapView, this);
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index 6c4c39d..d4c5be0 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -26,9 +26,13 @@
import android.view.ViewGroup;
/**
- * Adapter that exposes data from a {@link android.database.Cursor Cursor} to a
- * {@link android.widget.ListView ListView} widget. The Cursor must include
- * a column named "_id" or this class will not work.
+ * Adapter that exposes data from a {@link android.database.Cursor Cursor} to a
+ * {@link android.widget.ListView ListView} widget.
+ * <p>
+ * The Cursor must include a column named "_id" or this class will not work.
+ * Additionally, using {@link android.database.MergeCursor} with this class will
+ * not work if the merged Cursors have overlapping values in their "_id"
+ * columns.
*/
public abstract class CursorAdapter extends BaseAdapter implements Filterable,
CursorFilter.CursorFilterClient {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 97cb815..61e071b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4679,8 +4679,6 @@
assumeLayout();
}
- boolean changed = false;
-
if (mMovement != null) {
/* This code also provides auto-scrolling when a cursor is moved using a
* CursorController (insertion point or selection limits).
@@ -4703,10 +4701,10 @@
}
if (curs >= 0) {
- changed = bringPointIntoView(curs);
+ bringPointIntoView(curs);
}
} else {
- changed = bringTextIntoView();
+ bringTextIntoView();
}
// This has to be checked here since:
@@ -4727,7 +4725,7 @@
getViewTreeObserver().removeOnPreDrawListener(this);
mPreDrawRegistered = false;
- return !changed;
+ return true;
}
@Override
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 009b729..fbdf318 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -33,6 +33,7 @@
import android.media.SubtitleTrack.RenderingWidget;
import android.media.WebVttRenderer;
import android.net.Uri;
+import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
@@ -879,4 +880,10 @@
invalidate();
}
+
+ /** @hide */
+ @Override
+ public Looper getSubtitleLooper() {
+ return Looper.getMainLooper();
+ }
}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index a281f7c..a95bac8 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -47,6 +47,10 @@
public static final String SERVICE_NAME = "procstats";
+ // How often the service commits its data, giving the minimum batching
+ // that is done.
+ public static long COMMIT_PERIOD = 3*60*60*1000; // Commit current stats every 3 hours
+
public static final int STATE_NOTHING = -1;
public static final int STATE_PERSISTENT = 0;
public static final int STATE_TOP = 1;
@@ -1015,7 +1019,7 @@
pkgMap.removeAt(ip);
}
}
- mStartTime = SystemClock.uptimeMillis();
+ mStartTime = now;
if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
}
@@ -1449,7 +1453,7 @@
mReadError = "bad uid: " + uid;
return;
}
- PackageState pkgState = new PackageState(uid);
+ PackageState pkgState = new PackageState(pkgName, uid);
mPackages.put(pkgName, uid, pkgState);
int NPROCS = in.readInt();
if (NPROCS < 0) {
@@ -1620,7 +1624,7 @@
if (as != null) {
return as;
}
- as = new PackageState(uid);
+ as = new PackageState(packageName, uid);
mPackages.put(packageName, uid, as);
return as;
}
@@ -1646,11 +1650,22 @@
// but it was created for a different package than the caller.
// We need to convert it to a multi-package process.
commonProc.mMultiPackage = true;
- // The original package it was created for now needs to point
- // to its own copy.
+ // To do this, we need to make two new process states, one a copy
+ // of the current state for the process under the original package
+ // name, and the second a free new process state for it as the
+ // new package name.
long now = SystemClock.uptimeMillis();
- pkgState.mProcesses.put(commonProc.mName, commonProc.clone(
- commonProc.mPackage, now));
+ // First let's make a copy of the current process state and put
+ // that under the now unique state for its original package name.
+ final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage, uid);
+ if (commonPkgState != null) {
+ commonPkgState.mProcesses.put(commonProc.mName, commonProc.clone(
+ commonProc.mPackage, now));
+ } else {
+ Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage
+ + "/" + uid + " for proc " + commonProc.mName);
+ }
+ // And now make a fresh new process state for the new package name.
ps = new ProcessState(commonProc, packageName, uid, processName, now);
}
} else {
@@ -1677,6 +1692,32 @@
return ss;
}
+ private void dumpProcessInternalLocked(PrintWriter pw, String prefix, ProcessState proc,
+ boolean dumpAll) {
+ if (dumpAll) {
+ pw.print(prefix); pw.print("myID=");
+ pw.print(Integer.toHexString(System.identityHashCode(proc)));
+ pw.print(" mCommonProcess=");
+ pw.print(Integer.toHexString(System.identityHashCode(proc.mCommonProcess)));
+ pw.print(" mPackage="); pw.println(proc.mPackage);
+ if (proc.mMultiPackage) {
+ pw.print(prefix); pw.print("mMultiPackage="); pw.println(proc.mMultiPackage);
+ }
+ if (proc != proc.mCommonProcess) {
+ pw.print(prefix); pw.print("Common Proc: "); pw.print(proc.mCommonProcess.mName);
+ pw.print("/"); pw.print(proc.mCommonProcess.mUid);
+ pw.print(" pkg="); pw.println(proc.mCommonProcess.mPackage);
+ }
+ }
+ pw.print(prefix); pw.print("mActive="); pw.println(proc.mActive);
+ if (proc.mDead) {
+ pw.print(prefix); pw.print("mDead="); pw.println(proc.mDead);
+ }
+ pw.print(prefix); pw.print("mNumActiveServices="); pw.print(proc.mNumActiveServices);
+ pw.print(" mNumStartedServices=");
+ pw.println(proc.mNumStartedServices);
+ }
+
public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
boolean dumpAll) {
long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
@@ -1715,10 +1756,7 @@
ALL_PROC_STATES, now);
dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES);
- pw.print(" mActive="); pw.println(proc.mActive);
- pw.print(" mNumActiveServices="); pw.print(proc.mNumActiveServices);
- pw.print(" mNumStartedServices=");
- pw.println(proc.mNumStartedServices);
+ dumpProcessInternalLocked(pw, " ", proc, dumpAll);
}
} else {
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
@@ -1737,6 +1775,7 @@
pw.print(pkgState.mServices.keyAt(isvc));
pw.println(":");
ServiceState svc = pkgState.mServices.valueAt(isvc);
+ pw.print(" Process: "); pw.println(svc.mProcessName);
dumpServiceStats(pw, " ", " ", " ", "Running", svc,
svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
@@ -1759,16 +1798,19 @@
if (reqPackage == null) {
ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
printedHeader = false;
+ int numShownProcs = 0, numTotalProcs = 0;
for (int ip=0; ip<procMap.size(); ip++) {
String procName = procMap.keyAt(ip);
SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
int uid = uids.keyAt(iu);
+ numTotalProcs++;
ProcessState proc = uids.valueAt(iu);
if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
&& proc.mPssTableSize == 0) {
continue;
}
+ numShownProcs++;
if (!printedHeader) {
pw.println();
pw.println("Per-Process Stats:");
@@ -1783,13 +1825,15 @@
dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES);
if (dumpAll) {
- pw.print(" mActive="); pw.println(proc.mActive);
- pw.print(" mNumActiveServices="); pw.print(proc.mNumActiveServices);
- pw.print(" mNumStartedServices=");
- pw.println(proc.mNumStartedServices);
+ dumpProcessInternalLocked(pw, " ", proc, dumpAll);
}
}
}
+ if (dumpAll) {
+ pw.println();
+ pw.print(" Total procs: "); pw.print(numShownProcs);
+ pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+ }
pw.println();
if (dumpSummary) {
@@ -1876,7 +1920,7 @@
long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
mStartTime, now);
dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
+ ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
pw.println();
dumpTotalsLocked(pw, now);
}
@@ -1916,22 +1960,22 @@
}
void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
- int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime,
- String reqPackage) {
+ int[] screenStates, int[] memStates, int[] procStates,
+ int[] sortProcStates, long now, long totalTime, String reqPackage) {
ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
- procStates, now, reqPackage);
+ procStates, sortProcStates, now, reqPackage);
if (procs.size() > 0) {
if (header != null) {
pw.println();
pw.println(header);
}
- dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates, procStates,
- now, totalTime);
+ dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
+ sortProcStates, now, totalTime);
}
}
public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
- int[] procStates, long now, String reqPackage) {
+ int[] procStates, int sortProcStates[], long now, String reqPackage) {
ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
for (int ip=0; ip<pkgMap.size(); ip++) {
@@ -1953,6 +1997,9 @@
if (computeProcessTimeLocked(proc, screenStates, memStates,
procStates, now) > 0) {
outProcs.add(proc);
+ if (procStates != sortProcStates) {
+ computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now);
+ }
}
}
Collections.sort(outProcs, new Comparator<ProcessState>() {
@@ -2134,15 +2181,97 @@
pw.println();
}
- public static final class ProcessState {
+ public static class DurationsTable {
public final ProcessStats mStats;
+ public final String mName;
+ public int[] mDurationsTable;
+ public int mDurationsTableSize;
+
+ public DurationsTable(ProcessStats stats, String name) {
+ mStats = stats;
+ mName = name;
+ }
+
+ void copyDurationsTo(DurationsTable other) {
+ if (mDurationsTable != null) {
+ mStats.mAddLongTable = new int[mDurationsTable.length];
+ mStats.mAddLongTableSize = 0;
+ for (int i=0; i<mDurationsTableSize; i++) {
+ int origEnt = mDurationsTable[i];
+ int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ int newOff = mStats.addLongData(i, type, 1);
+ mStats.mAddLongTable[i] = newOff | type;
+ mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
+ }
+ other.mDurationsTable = mStats.mAddLongTable;
+ other.mDurationsTableSize = mStats.mAddLongTableSize;
+ } else {
+ other.mDurationsTable = null;
+ other.mDurationsTableSize = 0;
+ }
+ }
+
+ void addDurations(DurationsTable other) {
+ for (int i=0; i<other.mDurationsTableSize; i++) {
+ int ent = other.mDurationsTable[i];
+ int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
+ + other.mStats.getLong(ent, 0));
+ addDuration(state, other.mStats.getLong(ent, 0));
+ }
+ }
+
+ void resetDurationsSafely() {
+ mDurationsTable = null;
+ mDurationsTableSize = 0;
+ }
+
+ void writeDurationsToParcel(Parcel out) {
+ out.writeInt(mDurationsTableSize);
+ for (int i=0; i<mDurationsTableSize; i++) {
+ if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
+ + printLongOffset(mDurationsTable[i]));
+ out.writeInt(mDurationsTable[i]);
+ }
+ }
+
+ boolean readDurationsFromParcel(Parcel in) {
+ mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
+ if (mDurationsTable == BAD_TABLE) {
+ return false;
+ }
+ mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
+ return true;
+ }
+
+ void addDuration(int state, long dur) {
+ int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+ int off;
+ if (idx >= 0) {
+ off = mDurationsTable[idx];
+ } else {
+ mStats.mAddLongTable = mDurationsTable;
+ mStats.mAddLongTableSize = mDurationsTableSize;
+ off = mStats.addLongData(~idx, state, 1);
+ mDurationsTable = mStats.mAddLongTable;
+ mDurationsTableSize = mStats.mAddLongTableSize;
+ }
+ long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
+ + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
+ longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
+ }
+
+ long getDuration(int state, long now) {
+ int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+ return idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+ }
+ }
+
+ public static final class ProcessState extends DurationsTable {
public final ProcessState mCommonProcess;
public final String mPackage;
public final int mUid;
- public final String mName;
-
- int[] mDurationsTable;
- int mDurationsTableSize;
//final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
int mCurState = STATE_NOTHING;
@@ -2175,11 +2304,10 @@
* a single package running in a process. The initial state is not running.
*/
public ProcessState(ProcessStats processStats, String pkg, int uid, String name) {
- mStats = processStats;
+ super(processStats, name);
mCommonProcess = this;
mPackage = pkg;
mUid = uid;
- mName = name;
}
/**
@@ -2189,30 +2317,17 @@
*/
public ProcessState(ProcessState commonProcess, String pkg, int uid, String name,
long now) {
- mStats = commonProcess.mStats;
+ super(commonProcess.mStats, name);
mCommonProcess = commonProcess;
mPackage = pkg;
mUid = uid;
- mName = name;
mCurState = commonProcess.mCurState;
mStartTime = now;
}
ProcessState clone(String pkg, long now) {
ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now);
- if (mDurationsTable != null) {
- mStats.mAddLongTable = new int[mDurationsTable.length];
- mStats.mAddLongTableSize = 0;
- for (int i=0; i<mDurationsTableSize; i++) {
- int origEnt = mDurationsTable[i];
- int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mStats.addLongData(i, type, 1);
- mStats.mAddLongTable[i] = newOff | type;
- mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
- }
- pnew.mDurationsTable = mStats.mAddLongTable;
- pnew.mDurationsTableSize = mStats.mAddLongTableSize;
- }
+ copyDurationsTo(pnew);
if (mPssTable != null) {
mStats.mAddLongTable = new int[mPssTable.length];
mStats.mAddLongTableSize = 0;
@@ -2240,13 +2355,7 @@
}
void add(ProcessState other) {
- for (int i=0; i<other.mDurationsTableSize; i++) {
- int ent = other.mDurationsTable[i];
- int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
- + other.mStats.getLong(ent, 0));
- addDuration(state, other.mStats.getLong(ent, 0));
- }
+ addDurations(other);
for (int i=0; i<other.mPssTableSize; i++) {
int ent = other.mPssTable[i];
int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
@@ -2267,8 +2376,7 @@
}
void resetSafely(long now) {
- mDurationsTable = null;
- mDurationsTableSize = 0;
+ resetDurationsSafely();
mStartTime = now;
mLastPssState = STATE_NOTHING;
mLastPssTime = 0;
@@ -2294,12 +2402,7 @@
void writeToParcel(Parcel out, long now) {
out.writeInt(mMultiPackage ? 1 : 0);
- out.writeInt(mDurationsTableSize);
- for (int i=0; i<mDurationsTableSize; i++) {
- if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
- + printLongOffset(mDurationsTable[i]));
- out.writeInt(mDurationsTable[i]);
- }
+ writeDurationsToParcel(out);
out.writeInt(mPssTableSize);
for (int i=0; i<mPssTableSize; i++) {
if (DEBUG) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
@@ -2322,11 +2425,9 @@
mMultiPackage = multiPackage;
}
if (DEBUG) Slog.d(TAG, "Reading durations table...");
- mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
- if (mDurationsTable == BAD_TABLE) {
+ if (!readDurationsFromParcel(in)) {
return false;
}
- mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
if (DEBUG) Slog.d(TAG, "Reading pss table...");
mPssTable = mStats.readTableFromParcel(in, mName, "pss");
if (mPssTable == BAD_TABLE) {
@@ -2411,24 +2512,6 @@
mStartTime = now;
}
- void addDuration(int state, long dur) {
- int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- int off;
- if (idx >= 0) {
- off = mDurationsTable[idx];
- } else {
- mStats.mAddLongTable = mDurationsTable;
- mStats.mAddLongTableSize = mDurationsTableSize;
- off = mStats.addLongData(~idx, state, 1);
- mDurationsTable = mStats.mAddLongTable;
- mDurationsTableSize = mStats.mAddLongTableSize;
- }
- long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
- + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
- longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
- }
-
void incActiveServices() {
if (mCommonProcess != this) {
mCommonProcess.incActiveServices();
@@ -2470,7 +2553,8 @@
}
}
- public void addPss(long pss, long uss, boolean always) {
+ public void addPss(long pss, long uss, boolean always,
+ ArrayMap<String, ProcessState> pkgList) {
ensureNotDead();
if (!always) {
if (mLastPssState == mCurState && SystemClock.uptimeMillis()
@@ -2481,7 +2565,20 @@
mLastPssState = mCurState;
mLastPssTime = SystemClock.uptimeMillis();
if (mCurState != STATE_NOTHING) {
- addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
+ // First update the common process.
+ mCommonProcess.addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
+
+ // If the common process is not multi-package, there is nothing else to do.
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ if (pkgList != null) {
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).addPss(mCurState, 1,
+ pss, pss, pss, uss, uss, uss);
+ }
+ }
}
}
@@ -2632,8 +2729,7 @@
}
long getDuration(int state, long now) {
- int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+ long time = super.getDuration(state, now);
if (mCurState == state) {
time += now - mStartTime;
}
@@ -2676,10 +2772,8 @@
}
}
- public static final class ServiceState {
- final ProcessStats mStats;
+ public static final class ServiceState extends DurationsTable {
public final String mPackage;
- public final String mName;
public final String mProcessName;
ProcessState mProc;
@@ -2691,9 +2785,6 @@
public static final int SERVICE_EXEC = 3;
static final int SERVICE_COUNT = 4;
- int[] mDurationsTable;
- int mDurationsTableSize;
-
int mRunCount;
public int mRunState = STATE_NOTHING;
long mRunStartTime;
@@ -2712,9 +2803,8 @@
public ServiceState(ProcessStats processStats, String pkg, String name,
String processName, ProcessState proc) {
- mStats = processStats;
+ super(processStats, name);
mPackage = pkg;
- mName = name;
mProcessName = processName;
mProc = proc;
}
@@ -2743,11 +2833,7 @@
}
void add(ServiceState other) {
- for (int i=0; i<other.mDurationsTableSize; i++) {
- int ent = other.mDurationsTable[i];
- int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- addStateTime(state, other.mStats.getLong(ent, 0));
- }
+ addDurations(other);
mRunCount += other.mRunCount;
mStartedCount += other.mStartedCount;
mBoundCount += other.mBoundCount;
@@ -2755,22 +2841,16 @@
}
void resetSafely(long now) {
- mDurationsTable = null;
- mDurationsTableSize = 0;
+ resetDurationsSafely();
mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
- mStartedStartTime = mBoundStartTime = mExecStartTime = now;
+ mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
}
void writeToParcel(Parcel out, long now) {
- out.writeInt(mDurationsTableSize);
- for (int i=0; i<mDurationsTableSize; i++) {
- if (DEBUG) Slog.i(TAG, "Writing service in " + mPackage + " dur #" + i + ": "
- + printLongOffset(mDurationsTable[i]));
- out.writeInt(mDurationsTable[i]);
- }
+ writeDurationsToParcel(out);
out.writeInt(mRunCount);
out.writeInt(mStartedCount);
out.writeInt(mBoundCount);
@@ -2778,12 +2858,9 @@
}
boolean readFromParcel(Parcel in) {
- if (DEBUG) Slog.d(TAG, "Reading durations table...");
- mDurationsTable = mStats.readTableFromParcel(in, mPackage, "service");
- if (mDurationsTable == BAD_TABLE) {
+ if (!readDurationsFromParcel(in)) {
return false;
}
- mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
mRunCount = in.readInt();
mStartedCount = in.readInt();
mBoundCount = in.readInt();
@@ -2791,40 +2868,22 @@
return true;
}
- void addStateTime(int state, long time) {
- if (time > 0) {
- int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- int off;
- if (idx >= 0) {
- off = mDurationsTable[idx];
- } else {
- mStats.mAddLongTable = mDurationsTable;
- mStats.mAddLongTableSize = mDurationsTableSize;
- off = mStats.addLongData(~idx, state, 1);
- mDurationsTable = mStats.mAddLongTable;
- mDurationsTableSize = mStats.mAddLongTableSize;
- }
- long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += time;
- }
- }
-
void commitStateTime(long now) {
if (mRunState != STATE_NOTHING) {
- addStateTime(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
+ addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
mRunStartTime = now;
}
if (mStartedState != STATE_NOTHING) {
- addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+ addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
now - mStartedStartTime);
mStartedStartTime = now;
}
if (mBoundState != STATE_NOTHING) {
- addStateTime(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
+ addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
mBoundStartTime = now;
}
if (mExecState != STATE_NOTHING) {
- addStateTime(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
+ addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
mExecStartTime = now;
}
}
@@ -2834,7 +2893,7 @@
|| mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
if (mRunState != state) {
if (mRunState != STATE_NOTHING) {
- addStateTime(SERVICE_RUN + (mRunState*SERVICE_COUNT),
+ addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
now - mRunStartTime);
} else if (state != STATE_NOTHING) {
mRunCount++;
@@ -2852,7 +2911,7 @@
final int state = started ? memFactor : STATE_NOTHING;
if (mStartedState != state) {
if (mStartedState != STATE_NOTHING) {
- addStateTime(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
+ addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
now - mStartedStartTime);
} else if (started) {
mStartedCount++;
@@ -2878,7 +2937,7 @@
final int state = bound ? memFactor : STATE_NOTHING;
if (mBoundState != state) {
if (mBoundState != STATE_NOTHING) {
- addStateTime(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
+ addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
now - mBoundStartTime);
} else if (bound) {
mBoundCount++;
@@ -2896,7 +2955,7 @@
final int state = executing ? memFactor : STATE_NOTHING;
if (mExecState != state) {
if (mExecState != STATE_NOTHING) {
- addStateTime(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
+ addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
} else if (executing) {
mExecCount++;
}
@@ -2909,8 +2968,7 @@
private long getDuration(int opType, int curState, long startTime, int memFactor,
long now) {
int state = opType + (memFactor*SERVICE_COUNT);
- int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
+ long time = getDuration(state, now);
if (curState == memFactor) {
time += now - startTime;
}
@@ -2923,10 +2981,12 @@
= new ArrayMap<String, ProcessState>();
public final ArrayMap<String, ServiceState> mServices
= new ArrayMap<String, ServiceState>();
- final int mUid;
+ public final String mPackageName;
+ public final int mUid;
- public PackageState(int uid) {
+ public PackageState(String packageName, int uid) {
mUid = uid;
+ mPackageName = packageName;
}
}
@@ -2951,6 +3011,9 @@
}
void print(PrintWriter pw, long overallTime, boolean full) {
+ if (totalTime > overallTime) {
+ pw.print("*");
+ }
printPercent(pw, (double) totalTime / (double) overallTime);
if (numPss > 0) {
pw.print(" (");
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 15792e8..62f057f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -156,31 +156,32 @@
* Uses libmemtrack to retrieve graphics memory that the process is using.
* Any graphics memory reported in /proc/pid/smaps is not included here.
*/
-static int read_memtrack_memory(struct memtrack_proc* p, int pid, struct graphics_memory_pss* graphics_mem)
+static int read_memtrack_memory(struct memtrack_proc* p, int pid,
+ struct graphics_memory_pss* graphics_mem)
{
int err = memtrack_proc_get(p, pid);
if (err != 0) {
- ALOGE("failed to get memory consumption info: %d", err);
+ ALOGW("failed to get memory consumption info: %d", err);
return err;
}
ssize_t pss = memtrack_proc_graphics_pss(p);
if (pss < 0) {
- ALOGE("failed to get graphics pss: %d", pss);
+ ALOGW("failed to get graphics pss: %d", pss);
return pss;
}
graphics_mem->graphics = pss / 1024;
pss = memtrack_proc_gl_pss(p);
if (pss < 0) {
- ALOGE("failed to get gl pss: %d", pss);
+ ALOGW("failed to get gl pss: %d", pss);
return pss;
}
graphics_mem->gl = pss / 1024;
pss = memtrack_proc_other_pss(p);
if (pss < 0) {
- ALOGE("failed to get other pss: %d", pss);
+ ALOGW("failed to get other pss: %d", pss);
return pss;
}
graphics_mem->other = pss / 1024;
@@ -199,7 +200,7 @@
struct memtrack_proc* p = memtrack_proc_new();
if (p == NULL) {
- ALOGE("failed to create memtrack_proc");
+ ALOGW("failed to create memtrack_proc");
return -1;
}
@@ -418,8 +419,6 @@
stats[HEAP_GL].privateDirty = graphics_mem.gl;
stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
- } else {
- ALOGE("Failed to read gpu memory");
}
for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
@@ -623,7 +622,7 @@
close(fd);
if (len > 0) {
buffer[len] = 0;
- mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer);
+ mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer)/1024;
}
}
@@ -633,7 +632,7 @@
}
jlong* outArray = env->GetLongArrayElements(out, 0);
if (outArray != NULL) {
- for (int i=0; i<maxNum && tags[i]; i++) {
+ for (int i=0; i<maxNum; i++) {
outArray[i] = mem[i];
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b41b5b5..4c73cd7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -773,6 +773,13 @@
android:description="@string/permdesc_bluetoothAdmin"
android:label="@string/permlab_bluetoothAdmin" />
+ <!-- Allows applications to pair bluetooth devices without user interaction -->
+ <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
+ android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
+ android:protectionLevel="system|signature"
+ android:description="@string/permdesc_bluetoothPriv"
+ android:label="@string/permlab_bluetoothPriv" />
+
<!-- Allows bluetooth stack to access files
@hide This should only be used by Bluetooth apk.
-->
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
index f0d9b21..a804a8a 100644
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
index 458137c..778e4e6 100644
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
index f1209a2..77e69c7 100644
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
index 6c86258..edecb63 100644
--- a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6019e36..e39fd2a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -352,6 +352,10 @@
<!-- Wifi driver supports batched scan -->
<bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
+ <!-- Default wifi country code. If the device is going to be sold in the US this
+ needs to be US. Uses ISO 3166 country code -->
+ <string translatable="false" name="config_wifi_default_country_code">US</string>
+
<!-- Flag indicating whether the we should enable the automatic brightness in Settings.
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d0c24e2..6c334e2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1801,6 +1801,15 @@
<string name="permdesc_bluetoothAdmin" product="default">Allows the app to configure
the local Bluetooth phone, and to discover and pair with remote devices.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bluetoothPriv">allow Bluetooth pairing by Application</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bluetoothPriv" product="tablet">Allows the app to
+ pair with remote devices without user interaction.</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bluetoothPriv" product="default">Allows the app to
+ pair with remote devices without user interaction.</string>
+
<string name="permlab_accessWimaxState">connect and disconnect from WiMAX</string>
<string name="permdesc_accessWimaxState">Allows the app to determine whether
WiMAX is enabled and information about any WiMAX networks that are
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f739bed..c786888 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -817,6 +817,7 @@
<java-symbol type="string" name="wifi_tether_configure_ssid_default" />
<java-symbol type="string" name="wifi_watchdog_network_disabled" />
<java-symbol type="string" name="wifi_watchdog_network_disabled_detailed" />
+ <java-symbol type="string" name="config_wifi_default_country_code" />
<java-symbol type="string" name="imei" />
<java-symbol type="string" name="meid" />
<java-symbol type="string" name="granularity_label_character" />
diff --git a/docs/html/guide/topics/ui/controls/checkbox.jd b/docs/html/guide/topics/ui/controls/checkbox.jd
index 99140b5..2a64e38 100644
--- a/docs/html/guide/topics/ui/controls/checkbox.jd
+++ b/docs/html/guide/topics/ui/controls/checkbox.jd
@@ -94,7 +94,7 @@
android.view.View} that was clicked)</li>
</ul>
-<p class="note"><strong>Tip:</strong> If you need to change the radio button state
+<p class="note"><strong>Tip:</strong> If you need to change the checkbox state
yourself (such as when loading a saved {@link android.preference.CheckBoxPreference}),
use the {@link android.widget.CompoundButton#setChecked(boolean)} or {@link
android.widget.CompoundButton#toggle()} method.</p>
\ No newline at end of file
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 09767bf..d934c4b 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -593,7 +593,7 @@
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Send the negative button event back to the host activity
- mListener.onDialogPositiveClick(NoticeDialogFragment.this);
+ mListener.onDialogNegativeClick(NoticeDialogFragment.this);
}
});
return builder.create();
diff --git a/docs/html/training/articles/security-ssl.jd b/docs/html/training/articles/security-ssl.jd
index d3f68e2..f52865a 100644
--- a/docs/html/training/articles/security-ssl.jd
+++ b/docs/html/training/articles/security-ssl.jd
@@ -250,7 +250,7 @@
This is similar to an unknown certificate authority, so you can use the
same approach from the previous section.</p>
-<p>You can create yout own {@link javax.net.ssl.TrustManager},
+<p>You can create your own {@link javax.net.ssl.TrustManager},
this time trusting the server certificate directly. This has all of the
downsides discussed earlier of tying your app directly to a certificate, but can be done
securely. However, you should be careful to make sure your self-signed certificate has a
diff --git a/docs/html/training/articles/smp.jd b/docs/html/training/articles/smp.jd
index 0f667d7..7240eec 100644
--- a/docs/html/training/articles/smp.jd
+++ b/docs/html/training/articles/smp.jd
@@ -1057,7 +1057,7 @@
fix them. Before we do that, we need to discuss the use of a basic language
feature.</p>
-<h4 id="volatile">C/C+++ and "volatile"</h4>
+<h4 id="volatile">C/C++ and "volatile"</h4>
<p>When writing single-threaded code, declaring a variable “volatile” can be
very useful. The compiler will not omit or reorder accesses to volatile
diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
index 11a05e1..fb5096d 100644
--- a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
@@ -49,7 +49,8 @@
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
-boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre>
+boolean isConnected = activeNetwork != null &&
+ activeNetwork.isConnectedOrConnecting();</pre>
<h2 id="DetermineType">Determine the Type of your Internet Connection</h2>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index a3c9dac..77ac235 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -576,29 +576,6 @@
</li>
</ul>
</li>
- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>training/id-auth/index.html"
- description=
- "How to remember the user by account, authenticate the user, acquire user permission
- for the user's online data, and create custom accounts on the device."
- >Remembering Users</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>training/id-auth/identify.html">
- Remembering Your User
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/id-auth/authenticate.html">
- Authenticating to OAuth2 Services
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/id-auth/custom_auth.html">
- Creating a Custom Account Type
- </a>
- </li>
- </ul>
- </li>
<li class="nav-section">
<div class="nav-section-header">
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index deba2cc..def9aa7 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1772,6 +1772,9 @@
mSelectedSubtitleTrackIndex = -1;
}
setOnSubtitleDataListener(null);
+ if (track == null) {
+ return;
+ }
for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
if (mInbandSubtitleTracks[i] == track) {
Log.v(TAG, "Selecting subtitle track " + i);
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 5127479..06af5de 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -374,7 +374,7 @@
* Called when a sound has completed loading.
*
* @param soundPool SoundPool object from the load() method
- * @param soundPool the sample ID of the sound loaded.
+ * @param sampleId the sample ID of the sound loaded.
* @param status the status of the load operation (0 = success)
*/
public void onLoadComplete(SoundPool soundPool, int sampleId, int status);
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index 8090561..13205bc 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -21,6 +21,9 @@
import android.content.Context;
import android.media.SubtitleTrack.RenderingWidget;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.view.accessibility.CaptioningManager;
/**
@@ -37,6 +40,34 @@
private SubtitleTrack mSelectedTrack;
private boolean mShowing;
private CaptioningManager mCaptioningManager;
+ private Handler mHandler;
+
+ private static final int WHAT_SHOW = 1;
+ private static final int WHAT_HIDE = 2;
+ private static final int WHAT_SELECT_TRACK = 3;
+ private static final int WHAT_SELECT_DEFAULT_TRACK = 4;
+
+ private final Handler.Callback mCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case WHAT_SHOW:
+ doShow();
+ return true;
+ case WHAT_HIDE:
+ doHide();
+ return true;
+ case WHAT_SELECT_TRACK:
+ doSelectTrack((SubtitleTrack)msg.obj);
+ return true;
+ case WHAT_SELECT_DEFAULT_TRACK:
+ doSelectDefaultTrack();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
new CaptioningManager.CaptioningChangeListener() {
@@ -112,7 +143,7 @@
* in-band data from the {@link MediaPlayer}. However, this does
* not change the subtitle visibility.
*
- * Must be called from the UI thread.
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
*
* @param track The subtitle track to select. This must be one of the
* tracks in {@link #getTracks}.
@@ -122,9 +153,15 @@
if (track != null && !mTracks.contains(track)) {
return false;
}
+
+ processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_TRACK, track));
+ return true;
+ }
+
+ private void doSelectTrack(SubtitleTrack track) {
mTrackIsExplicit = true;
if (mSelectedTrack == track) {
- return true;
+ return;
}
if (mSelectedTrack != null) {
@@ -145,7 +182,6 @@
if (mListener != null) {
mListener.onSubtitleTrackSelected(track);
}
- return true;
}
/**
@@ -170,8 +206,6 @@
*
* The default values for these flags are DEFAULT=no, AUTOSELECT=yes
* and FORCED=no.
- *
- * Must be called from the UI thread.
*/
public SubtitleTrack getDefaultTrack() {
SubtitleTrack bestTrack = null;
@@ -226,8 +260,12 @@
private boolean mTrackIsExplicit = false;
private boolean mVisibilityIsExplicit = false;
- /** @hide - called from UI thread */
+ /** @hide - should be called from anchor thread */
public void selectDefaultTrack() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_DEFAULT_TRACK));
+ }
+
+ private void doSelectDefaultTrack() {
if (mTrackIsExplicit) {
// If track selection is explicit, but visibility
// is not, it falls back to the captioning setting
@@ -259,8 +297,9 @@
}
}
- /** @hide - called from UI thread */
+ /** @hide - must be called from anchor thread */
public void reset() {
+ checkAnchorLooper();
hide();
selectTrack(null);
mTracks.clear();
@@ -301,9 +340,13 @@
/**
* Show the selected (or default) subtitle track.
*
- * Must be called from the UI thread.
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
*/
public void show() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_SHOW));
+ }
+
+ private void doShow() {
mShowing = true;
mVisibilityIsExplicit = true;
if (mSelectedTrack != null) {
@@ -314,9 +357,13 @@
/**
* Hide the selected (or default) subtitle track.
*
- * Must be called from the UI thread.
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
*/
public void hide() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_HIDE));
+ }
+
+ private void doHide() {
mVisibilityIsExplicit = true;
if (mSelectedTrack != null) {
mSelectedTrack.hide();
@@ -384,25 +431,53 @@
* @hide
*/
public void setSubtitleWidget(RenderingWidget subtitleWidget);
+
+ /**
+ * Anchors provide the looper on which all track visibility changes
+ * (track.show/hide, setSubtitleWidget) will take place.
+ * @hide
+ */
+ public Looper getSubtitleLooper();
}
private Anchor mAnchor;
- /** @hide - called from UI thread */
+ /**
+ * @hide - called from anchor's looper (if any, both when unsetting and
+ * setting)
+ */
public void setAnchor(Anchor anchor) {
if (mAnchor == anchor) {
return;
}
if (mAnchor != null) {
+ checkAnchorLooper();
mAnchor.setSubtitleWidget(null);
}
mAnchor = anchor;
+ mHandler = null;
if (mAnchor != null) {
+ mHandler = new Handler(mAnchor.getSubtitleLooper(), mCallback);
+ checkAnchorLooper();
mAnchor.setSubtitleWidget(getRenderingWidget());
}
}
+ private void checkAnchorLooper() {
+ assert mHandler != null : "Should have a looper already";
+ assert Looper.myLooper() == mHandler.getLooper() : "Must be called from the anchor's looper";
+ }
+
+ private void processOnAnchor(Message m) {
+ assert mHandler != null : "Should have a looper already";
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ mHandler.dispatchMessage(m);
+ } else {
+ mHandler.sendMessage(m);
+ }
+ }
+
public interface Listener {
/**
* Called when a subtitle track has been selected.
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow.9.png
index 0240874..904d525 100644
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow.9.png
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_dir_shadow.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..0d75172
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..403eddb
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-hdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow.9.png
index 0240874..068619b 100644
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow.9.png
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_dir_shadow.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..0d75172
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..9a9cf5e
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-mdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow.9.png
index 0240874..e38a868 100644
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow.9.png
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_dir_shadow.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..0d75172
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..205c34b
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xhdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow.9.png
index 0240874..0b332e4 100644
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow.9.png
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_dir_shadow.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png
new file mode 100644
index 0000000..32b5f98
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_hairline_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png
new file mode 100644
index 0000000..f47d50a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable-xxhdpi/ic_drawer_tall_divider.9.png
Binary files differ
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
index 3bea166..851061f 100644
--- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -21,17 +21,18 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:orientation="horizontal">
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<FrameLayout
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_marginStart="12dp"
- android:layout_marginEnd="20dp"
- android:layout_gravity="center_vertical">
+ android:layout_marginEnd="20dp">
<ImageView
android:id="@+id/icon_mime"
@@ -49,11 +50,11 @@
</FrameLayout>
+ <!-- This is the one special case where we want baseline alignment! -->
<LinearLayout
- android:layout_width="0dip"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:layout_gravity="center_vertical"
android:orientation="horizontal">
<TextView
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
index 78735fd..9286277 100644
--- a/packages/DocumentsUI/res/layout-sw720dp/activity.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
@@ -17,7 +17,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<FrameLayout
android:layout_width="wrap_content"
@@ -47,7 +48,7 @@
<com.android.documentsui.DirectoryContainerView
android:id="@+id/container_directory"
android:layout_width="match_parent"
- android:layout_height="0dip"
+ android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/activity.xml
index 9937c39..2ef7e9c 100644
--- a/packages/DocumentsUI/res/layout/activity.xml
+++ b/packages/DocumentsUI/res/layout/activity.xml
@@ -27,7 +27,7 @@
<com.android.documentsui.DirectoryContainerView
android:id="@+id/container_directory"
android:layout_width="match_parent"
- android:layout_height="0dip"
+ android:layout_height="0dp"
android:layout_weight="1" />
<FrameLayout
diff --git a/packages/DocumentsUI/res/layout/fragment_roots.xml b/packages/DocumentsUI/res/layout/fragment_roots.xml
index 09782d9..c3a3da0 100644
--- a/packages/DocumentsUI/res/layout/fragment_roots.xml
+++ b/packages/DocumentsUI/res/layout/fragment_roots.xml
@@ -18,4 +18,4 @@
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:divider="@null" />
+ android:divider="@drawable/ic_drawer_hairline_divider" />
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
index 570b517..891f0a0 100644
--- a/packages/DocumentsUI/res/layout/fragment_save.xml
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -29,6 +29,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:baselineAligned="false"
android:gravity="center_vertical"
android:background="#ddd"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
@@ -44,7 +45,7 @@
<EditText
android:id="@android:id/title"
- android:layout_width="0dip"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index b745bb9..bb5dce1 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -28,37 +28,25 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="0dip"
+ android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="6dp"
- android:background="#fff">
-
- <FrameLayout
- android:id="@android:id/icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ImageView
- android:id="@+id/icon_mime"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
-
- <ImageView
- android:id="@+id/icon_thumb"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerCrop"
- android:contentDescription="@null" />
-
- </FrameLayout>
+ android:background="#fff"
+ android:foreground="@drawable/ic_grid_gradient_bg"
+ android:foregroundGravity="fill">
<ImageView
+ android:id="@+id/icon_mime"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:scaleType="fitXY"
- android:src="@drawable/ic_grid_gradient_bg"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ <ImageView
+ android:id="@+id/icon_thumb"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
android:contentDescription="@null" />
</FrameLayout>
@@ -67,7 +55,9 @@
android:id="@+id/line1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center_vertical"
android:orientation="horizontal"
+ android:baselineAligned="false"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
@@ -85,7 +75,7 @@
android:id="@android:id/icon1"
android:layout_width="@dimen/root_icon_size"
android:layout_height="@dimen/root_icon_size"
- android:layout_marginStart="8dip"
+ android:layout_marginStart="8dp"
android:scaleType="centerInside"
android:contentDescription="@null" />
@@ -95,16 +85,17 @@
android:id="@+id/line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center_vertical"
android:orientation="horizontal"
+ android:baselineAligned="false"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<TextView
android:id="@+id/date"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:minWidth="80dp"
+ android:layout_weight="0.5"
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
@@ -112,26 +103,20 @@
<TextView
android:id="@+id/size"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+ android:layout_weight="0.5"
android:layout_marginStart="8dp"
- android:minWidth="80dp"
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
style="@style/TextAppearance.Small" />
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
<ImageView
android:id="@android:id/icon2"
android:layout_width="@dimen/root_icon_size"
android:layout_height="@dimen/root_icon_size"
- android:layout_marginStart="8dip"
+ android:layout_marginStart="8dp"
android:scaleType="centerInside"
android:contentDescription="@null"
android:visibility="gone" />
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 84fda9d..4c5b2e3 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -21,17 +21,18 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:orientation="horizontal">
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<FrameLayout
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_marginStart="12dp"
- android:layout_marginEnd="20dp"
- android:layout_gravity="center_vertical">
+ android:layout_marginEnd="20dp">
<ImageView
android:id="@+id/icon_mime"
@@ -50,20 +51,20 @@
</FrameLayout>
<LinearLayout
- android:layout_width="0dip"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:layout_gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<TextView
android:id="@android:id/title"
- android:layout_width="0dip"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
@@ -75,7 +76,7 @@
android:id="@android:id/icon1"
android:layout_width="@dimen/root_icon_size"
android:layout_height="@dimen/root_icon_size"
- android:layout_marginStart="8dip"
+ android:layout_marginStart="8dp"
android:scaleType="centerInside"
android:contentDescription="@null" />
@@ -85,13 +86,15 @@
android:id="@+id/line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<TextView
android:id="@+id/date"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+ android:layout_weight="0.25"
android:minWidth="70dp"
android:singleLine="true"
android:ellipsize="marquee"
@@ -100,11 +103,11 @@
<TextView
android:id="@+id/size"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:minWidth="70dp"
+ android:layout_weight="0.25"
android:layout_marginStart="8dp"
+ android:minWidth="70dp"
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
@@ -114,8 +117,7 @@
android:id="@android:id/summary"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
+ android:layout_weight="0.5"
android:layout_marginStart="8dp"
android:singleLine="true"
android:ellipsize="marquee"
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
index 21be137..0bf6137 100644
--- a/packages/DocumentsUI/res/layout/item_loading_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -20,8 +20,8 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
android:orientation="horizontal">
<ProgressBar
diff --git a/packages/DocumentsUI/res/layout/item_loading_list.xml b/packages/DocumentsUI/res/layout/item_loading_list.xml
index 7da71e3..cdcd01d 100644
--- a/packages/DocumentsUI/res/layout/item_loading_list.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_list.xml
@@ -20,9 +20,8 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:orientation="horizontal">
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp">
<ProgressBar
android:layout_width="wrap_content"
diff --git a/packages/DocumentsUI/res/layout/item_message_list.xml b/packages/DocumentsUI/res/layout/item_message_list.xml
index ffda98c..2bcbc2d 100644
--- a/packages/DocumentsUI/res/layout/item_message_list.xml
+++ b/packages/DocumentsUI/res/layout/item_message_list.xml
@@ -21,15 +21,16 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:orientation="horizontal">
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<ImageView
android:id="@android:id/icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
- android:layout_marginEnd="8dip"
+ android:layout_marginEnd="8dp"
android:layout_gravity="center_vertical"
android:scaleType="centerInside"
android:contentDescription="@null" />
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index 98d78da..9b52d85 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -22,13 +22,14 @@
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:gravity="center_vertical"
android:orientation="horizontal"
+ android:baselineAligned="false"
android:background="@drawable/item_root">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
- android:layout_marginEnd="8dip"
+ android:layout_marginEnd="8dp"
android:scaleType="centerInside"
android:contentDescription="@null" />
diff --git a/packages/DocumentsUI/res/layout/item_root_spacer.xml b/packages/DocumentsUI/res/layout/item_root_spacer.xml
new file mode 100644
index 0000000..7d96ac8
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_root_spacer.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/ic_drawer_tall_divider" />
diff --git a/packages/DocumentsUI/res/layout/item_title.xml b/packages/DocumentsUI/res/layout/item_title.xml
index 7eb100a..58016f1 100644
--- a/packages/DocumentsUI/res/layout/item_title.xml
+++ b/packages/DocumentsUI/res/layout/item_title.xml
@@ -21,7 +21,8 @@
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:gravity="center_vertical"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:baselineAligned="false">
<ImageView
android:id="@+id/subdir"
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 9d92cd8..48bfaf0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -25,6 +25,7 @@
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -35,6 +36,8 @@
import com.android.documentsui.model.DocumentInfo;
+import java.io.FileNotFoundException;
+
/**
* Dialog to create a new directory.
*/
@@ -64,24 +67,45 @@
@Override
public void onClick(DialogInterface dialog, int which) {
final String displayName = text1.getText().toString();
-
- final DocumentsActivity activity = (DocumentsActivity) getActivity();
- final DocumentInfo cwd = activity.getCurrentDirectory();
-
- try {
- final Uri childUri = DocumentsContract.createDocument(
- resolver, cwd.derivedUri, Document.MIME_TYPE_DIR, displayName);
-
- // Navigate into newly created child
- final DocumentInfo childDoc = DocumentInfo.fromUri(resolver, childUri);
- activity.onDocumentPicked(childDoc);
- } catch (Exception e) {
- Toast.makeText(context, R.string.create_error, Toast.LENGTH_SHORT).show();
- }
+ new CreateDirectoryTask(displayName).execute();
}
});
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
+
+ private class CreateDirectoryTask extends AsyncTask<Void, Void, DocumentInfo> {
+ private final String mDisplayName;
+
+ public CreateDirectoryTask(String displayName) {
+ mDisplayName = displayName;
+ }
+
+ @Override
+ protected DocumentInfo doInBackground(Void... params) {
+ final DocumentsActivity activity = (DocumentsActivity) getActivity();
+ final ContentResolver resolver = activity.getContentResolver();
+
+ final DocumentInfo cwd = activity.getCurrentDirectory();
+ final Uri childUri = DocumentsContract.createDocument(
+ resolver, cwd.derivedUri, Document.MIME_TYPE_DIR, mDisplayName);
+ try {
+ return DocumentInfo.fromUri(resolver, childUri);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(DocumentInfo result) {
+ final DocumentsActivity activity = (DocumentsActivity) getActivity();
+ if (result != null) {
+ // Navigate into newly created child
+ activity.onDocumentPicked(result);
+ } else {
+ Toast.makeText(activity, R.string.create_error, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index c46dfb2..1f11aed 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -742,7 +742,6 @@
final View line1 = convertView.findViewById(R.id.line1);
final View line2 = convertView.findViewById(R.id.line2);
- final View icon = convertView.findViewById(android.R.id.icon);
final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
final ImageView iconThumb = (ImageView) convertView.findViewById(R.id.icon_thumb);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
@@ -786,10 +785,12 @@
// loaded in background.
if (cacheHit) {
iconMime.setAlpha(0f);
+ iconMime.setImageDrawable(null);
iconThumb.setAlpha(1f);
} else {
iconMime.setAlpha(1f);
iconThumb.setAlpha(0f);
+ iconThumb.setImageDrawable(null);
if (docIcon != 0) {
iconMime.setImageDrawable(
IconUtils.loadPackageIcon(context, docAuthority, docIcon));
@@ -895,12 +896,14 @@
final boolean enabled = isDocumentEnabled(docMimeType, docFlags);
if (enabled) {
setEnabledRecursive(convertView, true);
- icon.setAlpha(1f);
+ iconMime.setAlpha(1f);
+ iconThumb.setAlpha(1f);
if (icon1 != null) icon1.setAlpha(1f);
if (icon2 != null) icon2.setAlpha(1f);
} else {
setEnabledRecursive(convertView, false);
- icon.setAlpha(0.5f);
+ iconMime.setAlpha(0.5f);
+ iconThumb.setAlpha(0.5f);
if (icon1 != null) icon1.setAlpha(0.5f);
if (icon2 != null) icon2.setAlpha(0.5f);
}
@@ -991,10 +994,11 @@
mIconThumb.setTag(null);
mIconThumb.setImageBitmap(result);
- mIconMime.setAlpha(1f);
+ final float targetAlpha = mIconMime.isEnabled() ? 1f : 0.5f;
+ mIconMime.setAlpha(targetAlpha);
mIconMime.animate().alpha(0f).start();
mIconThumb.setAlpha(0f);
- mIconThumb.animate().alpha(1f).start();
+ mIconThumb.animate().alpha(targetAlpha).start();
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 8627ecf..0b3ecf8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -63,6 +63,9 @@
}
public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
+
+ private static final String[] SEARCH_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };
+
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
private final int mType;
@@ -164,8 +167,7 @@
if (mType == DirectoryFragment.TYPE_SEARCH) {
// Filter directories out of search results, for now
- cursor = new FilteringCursorWrapper(cursor, null, new String[] {
- Document.MIME_TYPE_DIR });
+ cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
} else {
// Normal directories should have sorting applied
cursor = new SortingCursorWrapper(cursor, result.sortOrder);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 72fdc57..4caec8f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -854,14 +854,7 @@
mState.stackTouched = true;
if (!mRoots.isRecentsRoot(root)) {
- try {
- final Uri uri = DocumentsContract.buildDocumentUri(root.authority, root.documentId);
- final DocumentInfo doc = DocumentInfo.fromUri(getContentResolver(), uri);
- mState.stack.push(doc);
- mState.stackTouched = true;
- onCurrentDirectoryChanged(ANIM_SIDE);
- } catch (FileNotFoundException e) {
- }
+ new PickRootTask(root).execute();
} else {
onCurrentDirectoryChanged(ANIM_SIDE);
}
@@ -871,6 +864,34 @@
}
}
+ private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
+ private RootInfo mRoot;
+
+ public PickRootTask(RootInfo root) {
+ mRoot = root;
+ }
+
+ @Override
+ protected DocumentInfo doInBackground(Void... params) {
+ try {
+ final Uri uri = DocumentsContract.buildDocumentUri(
+ mRoot.authority, mRoot.documentId);
+ return DocumentInfo.fromUri(getContentResolver(), uri);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(DocumentInfo result) {
+ if (result != null) {
+ mState.stack.push(result);
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_SIDE);
+ }
+ }
+ }
+
public void onAppPicked(ResolveInfo info) {
final Intent intent = new Intent(getIntent());
intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
@@ -909,7 +930,7 @@
onCurrentDirectoryChanged(ANIM_DOWN);
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
// Explicit file picked, return
- onFinished(doc.derivedUri);
+ new ExistingFinishTask(doc.derivedUri).execute();
} else if (mState.action == ACTION_CREATE) {
// Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc);
@@ -943,29 +964,19 @@
for (int i = 0; i < size; i++) {
uris[i] = docs.get(i).derivedUri;
}
- onFinished(uris);
+ new ExistingFinishTask(uris).execute();
}
}
public void onSaveRequested(DocumentInfo replaceTarget) {
- onFinished(replaceTarget.derivedUri);
+ new ExistingFinishTask(replaceTarget.derivedUri).execute();
}
public void onSaveRequested(String mimeType, String displayName) {
- final DocumentInfo cwd = getCurrentDirectory();
-
- final Uri childUri = DocumentsContract.createDocument(
- getContentResolver(), cwd.derivedUri, mimeType, displayName);
- if (childUri != null) {
- onFinished(childUri);
- } else {
- Toast.makeText(this, R.string.save_error, Toast.LENGTH_SHORT).show();
- }
+ new CreateFinishTask(mimeType, displayName).execute();
}
- private void onFinished(Uri... uris) {
- Log.d(TAG, "onFinished() " + Arrays.toString(uris));
-
+ private void saveStackBlocking() {
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
@@ -973,6 +984,7 @@
if (mState.action == ACTION_CREATE) {
// Remember stack for last create
values.clear();
+ values.put(RecentColumns.KEY, mState.stack.buildKey());
values.put(RecentColumns.STACK, rawStack);
resolver.insert(RecentsProvider.buildRecent(), values);
}
@@ -983,6 +995,10 @@
values.put(ResumeColumns.STACK, rawStack);
values.put(ResumeColumns.EXTERNAL, 0);
resolver.insert(RecentsProvider.buildResume(packageName), values);
+ }
+
+ private void onFinished(Uri... uris) {
+ Log.d(TAG, "onFinished() " + Arrays.toString(uris));
final Intent intent = new Intent();
if (uris.length == 1) {
@@ -1008,6 +1024,56 @@
finish();
}
+ private class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
+ private final String mMimeType;
+ private final String mDisplayName;
+
+ public CreateFinishTask(String mimeType, String displayName) {
+ mMimeType = mimeType;
+ mDisplayName = displayName;
+ }
+
+ @Override
+ protected Uri doInBackground(Void... params) {
+ final DocumentInfo cwd = getCurrentDirectory();
+ final Uri childUri = DocumentsContract.createDocument(
+ getContentResolver(), cwd.derivedUri, mMimeType, mDisplayName);
+ if (childUri != null) {
+ saveStackBlocking();
+ }
+ return childUri;
+ }
+
+ @Override
+ protected void onPostExecute(Uri result) {
+ if (result != null) {
+ onFinished(result);
+ } else {
+ Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
+ .show();
+ }
+ }
+ }
+
+ private class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
+ private final Uri[] mUris;
+
+ public ExistingFinishTask(Uri... uris) {
+ mUris = uris;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ saveStackBlocking();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onFinished(mUris);
+ }
+ }
+
public static class State implements android.os.Parcelable {
public int action;
public String[] acceptMimes;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 5f56963..52d816f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -34,10 +34,15 @@
private int mCount;
public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) {
- this(cursor, acceptMimes, null);
+ this(cursor, acceptMimes, null, Long.MIN_VALUE);
}
public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes, String[] rejectMimes) {
+ this(cursor, acceptMimes, rejectMimes, Long.MIN_VALUE);
+ }
+
+ public FilteringCursorWrapper(
+ Cursor cursor, String[] acceptMimes, String[] rejectMimes, long rejectBefore) {
mCursor = cursor;
final int count = cursor.getCount();
@@ -47,9 +52,14 @@
while (cursor.moveToNext()) {
final String mimeType = cursor.getString(
cursor.getColumnIndex(Document.COLUMN_MIME_TYPE));
+ final long lastModified = cursor.getLong(
+ cursor.getColumnIndex(Document.COLUMN_LAST_MODIFIED));
if (rejectMimes != null && MimePredicate.mimeMatches(rejectMimes, mimeType)) {
continue;
}
+ if (lastModified < rejectBefore) {
+ continue;
+ }
if (MimePredicate.mimeMatches(acceptMimes, mimeType)) {
mPosition[mCount++] = cursor.getPosition();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index e390456..9a4fb7d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -26,9 +26,11 @@
import android.database.Cursor;
import android.database.MergeCursor;
import android.net.Uri;
+import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.text.format.DateUtils;
import android.util.Log;
import com.android.documentsui.DocumentsActivity.State;
@@ -54,17 +56,23 @@
public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
private static final boolean LOGD = true;
- public static final int MAX_OUTSTANDING_RECENTS = 2;
+ // TODO: adjust for svelte devices
+ // TODO: add support for oneway queries to avoid wedging loader
+ private static final int MAX_OUTSTANDING_RECENTS = 2;
/**
* Time to wait for first pass to complete before returning partial results.
*/
- public static final int MAX_FIRST_PASS_WAIT_MILLIS = 500;
+ private static final int MAX_FIRST_PASS_WAIT_MILLIS = 500;
- /**
- * Maximum documents from a single root.
- */
- public static final int MAX_DOCS_FROM_ROOT = 64;
+ /** Maximum documents from a single root. */
+ private static final int MAX_DOCS_FROM_ROOT = 64;
+
+ /** Ignore documents older than this age. */
+ private static final long REJECT_OLDER_THAN = 45 * DateUtils.DAY_IN_MILLIS;
+
+ /** MIME types that should always be excluded from recents. */
+ private static final String[] RECENT_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };
private static final ExecutorService sExecutor = buildExecutor();
@@ -173,6 +181,8 @@
}
}
+ final long rejectBefore = System.currentTimeMillis() - REJECT_OLDER_THAN;
+
// Collect all finished tasks
List<Cursor> cursors = Lists.newArrayList();
for (RecentTask task : mTasks.values()) {
@@ -180,7 +190,7 @@
try {
final Cursor cursor = task.get();
final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
- cursor, mState.acceptMimes, new String[] { Document.MIME_TYPE_DIR }) {
+ cursor, mState.acceptMimes, RECENT_REJECT_MIMES, rejectBefore) {
@Override
public void close() {
// Ignored, since we manage cursor lifecycle internally
@@ -203,11 +213,22 @@
final DirectoryResult result = new DirectoryResult();
result.sortOrder = SORT_ORDER_LAST_MODIFIED;
- if (cursors.size() > 0) {
- final MergeCursor merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
- final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder);
- result.cursor = sorted;
+ // Hint to UI if we're still loading
+ final Bundle extras = new Bundle();
+ if (cursors.size() != mTasks.size()) {
+ extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
}
+
+ final MergeCursor merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
+ final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder) {
+ @Override
+ public Bundle getExtras() {
+ return extras;
+ }
+ };
+
+ result.cursor = sorted;
+
return result;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index c975382..3954173 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -66,6 +66,7 @@
*/
public class RecentsCreateFragment extends Fragment {
+ private View mEmptyView;
private ListView mListView;
private DocumentStackAdapter mAdapter;
@@ -87,6 +88,8 @@
final View view = inflater.inflate(R.layout.fragment_directory, container, false);
+ mEmptyView = view.findViewById(android.R.id.empty);
+
mListView = (ListView) view.findViewById(R.id.list);
mListView.setOnItemClickListener(mItemListener);
@@ -189,6 +192,13 @@
public void swapStacks(List<DocumentStack> stacks) {
mStacks = stacks;
+
+ if (isEmpty()) {
+ mEmptyView.setVisibility(View.VISIBLE);
+ } else {
+ mEmptyView.setVisibility(View.GONE);
+ }
+
notifyDataSetChanged();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 7386cae..4313fa7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -33,7 +33,7 @@
public class RecentsProvider extends ContentProvider {
private static final String TAG = "RecentsProvider";
- public static final long MAX_HISTORY_IN_MILLIS = DateUtils.DAY_IN_MILLIS * 45;
+ public static final long MAX_HISTORY_IN_MILLIS = 45 * DateUtils.DAY_IN_MILLIS;
private static final String AUTHORITY = "com.android.documentsui.recents";
@@ -56,6 +56,7 @@
public static final String TABLE_RESUME = "resume";
public static class RecentColumns {
+ public static final String KEY = "key";
public static final String STACK = "stack";
public static final String TIMESTAMP = "timestamp";
}
@@ -99,16 +100,18 @@
private static final int VERSION_INIT = 1;
private static final int VERSION_AS_BLOB = 3;
private static final int VERSION_ADD_EXTERNAL = 4;
+ private static final int VERSION_ADD_RECENT_KEY = 5;
public DatabaseHelper(Context context) {
- super(context, DB_NAME, null, VERSION_ADD_EXTERNAL);
+ super(context, DB_NAME, null, VERSION_ADD_RECENT_KEY);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_RECENT + " (" +
- RecentColumns.STACK + " BLOB PRIMARY KEY ON CONFLICT REPLACE," +
+ RecentColumns.KEY + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
+ RecentColumns.STACK + " BLOB DEFAULT NULL," +
RecentColumns.TIMESTAMP + " INTEGER" +
")");
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 15af8aa..e3908e9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -99,7 +99,8 @@
*/
public void updateAsync() {
// Special root for recents
- mRecentsRoot.rootType = Root.ROOT_TYPE_SHORTCUT;
+ mRecentsRoot.authority = null;
+ mRecentsRoot.rootId = null;
mRecentsRoot.icon = R.drawable.ic_root_recent;
mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE;
mRecentsRoot.title = mContext.getString(R.string.root_recent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index d602622..2fb12bb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -26,7 +26,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
-import android.provider.DocumentsContract.Root;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.LayoutInflater;
@@ -37,16 +36,16 @@
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
-import android.widget.Space;
import android.widget.TextView;
import com.android.documentsui.DocumentsActivity.State;
-import com.android.documentsui.SectionedListAdapter.SectionAdapter;
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;
@@ -56,7 +55,7 @@
public class RootsFragment extends Fragment {
private ListView mList;
- private SectionedRootsAdapter mAdapter;
+ private RootsAdapter mAdapter;
private LoaderCallbacks<Collection<RootInfo>> mCallbacks;
@@ -112,7 +111,7 @@
final Intent includeApps = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
- mAdapter = new SectionedRootsAdapter(context, result, includeApps);
+ mAdapter = new RootsAdapter(context, result, includeApps);
mList.setAdapter(mAdapter);
onCurrentRootChanged();
@@ -154,136 +153,148 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
- final Object item = mAdapter.getItem(position);
- if (item instanceof RootInfo) {
- activity.onRootPicked((RootInfo) item, true);
- } else if (item instanceof ResolveInfo) {
- activity.onAppPicked((ResolveInfo) item);
+ final Item item = mAdapter.getItem(position);
+ if (item instanceof RootItem) {
+ activity.onRootPicked(((RootItem) item).root, true);
+ } else if (item instanceof AppItem) {
+ activity.onAppPicked(((AppItem) item).info);
} else {
throw new IllegalStateException("Unknown root: " + item);
}
}
};
- private static class RootsAdapter extends ArrayAdapter<RootInfo> implements SectionAdapter {
- public RootsAdapter(Context context) {
- super(context, 0);
+ private static abstract class Item {
+ private final int mLayoutId;
+
+ public Item(int layoutId) {
+ mLayoutId = layoutId;
+ }
+
+ public View getView(View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext())
+ .inflate(mLayoutId, parent, false);
+ }
+ bindView(convertView);
+ return convertView;
+ }
+
+ public abstract void bindView(View convertView);
+ }
+
+ private static class RootItem extends Item {
+ public final RootInfo root;
+
+ public RootItem(RootInfo root) {
+ super(R.layout.item_root);
+ this.root = root;
}
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final Context context = parent.getContext();
- if (convertView == null) {
- convertView = LayoutInflater.from(context)
- .inflate(R.layout.item_root, parent, false);
- }
-
+ public void bindView(View convertView) {
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
- final RootInfo root = getItem(position);
+ final Context context = convertView.getContext();
icon.setImageDrawable(root.loadIcon(context));
title.setText(root.title);
- // Device summary is always available space
- final String summaryText;
- if (root.rootType == Root.ROOT_TYPE_DEVICE && root.availableBytes >= 0) {
+ // Show available space if no summary
+ String summaryText = root.summary;
+ if (TextUtils.isEmpty(summaryText) && root.availableBytes >= 0) {
summaryText = context.getString(R.string.root_available_bytes,
Formatter.formatFileSize(context, root.availableBytes));
- } else {
- summaryText = root.summary;
}
summary.setText(summaryText);
summary.setVisibility(TextUtils.isEmpty(summaryText) ? View.GONE : View.VISIBLE);
-
- return convertView;
- }
-
- @Override
- public View getHeaderView(View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = new Space(parent.getContext());
- }
- return convertView;
}
}
- private static class AppsAdapter extends ArrayAdapter<ResolveInfo> implements SectionAdapter {
- public AppsAdapter(Context context) {
- super(context, 0);
+ private static class SpacerItem extends Item {
+ public SpacerItem() {
+ super(R.layout.item_root_spacer);
}
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final Context context = parent.getContext();
- final PackageManager pm = context.getPackageManager();
- if (convertView == null) {
- convertView = LayoutInflater.from(context)
- .inflate(R.layout.item_root, parent, false);
- }
+ public void bindView(View convertView) {
+ // Nothing to bind
+ }
+ }
+ private static class AppItem extends Item {
+ public final ResolveInfo info;
+
+ public AppItem(ResolveInfo info) {
+ super(R.layout.item_root);
+ this.info = info;
+ }
+
+ @Override
+ public void bindView(View convertView) {
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
- final ResolveInfo info = getItem(position);
+ final PackageManager pm = convertView.getContext().getPackageManager();
icon.setImageDrawable(info.loadIcon(pm));
title.setText(info.loadLabel(pm));
// TODO: match existing summary behavior from disambig dialog
summary.setVisibility(View.GONE);
-
- return convertView;
- }
-
- @Override
- public View getHeaderView(View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_root_header, parent, false);
- }
-
- final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- title.setText(R.string.root_type_apps);
-
- return convertView;
}
}
- private static class SectionedRootsAdapter extends SectionedListAdapter {
- private final RootsAdapter mRecent;
- private final RootsAdapter mServices;
- private final RootsAdapter mShortcuts;
- private final RootsAdapter mDevices;
- private final AppsAdapter mApps;
+ private static class RootsAdapter extends ArrayAdapter<Item> {
+ public RootsAdapter(Context context, Collection<RootInfo> roots, Intent includeApps) {
+ super(context, 0);
- public SectionedRootsAdapter(
- Context context, Collection<RootInfo> roots, Intent includeApps) {
- mRecent = new RootsAdapter(context);
- mServices = new RootsAdapter(context);
- mShortcuts = new RootsAdapter(context);
- mDevices = new RootsAdapter(context);
- mApps = new AppsAdapter(context);
+ RootItem recents = null;
+ RootItem images = null;
+ RootItem videos = null;
+ RootItem audio = null;
+ RootItem downloads = null;
+
+ final List<RootInfo> clouds = Lists.newArrayList();
+ final List<RootInfo> locals = Lists.newArrayList();
for (RootInfo root : roots) {
- if (root.authority == null) {
- mRecent.add(root);
- continue;
+ if (root.isRecents()) {
+ recents = new RootItem(root);
+ } else if (root.isExternalStorage()) {
+ locals.add(root);
+ } else if (root.isDownloads()) {
+ downloads = new RootItem(root);
+ } else if (root.isImages()) {
+ images = new RootItem(root);
+ } else if (root.isVideos()) {
+ videos = new RootItem(root);
+ } else if (root.isAudio()) {
+ audio = new RootItem(root);
+ } else {
+ clouds.add(root);
}
+ }
- switch (root.rootType) {
- case Root.ROOT_TYPE_SERVICE:
- mServices.add(root);
- break;
- case Root.ROOT_TYPE_SHORTCUT:
- mShortcuts.add(root);
- break;
- case Root.ROOT_TYPE_DEVICE:
- mDevices.add(root);
- break;
- }
+ final RootComparator comp = new RootComparator();
+ Collections.sort(clouds, comp);
+ Collections.sort(locals, comp);
+
+ if (recents != null) add(recents);
+
+ for (RootInfo cloud : clouds) {
+ add(new RootItem(cloud));
+ }
+
+ if (images != null) add(images);
+ if (videos != null) add(videos);
+ if (audio != null) add(audio);
+ if (downloads != null) add(downloads);
+
+ for (RootInfo local : locals) {
+ add(new RootItem(local));
}
if (includeApps != null) {
@@ -291,34 +302,53 @@
final List<ResolveInfo> infos = pm.queryIntentActivities(
includeApps, PackageManager.MATCH_DEFAULT_ONLY);
+ final List<AppItem> apps = Lists.newArrayList();
+
// Omit ourselves from the list
for (ResolveInfo info : infos) {
if (!context.getPackageName().equals(info.activityInfo.packageName)) {
- mApps.add(info);
+ apps.add(new AppItem(info));
+ }
+ }
+
+ if (apps.size() > 0) {
+ add(new SpacerItem());
+ for (Item item : apps) {
+ add(item);
}
}
}
+ }
- final RootComparator comp = new RootComparator();
- mServices.sort(comp);
- mShortcuts.sort(comp);
- mDevices.sort(comp);
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final Item item = getItem(position);
+ return item.getView(convertView, parent);
+ }
- if (mRecent.getCount() > 0) {
- addSection(mRecent);
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItemViewType(position) != 1;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ final Item item = getItem(position);
+ if (item instanceof RootItem || item instanceof AppItem) {
+ return 0;
+ } else {
+ return 1;
}
- if (mServices.getCount() > 0) {
- addSection(mServices);
- }
- if (mShortcuts.getCount() > 0) {
- addSection(mShortcuts);
- }
- if (mDevices.getCount() > 0) {
- addSection(mDevices);
- }
- if (mApps.getCount() > 0) {
- addSection(mApps);
- }
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
index 57fc7e4..1a47308 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
@@ -213,8 +213,13 @@
if (DocumentsContract.isDocumentUri(this, uri)) {
result += "; DOC_ID";
}
- getContentResolver()
- .takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ try {
+ getContentResolver().takePersistableUriPermission(
+ uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ } catch (SecurityException e) {
+ result += "; FAILED TO TAKE";
+ Log.e(TAG, "Failed to take", e);
+ }
InputStream is = null;
try {
is = getContentResolver().openInputStream(uri);
@@ -222,7 +227,7 @@
result += "; read length=" + length;
} catch (Exception e) {
result += "; ERROR";
- Log.w(TAG, "Failed to read " + uri, e);
+ Log.e(TAG, "Failed to read " + uri, e);
} finally {
IoUtils.closeQuietly(is);
}
@@ -235,15 +240,20 @@
if (DocumentsContract.isDocumentUri(this, uri)) {
result += "; DOC_ID";
}
- getContentResolver()
- .takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ try {
+ getContentResolver().takePersistableUriPermission(
+ uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ } catch (SecurityException e) {
+ result += "; FAILED TO TAKE";
+ Log.e(TAG, "Failed to take", e);
+ }
OutputStream os = null;
try {
os = getContentResolver().openOutputStream(uri);
os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
} catch (Exception e) {
result += "; ERROR";
- Log.w(TAG, "Failed to write " + uri, e);
+ Log.e(TAG, "Failed to write " + uri, e);
} finally {
IoUtils.closeQuietly(os);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
index 0a378c0..28bab6c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -71,6 +71,25 @@
}
}
+ /**
+ * Build key that uniquely identifies this stack. It omits most of the raw
+ * details included in {@link #write(DataOutputStream)}, since they change
+ * too regularly to be used as a key.
+ */
+ public String buildKey() {
+ final StringBuilder builder = new StringBuilder();
+ if (root != null) {
+ builder.append(root.authority).append('#');
+ builder.append(root.rootId).append('#');
+ } else {
+ builder.append("[null]").append('#');
+ }
+ for (DocumentInfo doc : this) {
+ builder.append(doc.documentId).append('#');
+ }
+ return builder.toString();
+ }
+
@Override
public void reset() {
clear();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 014901a..e220c9e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -42,10 +42,10 @@
*/
public class RootInfo implements Durable, Parcelable {
private static final int VERSION_INIT = 1;
+ private static final int VERSION_DROP_TYPE = 2;
public String authority;
public String rootId;
- public int rootType;
public int flags;
public int icon;
public String title;
@@ -67,7 +67,6 @@
public void reset() {
authority = null;
rootId = null;
- rootType = 0;
flags = 0;
icon = 0;
title = null;
@@ -85,10 +84,9 @@
public void read(DataInputStream in) throws IOException {
final int version = in.readInt();
switch (version) {
- case VERSION_INIT:
+ case VERSION_DROP_TYPE:
authority = DurableUtils.readNullableString(in);
rootId = DurableUtils.readNullableString(in);
- rootType = in.readInt();
flags = in.readInt();
icon = in.readInt();
title = DurableUtils.readNullableString(in);
@@ -105,10 +103,9 @@
@Override
public void write(DataOutputStream out) throws IOException {
- out.writeInt(VERSION_INIT);
+ out.writeInt(VERSION_DROP_TYPE);
DurableUtils.writeNullableString(out, authority);
DurableUtils.writeNullableString(out, rootId);
- out.writeInt(rootType);
out.writeInt(flags);
out.writeInt(icon);
DurableUtils.writeNullableString(out, title);
@@ -146,7 +143,6 @@
final RootInfo root = new RootInfo();
root.authority = authority;
root.rootId = getCursorString(cursor, Root.COLUMN_ROOT_ID);
- root.rootType = getCursorInt(cursor, Root.COLUMN_ROOT_TYPE);
root.flags = getCursorInt(cursor, Root.COLUMN_FLAGS);
root.icon = getCursorInt(cursor, Root.COLUMN_ICON);
root.title = getCursorString(cursor, Root.COLUMN_TITLE);
@@ -162,25 +158,44 @@
derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
// TODO: remove these special case icons
- if ("com.android.externalstorage.documents".equals(authority)) {
- if ("documents".equals(rootId)) {
- derivedIcon = R.drawable.ic_doc_text;
- } else {
- derivedIcon = R.drawable.ic_root_sdcard;
- }
- }
- if ("com.android.providers.downloads.documents".equals(authority)) {
+ if (isExternalStorage()) {
+ derivedIcon = R.drawable.ic_root_sdcard;
+ } else if (isDownloads()) {
derivedIcon = R.drawable.ic_root_download;
+ } else if (isImages()) {
+ derivedIcon = R.drawable.ic_doc_image;
+ } else if (isVideos()) {
+ derivedIcon = R.drawable.ic_doc_video;
+ } else if (isAudio()) {
+ derivedIcon = R.drawable.ic_doc_audio;
}
- if ("com.android.providers.media.documents".equals(authority)) {
- if ("images_root".equals(rootId)) {
- derivedIcon = R.drawable.ic_doc_image;
- } else if ("videos_root".equals(rootId)) {
- derivedIcon = R.drawable.ic_doc_video;
- } else if ("audio_root".equals(rootId)) {
- derivedIcon = R.drawable.ic_doc_audio;
- }
- }
+ }
+
+ public boolean isRecents() {
+ return authority == null && rootId == null;
+ }
+
+ public boolean isExternalStorage() {
+ return "com.android.externalstorage.documents".equals(authority);
+ }
+
+ public boolean isDownloads() {
+ return "com.android.providers.downloads.documents".equals(authority);
+ }
+
+ public boolean isImages() {
+ return "com.android.providers.media.documents".equals(authority)
+ && "images_root".equals(rootId);
+ }
+
+ public boolean isVideos() {
+ return "com.android.providers.media.documents".equals(authority)
+ && "videos_root".equals(rootId);
+ }
+
+ public boolean isAudio() {
+ return "com.android.providers.media.documents".equals(authority)
+ && "audio_root".equals(rootId);
}
@Override
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index ed28da5..9328b33 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -47,9 +47,8 @@
// docId format: root:path/to/file
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
- Root.COLUMN_ROOT_ID, Root.COLUMN_ROOT_TYPE, Root.COLUMN_FLAGS, Root.COLUMN_ICON,
- Root.COLUMN_TITLE, Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID,
- Root.COLUMN_AVAILABLE_BYTES,
+ Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
+ Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES,
};
private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
@@ -59,7 +58,6 @@
private static class RootInfo {
public String rootId;
- public int rootType;
public int flags;
public String title;
public String docId;
@@ -84,7 +82,6 @@
final RootInfo root = new RootInfo();
root.rootId = rootId;
- root.rootType = Root.ROOT_TYPE_DEVICE;
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
| Root.FLAG_SUPPORTS_SEARCH;
root.title = getContext().getString(R.string.root_internal_storage);
@@ -198,7 +195,6 @@
final RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, root.rootId);
- row.add(Root.COLUMN_ROOT_TYPE, root.rootType);
row.add(Root.COLUMN_FLAGS, root.flags);
row.add(Root.COLUMN_TITLE, root.title);
row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
index e6fbb1b..5a15cd2 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
@@ -65,7 +65,7 @@
private static final String MY_DOC_NULL = "myNull";
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
- Root.COLUMN_ROOT_ID, Root.COLUMN_ROOT_TYPE, Root.COLUMN_FLAGS, Root.COLUMN_ICON,
+ Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON,
Root.COLUMN_TITLE, Root.COLUMN_SUMMARY, Root.COLUMN_DOCUMENT_ID,
Root.COLUMN_AVAILABLE_BYTES,
};
@@ -114,7 +114,6 @@
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
final RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
- row.add(Root.COLUMN_ROOT_TYPE, Root.ROOT_TYPE_SERVICE);
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
row.add(Root.COLUMN_TITLE, "_Test title which is really long");
row.add(Root.COLUMN_SUMMARY,
diff --git a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
index 7e36f9f..801999a 100644
--- a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
@@ -22,22 +22,16 @@
android:gravity="center_horizontal"
android:id="@+id/keyguard_transport_control">
- <!-- FrameLayout used as scrim to show between album art and buttons -->
- <FrameLayout
+ <!-- Use ImageView for its cropping features; otherwise could be android:background -->
+ <ImageView
+ android:id="@+id/albumart"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:foreground="@drawable/ic_lockscreen_player_background"
- android:contentDescription="@string/keygaurd_accessibility_media_controls">
- <!-- Use ImageView for its cropping features; otherwise could be android:background -->
- <ImageView
- android:id="@+id/albumart"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="fill"
- android:scaleType="centerCrop"
- android:adjustViewBounds="false"
- />
- </FrameLayout>
+ android:layout_gravity="fill"
+ android:scaleType="centerCrop"
+ android:adjustViewBounds="false"
+ android:contentDescription="@string/keygaurd_accessibility_media_controls" />
+
<LinearLayout
android:orientation="vertical"
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index 16a3f3f..a31f708 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -22,15 +22,16 @@
<style name="Widget.Button.NumPadKey"
parent="@android:style/Widget.Button">
<item name="android:singleLine">true</item>
- <item name="android:padding">6dip</item>
<item name="android:gravity">left|center_vertical</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:textSize">34dp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">#ffffff</item>
- <item name="android:paddingBottom">10dp</item>
+ <item name="android:paddingTop">6dp</item>
+ <item name="android:paddingBottom">8dp</item>
<item name="android:paddingLeft">20dp</item>
+ <item name="android:paddingRight">6dp</item>
</style>
<style name="TextAppearance.NumPadKey"
parent="@android:style/TextAppearance">
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 07d4d1b..4da6171 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -428,10 +428,11 @@
}
private boolean widgetsDisabled() {
+ boolean disabledByLowRamDevice = ActivityManager.isLowRamDeviceStatic();
boolean disabledByDpm =
(mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
boolean disabledByUser = !mLockPatternUtils.getWidgetsEnabled();
- return disabledByDpm || disabledByUser;
+ return disabledByLowRamDevice || disabledByDpm || disabledByUser;
}
private boolean cameraDisabledByDpm() {
@@ -1483,6 +1484,7 @@
if (DEBUGXPORT) Log.v(TAG, "remove transport");
mAppWidgetContainer.removeWidget(getOrCreateTransportControl());
mTransportControl = null;
+ KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
index 3208aff..2a5f979 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
@@ -36,6 +36,7 @@
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -98,11 +99,9 @@
case MSG_SET_ARTWORK:
if (mClientGeneration == msg.arg1) {
- if (mMetadata.bitmap != null) {
- mMetadata.bitmap.recycle();
- }
mMetadata.bitmap = (Bitmap) msg.obj;
- mAlbumArt.setImageBitmap(mMetadata.bitmap);
+ KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(
+ mMetadata.bitmap);
}
break;
@@ -223,7 +222,8 @@
@Override
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
if (mAttached) {
- int dim = Math.min(512, Math.max(w, h));
+ final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
+ int dim = Math.max(dm.widthPixels, dm.heightPixels);
if (DEBUG) Log.v(TAG, "TCV uses bitmap size=" + dim);
mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
}
@@ -300,7 +300,8 @@
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- mAlbumArt.setImageBitmap(mMetadata.bitmap);
+ KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(
+ mMetadata.bitmap);
final int flags = mTransportControlFlags;
setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f4bbf9a..734f517 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -249,11 +249,11 @@
if (Intent.ACTION_TIME_TICK.equals(action)
|| Intent.ACTION_TIME_CHANGED.equals(action)
|| Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
+ mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
} else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
mTelephonyPlmn = getTelephonyPlmnFrom(intent);
mTelephonySpn = getTelephonySpnFrom(intent);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
+ mHandler.sendEmptyMessage(MSG_CARRIER_INFO_UPDATE);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
@@ -277,12 +277,12 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
} else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
.equals(action)) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
+ mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_BOOT_COMPLETED));
+ dispatchBootCompleted();
}
}
};
@@ -407,6 +407,20 @@
return sInstance;
}
+ /**
+ * IMPORTANT: Must be called from UI thread.
+ */
+ public void dispatchSetBackground(Bitmap bmp) {
+ if (DEBUG) Log.d(TAG, "dispatchSetBackground");
+ final int count = mCallbacks.size();
+ for (int i = 0; i < count; i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onSetBackground(bmp);
+ }
+ }
+ }
+
protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
mDisplayClientState.clientGeneration = clientGeneration;
mDisplayClientState.clearing = clearing;
@@ -520,7 +534,7 @@
super.onChange(selfChange);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
if (mDeviceProvisioned) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
+ mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
}
if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
}
@@ -536,7 +550,7 @@
if (provisioned != mDeviceProvisioned) {
mDeviceProvisioned = provisioned;
if (mDeviceProvisioned) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
+ mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
}
}
}
@@ -582,6 +596,18 @@
}
/**
+ * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If
+ * keyguard crashes sometime after boot, then it will never receive this
+ * broadcast and hence not handle the event. This method is ultimately called by
+ * PhoneWindowManager in this case.
+ */
+ protected void dispatchBootCompleted() {
+ if (!mBootCompleted) {
+ mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
+ }
+ }
+
+ /**
* Handle {@link #MSG_BOOT_COMPLETED}
*/
protected void handleBootCompleted() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index b0511e5..e6dddab 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -17,6 +17,7 @@
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
+import android.graphics.Bitmap;
import android.media.AudioManager;
import com.android.internal.telephony.IccCardConstants;
@@ -135,4 +136,8 @@
* Called when the emergency call button is pressed.
*/
void onEmergencyCallAction() { }
+
+ public void onSetBackground(Bitmap bitmap) {
+ // THIS SPACE FOR RENT
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index b96ef88..2084a16 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -16,6 +16,9 @@
package com.android.keyguard;
+import android.app.PendingIntent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.widget.LockPatternUtils;
@@ -77,6 +80,14 @@
private boolean mScreenOn = false;
private LockPatternUtils mLockPatternUtils;
+ private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSetBackground(Bitmap bmp) {
+ mKeyguardHost.setCustomBackground(bmp != null ?
+ new BitmapDrawable(mContext.getResources(), bmp) : null);
+ }
+ };
+
public interface ShowListener {
void onShown(IBinder windowToken);
};
@@ -140,11 +151,25 @@
class ViewManagerHost extends FrameLayout {
private static final int BACKGROUND_COLOR = 0x70000000;
+ private Drawable mCustomBackground;
+
// This is a faster way to draw the background on devices without hardware acceleration
private final Drawable mBackgroundDrawable = new Drawable() {
@Override
public void draw(Canvas canvas) {
- canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC);
+ if (mCustomBackground != null) {
+ final Rect bounds = mCustomBackground.getBounds();
+ final int vWidth = getWidth();
+ final int vHeight = getHeight();
+
+ final int restore = canvas.save();
+ canvas.translate(-(bounds.width() - vWidth) / 2,
+ -(bounds.height() - vHeight) / 2);
+ mCustomBackground.draw(canvas);
+ canvas.restoreToCount(restore);
+ } else {
+ canvas.drawColor(BACKGROUND_COLOR, PorterDuff.Mode.SRC);
+ }
}
@Override
@@ -166,6 +191,40 @@
setBackground(mBackgroundDrawable);
}
+ public void setCustomBackground(Drawable d) {
+ mCustomBackground = d;
+ if (d != null) {
+ d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
+ }
+ computeCustomBackgroundBounds();
+ invalidate();
+ }
+
+ private void computeCustomBackgroundBounds() {
+ if (mCustomBackground == null) return; // Nothing to do
+ if (!isLaidOut()) return; // We'll do this later
+
+ final int bgWidth = mCustomBackground.getIntrinsicWidth();
+ final int bgHeight = mCustomBackground.getIntrinsicHeight();
+ final int vWidth = getWidth();
+ final int vHeight = getHeight();
+
+ final float bgAspect = (float) bgWidth / bgHeight;
+ final float vAspect = (float) vWidth / vHeight;
+
+ if (bgAspect > vAspect) {
+ mCustomBackground.setBounds(0, 0, (int) (vHeight * bgAspect), vHeight);
+ } else {
+ mCustomBackground.setBounds(0, 0, vWidth, (int) (vWidth / bgAspect));
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ computeCustomBackgroundBounds();
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -239,9 +298,12 @@
lp.setTitle("Keyguard");
mWindowLayoutParams = lp;
mViewManager.addView(mKeyguardHost, lp);
+
+ KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mBackgroundChanger);
}
if (force || mKeyguardView == null) {
+ mKeyguardHost.setCustomBackground(null);
mKeyguardHost.removeAllViews();
inflateKeyguardView(options);
mKeyguardView.requestFocus();
@@ -428,6 +490,8 @@
public void run() {
synchronized (KeyguardViewManager.this) {
lastView.cleanUp();
+ // Let go of any large bitmaps.
+ mKeyguardHost.setCustomBackground(null);
mKeyguardHost.removeView(lastView);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 0606d83..ec3eb157 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.graphics.Bitmap;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardShowCallback;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
@@ -528,6 +529,9 @@
mSystemReady = true;
mUpdateMonitor.registerCallback(mUpdateCallback);
+ // Send boot completed message if it hasn't already been sent.
+ mUpdateMonitor.dispatchBootCompleted();
+
// Suppress biometric unlock right after boot until things have settled if it is the
// selected security method, otherwise unsuppress it. It must be unsuppressed if it is
// not the selected security method for the following reason: if the user starts
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 9fe7e00..5ee8d8c 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -109,6 +109,9 @@
<!-- Label for an unknown reason for failed or blocked print job. [CHAR LIMIT=25] -->
<string name="reason_unknown">unknown</string>
+ <!-- Label for a printer that is not available. [CHAR LIMIT=25] -->
+ <string name="printer_unavailable"><xliff:g id="print_job_name" example="Canon-123GHT">%1$s</xliff:g> – unavailable</string>
+
<!-- Arrays -->
<!-- Color mode labels. -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 3a1a3c4..65af830 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -19,13 +19,16 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Loader;
+import android.content.pm.ServiceInfo;
import android.os.AsyncTask;
import android.print.PrintManager;
import android.print.PrinterDiscoverySession;
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
import android.print.PrinterId;
import android.print.PrinterInfo;
+import android.printservice.PrintServiceInfo;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
@@ -46,6 +49,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import libcore.io.IoUtils;
@@ -384,6 +388,30 @@
+ FusedPrintersProvider.this.hashCode());
}
+ // Ignore printer records whose target services are not installed.
+ PrintManager printManager = (PrintManager) getContext()
+ .getSystemService(Context.PRINT_SERVICE);
+ List<PrintServiceInfo> services = printManager
+ .getInstalledPrintServices();
+
+ Set<ComponentName> installedComponents = new ArraySet<ComponentName>();
+ final int installedServiceCount = services.size();
+ for (int i = 0; i < installedServiceCount; i++) {
+ ServiceInfo serviceInfo = services.get(i).getResolveInfo().serviceInfo;
+ ComponentName componentName = new ComponentName(
+ serviceInfo.packageName, serviceInfo.name);
+ installedComponents.add(componentName);
+ }
+
+ final int printerCount = printers.size();
+ for (int i = printerCount - 1; i >= 0; i--) {
+ ComponentName printerServiceName = printers.get(i).getId().getServiceName();
+ if (!installedComponents.contains(printerServiceName.getPackageName())) {
+ printers.remove(i);
+ }
+ }
+
+ // Store the filtered list.
mHistoricalPrinters = printers;
// Compute the favorite printers.
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index b6ef7b1..44362d4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -819,8 +819,6 @@
private PrinterInfo mCurrentPrinter;
- private boolean mRequestedCurrentPrinterRefresh;
-
private final OnItemSelectedListener mOnItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@Override
@@ -840,7 +838,7 @@
return;
}
- mRequestedCurrentPrinterRefresh = false;
+ mCapabilitiesTimeout.remove();
mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter
.getItem(position);
@@ -855,8 +853,7 @@
PrinterCapabilitiesInfo capabilities = mCurrentPrinter.getCapabilities();
if (capabilities == null) {
- // TODO: We need a timeout for the update.
- mRequestedCurrentPrinterRefresh = true;
+ mCapabilitiesTimeout.post();
updateUi();
refreshCurrentPrinter();
} else {
@@ -1129,6 +1126,9 @@
}
};
+ private final WaitForPrinterCapabilitiesTimeout mCapabilitiesTimeout =
+ new WaitForPrinterCapabilitiesTimeout();
+
private int mEditorState;
private boolean mIgnoreNextDestinationChange;
@@ -1174,16 +1174,16 @@
if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
&& printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
&& printer.getCapabilities() == null
- && !mRequestedCurrentPrinterRefresh) {
- mRequestedCurrentPrinterRefresh = true;
+ && !mCapabilitiesTimeout.isPosted()) {
+ mCapabilitiesTimeout.post();
refreshCurrentPrinter();
return;
}
// We just refreshed the current printer.
if (printer.getCapabilities() != null
- && mRequestedCurrentPrinterRefresh) {
- mRequestedCurrentPrinterRefresh = false;
+ && mCapabilitiesTimeout.isPosted()) {
+ mCapabilitiesTimeout.remove();
updatePrintAttributes(printer.getCapabilities());
updateUi();
mController.update();
@@ -1972,6 +1972,43 @@
}
}
+ private final class WaitForPrinterCapabilitiesTimeout implements Runnable {
+ private static final long GET_CAPABILITIES_TIMEOUT_MILLIS = 10000; // 10sec
+
+ private boolean mIsPosted;
+
+ public void post() {
+ if (!mIsPosted) {
+ mDestinationSpinner.postDelayed(this,
+ GET_CAPABILITIES_TIMEOUT_MILLIS);
+ mIsPosted = true;
+ }
+ }
+
+ public void remove() {
+ if (mIsPosted) {
+ mIsPosted = false;
+ mDestinationSpinner.removeCallbacks(this);
+ }
+ }
+
+ public boolean isPosted() {
+ return mIsPosted;
+ }
+
+ @Override
+ public void run() {
+ mIsPosted = false;
+ if (mDestinationSpinner.getSelectedItemPosition() >= 0) {
+ View itemView = mDestinationSpinner.getSelectedView();
+ TextView titleView = (TextView) itemView.findViewById(R.id.title);
+ String title = getString(R.string.printer_unavailable,
+ mCurrentPrinter.getName());
+ titleView.setText(title);
+ }
+ }
+ }
+
private final class DestinationAdapter extends BaseAdapter
implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>{
private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 62b35fe..87181f7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -43,6 +43,7 @@
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
@@ -59,10 +60,12 @@
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -82,6 +85,8 @@
private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000;
+ private static final String PRINT_JOB_FILE_PREFIX = "print_job_";
+
private static final String PRINT_FILE_EXTENSION = "pdf";
private static final Object sLock = new Object();
@@ -168,9 +173,9 @@
PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
- Message message = mHandlerCaller.obtainMessageIIO(
+ Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
- printJob.getAppId(), 0, printJob.getId());
+ printJob);
mHandlerCaller.executeOrSendMessage(message);
message = mHandlerCaller.obtainMessageOO(
@@ -179,9 +184,6 @@
mHandlerCaller.executeOrSendMessage(message);
printJob.setCreationTime(System.currentTimeMillis());
- synchronized (mLock) {
- mPersistanceManager.writeStateLocked();
- }
}
@Override
@@ -225,12 +227,40 @@
}
@Override
- public void forgetPrintJobs(List<PrintJobId> printJobIds) {
- PrintSpoolerService.this.forgetPrintJobs(printJobIds);
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ PrintSpoolerService.this.dump(fd, writer, args);
}
};
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mLock) {
+ String prefix = args[0];
+ String tab = " ";
+
+ pw.append(prefix).append("print jobs:").println();
+ final int printJobCount = mPrintJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = mPrintJobs.get(i);
+ pw.append(prefix).append(tab).append(printJob.toString());
+ pw.println();
+ }
+
+ pw.append(prefix).append("print job files:").println();
+ File[] files = getFilesDir().listFiles();
+ if (files != null) {
+ final int fileCount = files.length;
+ for (int i = 0; i < fileCount; i++) {
+ File file = files[i];
+ if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
+ pw.append(prefix).append(tab).append(file.getName()).println();
+ }
+ }
+ }
+ }
+ }
+
private void sendOnPrintJobQueued(PrintJobInfo printJob) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
@@ -324,10 +354,9 @@
case MSG_ON_PRINT_JOB_STATE_CHANGED: {
if (mClient != null) {
- PrintJobId printJobId = (PrintJobId) message.obj;
- final int appId = message.arg1;
+ PrintJobInfo printJob = (PrintJobInfo) message.obj;
try {
- mClient.onPrintJobStateChanged(printJobId, appId);
+ mClient.onPrintJobStateChanged(printJob);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error notify for print job state change.", re);
}
@@ -391,17 +420,46 @@
public void createPrintJob(PrintJobInfo printJob) {
synchronized (mLock) {
addPrintJobLocked(printJob);
+ setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
}
}
private void handleReadPrintJobsLocked() {
+ // Make a map with the files for a print job since we may have
+ // to delete some. One example of getting orphan files if the
+ // spooler crashes while constructing a print job. We do not
+ // persist partially populated print jobs under construction to
+ // avoid special handling for various attributes missing.
+ ArrayMap<PrintJobId, File> fileForJobMap = null;
+ File[] files = getFilesDir().listFiles();
+ if (files != null) {
+ final int fileCount = files.length;
+ for (int i = 0; i < fileCount; i++) {
+ File file = files[i];
+ if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
+ if (fileForJobMap == null) {
+ fileForJobMap = new ArrayMap<PrintJobId, File>();
+ }
+ String printJobIdString = file.getName().substring(0,
+ PRINT_JOB_FILE_PREFIX.length());
+ PrintJobId printJobId = PrintJobId.unflattenFromString(
+ printJobIdString);
+ fileForJobMap.put(printJobId, file);
+ }
+ }
+ }
+
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
+ // We want to have only the orphan files at the end.
+ if (fileForJobMap != null) {
+ fileForJobMap.remove(printJob.getId());
+ }
+
// Update the notification.
mNotificationController.onPrintJobStateChanged(printJob);
-
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED:
@@ -415,6 +473,15 @@
} break;
}
}
+
+ // Delete the orphan files.
+ if (fileForJobMap != null) {
+ final int orphanFileCount = fileForJobMap.size();
+ for (int i = 0; i < orphanFileCount; i++) {
+ File file = fileForJobMap.valueAt(i);
+ file.delete();
+ }
+ }
}
public void checkAllPrintJobsHandled() {
@@ -465,7 +532,7 @@
}
public File generateFileForPrintJob(PrintJobId printJobId) {
- return new File(getFilesDir(), "print_job_"
+ return new File(getFilesDir(), PRINT_JOB_FILE_PREFIX
+ printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
}
@@ -476,31 +543,6 @@
}
}
- private void forgetPrintJobs(List<PrintJobId> printJobIds) {
- synchronized (mLock) {
- boolean printJobsRemoved = false;
- final int removedPrintJobCount = printJobIds.size();
- for (int i = 0; i < removedPrintJobCount; i++) {
- PrintJobId removedPrintJobId = printJobIds.get(i);
- final int printJobCount = mPrintJobs.size();
- for (int j = printJobCount - 1; j >= 0; j--) {
- PrintJobInfo printJob = mPrintJobs.get(j);
- if (removedPrintJobId.equals(printJob.getId())) {
- mPrintJobs.remove(j);
- printJobsRemoved = true;
- if (DEBUG_PRINT_JOB_LIFECYCLE) {
- Slog.i(LOG_TAG, "[FORGOT] " + printJob.getId().flattenToString());
- }
- removePrintJobFileLocked(printJob.getId());
- }
- }
- }
- if (printJobsRemoved) {
- mPersistanceManager.writeStateLocked();
- }
- }
- }
-
private void removeObsoletePrintJobs() {
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
@@ -523,7 +565,7 @@
if (file.exists()) {
file.delete();
if (DEBUG_PRINT_JOB_LIFECYCLE) {
- Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId.flattenToString());
+ Slog.i(LOG_TAG, "[REMOVE FILE FOR] " + printJobId);
}
}
}
@@ -552,10 +594,7 @@
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED:
- // Just remove the file but keep the print job info since
- // the app that created it may be holding onto the PrintJob
- // instance and query it for its most recent state. We will
- // remove the info for this job when told so by the system.
+ mPrintJobs.remove(printJob);
removePrintJobFileLocked(printJob.getId());
// $fall-through$
@@ -582,9 +621,9 @@
notifyOnAllPrintJobsHandled();
}
- Message message = mHandlerCaller.obtainMessageIIO(
+ Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
- printJob.getAppId(), 0, printJob.getId());
+ printJob);
mHandlerCaller.executeOrSendMessage(message);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index c32f741..c7f0e17 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -46,6 +46,7 @@
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarPanel;
+import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
public class SearchPanelView extends FrameLayout implements
@@ -88,11 +89,7 @@
if (isKeyguardShowing) {
// Have keyguard show the bouncer and launch the activity if the user succeeds.
- try {
- mWm.showAssistant();
- } catch (RemoteException e) {
- // too bad, so sad...
- }
+ KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
onAnimationStarted();
} else {
// Otherwise, keyguard isn't showing so launch it from here.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 49777d4..932fe20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -123,7 +123,7 @@
protected int mCurrentUserId = 0;
- protected int mLayoutDirection;
+ protected int mLayoutDirection = -1; // invalid
private Locale mLocale;
protected boolean mUseHeadsUp = false;
@@ -299,8 +299,6 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mBroadcastReceiver, filter);
-
- mLocale = mContext.getResources().getConfiguration().locale;
}
public void userSwitched(int newUserId) {
@@ -320,11 +318,17 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- final Locale newLocale = mContext.getResources().getConfiguration().locale;
- if (! newLocale.equals(mLocale)) {
- mLocale = newLocale;
- mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
- refreshLayout(mLayoutDirection);
+ final Locale locale = mContext.getResources().getConfiguration().locale;
+ final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
+ if (! locale.equals(mLocale) || ld != mLayoutDirection) {
+ if (DEBUG) {
+ Log.v(TAG, String.format(
+ "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
+ locale, ld));
+ }
+ mLocale = locale;
+ mLayoutDirection = ld;
+ refreshLayout(ld);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
index ecf7b35..16fe1aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import android.content.res.Configuration;
import android.provider.Settings;
import android.util.Log;
@@ -70,6 +71,13 @@
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ if (mStatusBar != null) {
+ mStatusBar.onConfigurationChanged(newConfig);
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mStatusBar != null) {
mStatusBar.dump(fd, pw, args);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
index 1221a55..5c55f0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardTouchDelegate.java
@@ -23,7 +23,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Log;
+import android.util.Slog;
import android.view.MotionEvent;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -41,7 +41,9 @@
static final String KEYGUARD_PACKAGE = "com.android.keyguard";
static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
- IKeyguardService mService;
+ private static KeyguardTouchDelegate sInstance;
+
+ private volatile IKeyguardService mService;
protected static final boolean DEBUG = false;
protected static final String TAG = "KeyguardTouchDelegate";
@@ -49,83 +51,121 @@
private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- Log.v(TAG, "Connected to keyguard");
+ Slog.v(TAG, "Connected to keyguard");
mService = IKeyguardService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
- Log.v(TAG, "Disconnected from keyguard");
+ Slog.v(TAG, "Disconnected from keyguard");
mService = null;
+ sInstance = null; // force reconnection if this goes away
}
};
- public KeyguardTouchDelegate(Context context) {
+ private KeyguardTouchDelegate(Context context) {
Intent intent = new Intent();
intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
- if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+ if (DEBUG) Slog.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
} else {
- if (DEBUG) Log.v(TAG, "*** Keyguard started");
+ if (DEBUG) Slog.v(TAG, "*** Keyguard started");
}
}
+ public static KeyguardTouchDelegate getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new KeyguardTouchDelegate(context);
+ }
+ return sInstance;
+ }
+
public boolean isSecure() {
- boolean secure = false;
- if (mService != null) {
+ final IKeyguardService service = mService;
+ if (service != null) {
try {
- secure = mService.isSecure();
+ return service.isSecure();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling keyguard.isSecure()!", e);
+ Slog.e(TAG, "RemoteException calling keyguard.isSecure()!", e);
}
} else {
- Log.w(TAG, "isSecure(): NO SERVICE!");
+ Slog.w(TAG, "isSecure(): NO SERVICE!");
}
- return secure;
+ return false;
}
public boolean dispatch(MotionEvent event) {
- if (mService != null) {
+ final IKeyguardService service = mService;
+ if (service != null) {
try {
- mService.dispatch(event);
+ service.dispatch(event);
+ return true;
} catch (RemoteException e) {
// What to do?
- Log.e(TAG, "RemoteException sending event to keyguard!", e);
- return false;
+ Slog.e(TAG, "RemoteException sending event to keyguard!", e);
}
- return true;
} else {
- Log.w(TAG, "dispatch(event): NO SERVICE!");
+ Slog.w(TAG, "dispatch(event): NO SERVICE!");
+ }
+ return false;
+ }
+
+ public boolean isInputRestricted() {
+ final IKeyguardService service = mService;
+ if (service != null) {
+ try {
+ return service.isInputRestricted();
+ } catch (RemoteException e) {
+ Slog.w(TAG , "Remote Exception", e);
+ }
+ } else {
+ Slog.w(TAG, "isInputRestricted(): NO SERVICE!");
+ }
+ return false;
+ }
+
+ public boolean isShowingAndNotHidden() {
+ final IKeyguardService service = mService;
+ if (service != null) {
+ try {
+ return service.isShowingAndNotHidden();
+ } catch (RemoteException e) {
+ Slog.w(TAG , "Remote Exception", e);
+ }
+ } else {
+ Slog.w(TAG, "isShowingAndNotHidden(): NO SERVICE!");
}
return false;
}
public void showAssistant() {
- if (mService != null) {
+ final IKeyguardService service = mService;
+ if (service != null) {
try {
- mService.showAssistant();
+ service.showAssistant();
} catch (RemoteException e) {
// What to do?
- Log.e(TAG, "RemoteException launching assistant!", e);
+ Slog.e(TAG, "RemoteException launching assistant!", e);
}
} else {
- Log.w(TAG, "dispatch(event): NO SERVICE!");
+ Slog.w(TAG, "showAssistant(event): NO SERVICE!");
}
}
public void launchCamera() {
- if (mService != null) {
+ final IKeyguardService service = mService;
+ if (service != null) {
try {
- mService.launchCamera();
+ service.launchCamera();
} catch (RemoteException e) {
// What to do?
- Log.e(TAG, "RemoteException launching camera!", e);
+ Slog.e(TAG, "RemoteException launching camera!", e);
}
} else {
- Log.w(TAG, "dispatch(event): NO SERVICE!");
+ Slog.w(TAG, "dispatch(event): NO SERVICE!");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 596fac6..04885f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -88,7 +88,6 @@
// used to disable the camera icon in navbar when disabled by DPM
private boolean mCameraDisabledByDpm;
- KeyguardTouchDelegate mKeyguardTouchDelegate;
private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
@Override
@@ -112,7 +111,7 @@
}
break;
}
- return mKeyguardTouchDelegate.dispatch(event);
+ return KeyguardTouchDelegate.getInstance(getContext()).dispatch(event);
}
};
@@ -155,8 +154,6 @@
mBarTransitions = new NavigationBarTransitions(this);
- mKeyguardTouchDelegate = new KeyguardTouchDelegate(mContext);
-
mCameraDisabledByDpm = isCameraDisabledByDpm();
watchForDevicePolicyChanges();
}
@@ -341,7 +338,7 @@
final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
final boolean disabledBecauseKeyguardSecure =
(disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
- && mKeyguardTouchDelegate.isSecure();
+ && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
} catch (RemoteException e) {
Log.e(TAG, "Can't get userId", e);
@@ -426,9 +423,9 @@
protected void launchForAccessibilityClick(View v) {
if (v == getCameraButton()) {
- mKeyguardTouchDelegate.launchCamera();
+ KeyguardTouchDelegate.getInstance(getContext()).launchCamera();
} else if (v == getSearchLight()) {
- mKeyguardTouchDelegate.showAssistant();
+ KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index fbc94b1..c47d0eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -38,6 +38,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
@@ -633,7 +634,6 @@
// receive broadcasts
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
@@ -2433,17 +2433,6 @@
notifyNavigationBarScreenOn(false);
notifyHeadsUpScreenOn(false);
}
- else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
- if (DEBUG) {
- Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
- }
- mDisplay.getSize(mCurrentDisplaySize);
-
- updateResources();
- repositionNavigationBar();
- updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- updateShowSearchHoldoff();
- }
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
mScreenOn = true;
// work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
@@ -2466,6 +2455,22 @@
}
};
+ // SystemUIService notifies SystemBars of configuration changes, which then calls down here
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig); // calls refreshLayout
+
+ if (DEBUG) {
+ Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
+ }
+ mDisplay.getSize(mCurrentDisplaySize);
+
+ updateResources();
+ repositionNavigationBar();
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ updateShowSearchHoldoff();
+ }
+
@Override
public void userSwitched(int newUserId) {
if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 9f9b6d6..a5fd1d7 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5127,11 +5127,6 @@
}
@Override
- public void showAssistant() {
- mKeyguardDelegate.showAssistant();
- }
-
- @Override
public boolean canMagnifyWindow(int windowType) {
switch (windowType) {
case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
index 5e299ee..83be1a8 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
@@ -181,11 +181,7 @@
}
public void showAssistant() {
- try {
- mService.showAssistant();
- } catch (RemoteException e) {
- Slog.w(TAG , "Remote Exception", e);
- }
+ // Not used by PhoneWindowManager
}
public void dispatch(MotionEvent event) {
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 2145b76..3a3dfd5 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -47,6 +47,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCacheListener;
+import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.database.DatabaseUtils;
@@ -580,15 +581,18 @@
try {
new Session(fromAccounts, null, account.type, false,
false /* stripAuthTokenFromResult */) {
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
+ ", " + account.type;
}
+ @Override
public void run() throws RemoteException {
mAuthenticator.getAccountCredentialsForCloning(this, account);
}
+ @Override
public void onResult(Bundle result) {
if (result != null) {
if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
@@ -613,11 +617,13 @@
try {
new Session(targetUser, null, account.type, false,
false /* stripAuthTokenFromResult */) {
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
+ ", " + account.type;
}
+ @Override
public void run() throws RemoteException {
// Confirm that the owner's account still exists before this step.
UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
@@ -632,6 +638,7 @@
}
}
+ @Override
public void onResult(Bundle result) {
if (result != null) {
if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
@@ -646,6 +653,7 @@
}
}
+ @Override
public void onError(int errorCode, String errorMessage) {
super.onError(errorCode, errorMessage);
// TODO: Show error notification to user
@@ -774,6 +782,7 @@
mAccount = account;
}
+ @Override
public void run() throws RemoteException {
try {
mAuthenticator.hasFeatures(this, mAccount, mFeatures);
@@ -782,6 +791,7 @@
}
}
+ @Override
public void onResult(Bundle result) {
IAccountManagerResponse response = getResponseAndClose();
if (response != null) {
@@ -807,6 +817,7 @@
}
}
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", hasFeatures"
+ ", " + mAccount
@@ -863,15 +874,18 @@
mAccount = account;
}
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", removeAccount"
+ ", account " + mAccount;
}
+ @Override
public void run() throws RemoteException {
mAuthenticator.getAccountRemovalAllowed(this, mAccount);
}
+ @Override
public void onResult(Bundle result) {
if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
&& !result.containsKey(AccountManager.KEY_INTENT)) {
@@ -1212,16 +1226,19 @@
try {
new Session(accounts, response, accountType, false,
false /* stripAuthTokenFromResult */) {
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAuthTokenLabel"
+ ", " + accountType
+ ", authTokenType " + authTokenType;
}
+ @Override
public void run() throws RemoteException {
mAuthenticator.getAuthTokenLabel(this, authTokenType);
}
+ @Override
public void onResult(Bundle result) {
if (result != null) {
String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
@@ -1299,6 +1316,7 @@
new Session(accounts, response, account.type, expectActivityLaunch,
false /* stripAuthTokenFromResult */) {
+ @Override
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
return super.toDebugString(now) + ", getAuthToken"
@@ -1308,6 +1326,7 @@
+ ", notifyOnAuthFailure " + notifyOnAuthFailure;
}
+ @Override
public void run() throws RemoteException {
// If the caller doesn't have permission then create and return the
// "grant permission" intent instead of the "getAuthToken" intent.
@@ -1318,6 +1337,7 @@
}
}
+ @Override
public void onResult(Bundle result) {
if (result != null) {
if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
@@ -1482,11 +1502,13 @@
try {
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */) {
+ @Override
public void run() throws RemoteException {
mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
options);
}
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", addAccount"
+ ", accountType " + accountType
@@ -1530,9 +1552,11 @@
try {
new Session(accounts, response, account.type, expectActivityLaunch,
true /* stripAuthTokenFromResult */) {
+ @Override
public void run() throws RemoteException {
mAuthenticator.confirmCredentials(this, account, options);
}
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", confirmCredentials"
+ ", " + account;
@@ -1563,9 +1587,11 @@
try {
new Session(accounts, response, account.type, expectActivityLaunch,
true /* stripAuthTokenFromResult */) {
+ @Override
public void run() throws RemoteException {
mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
}
+ @Override
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
return super.toDebugString(now) + ", updateCredentials"
@@ -1596,9 +1622,11 @@
try {
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */) {
+ @Override
public void run() throws RemoteException {
mAuthenticator.editProperties(this, mAccountType);
}
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", editProperties"
+ ", accountType " + accountType;
@@ -1624,6 +1652,7 @@
mFeatures = features;
}
+ @Override
public void run() throws RemoteException {
synchronized (mAccounts.cacheLock) {
mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
@@ -1661,6 +1690,7 @@
}
}
+ @Override
public void onResult(Bundle result) {
mNumResults++;
if (result == null) {
@@ -1699,6 +1729,7 @@
}
+ @Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
+ ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
@@ -2111,9 +2142,31 @@
}
}
+ @Override
public void onResult(Bundle result) {
mNumResults++;
- if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
+ Intent intent = null;
+ if (result != null
+ && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+ /*
+ * The Authenticator API allows third party authenticators to
+ * supply arbitrary intents to other apps that they can run,
+ * this can be very bad when those apps are in the system like
+ * the System Settings.
+ */
+ PackageManager pm = mContext.getPackageManager();
+ ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+ int targetUid = resolveInfo.activityInfo.applicationInfo.uid;
+ int authenticatorUid = Binder.getCallingUid();
+ if (PackageManager.SIGNATURE_MATCH !=
+ pm.checkSignatures(authenticatorUid, targetUid)) {
+ throw new SecurityException(
+ "Activity to be started with KEY_INTENT must " +
+ "share Authenticator's signatures");
+ }
+ }
+ if (result != null
+ && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
@@ -2223,6 +2276,7 @@
super(looper);
}
+ @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_TIMED_OUT:
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a14d729..ddb6d1a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1689,7 +1689,7 @@
&& proc.pid == pid) {
num++;
proc.lastPssTime = SystemClock.uptimeMillis();
- proc.baseProcessTracker.addPss(pss, tmp[0], true);
+ proc.baseProcessTracker.addPss(pss, tmp[0], true, proc.pkgList);
if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
+ ": " + pss + " lastPss=" + proc.lastPss
+ " state=" + ProcessList.makeProcStateString(procState));
@@ -2705,18 +2705,6 @@
return intent;
}
- String getHomePackageName() {
- Intent intent = getHomeIntent();
- ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, mCurrentUserId);
- if (aInfo != null) {
- final String homePackageName = aInfo.applicationInfo.packageName;
- if (!ResolverActivity.class.getName().equals(homePackageName)) {
- return homePackageName;
- }
- }
- return null;
- }
-
boolean startHomeActivityLocked(int userId) {
if (mHeadless) {
// Added because none of the other calls to ensureBootCompleted seem to fire
@@ -4278,7 +4266,7 @@
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
- infos[i].getTotalUss(), false);
+ infos[i].getTotalUss(), false, proc.pkgList);
}
}
}
@@ -4305,7 +4293,7 @@
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
- proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false);
+ proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false, proc.pkgList);
}
}
}
@@ -6786,6 +6774,10 @@
// Kill the running processes.
for (int i=0; i<procs.size(); i++) {
ProcessRecord pr = procs.get(i);
+ if (pr == mHomeProcess) {
+ // Don't kill the home process along with tasks from the same package.
+ continue;
+ }
if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
killUnneededProcessLocked(pr, "remove task");
} else {
@@ -11748,7 +11740,7 @@
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
- r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true);
+ r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true, r.pkgList);
}
}
@@ -11909,7 +11901,7 @@
if (memInfo.getZramTotalSizeKb() != 0) {
if (!isCompact) {
pw.print(" ZRAM: "); pw.print(memInfo.getZramTotalSizeKb());
- pw.print(" kB used for ");
+ pw.print(" kB physical used for ");
pw.print(memInfo.getSwapTotalSizeKb()
- memInfo.getSwapFreeSizeKb());
pw.print(" kB in swap (");
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 4359895..2c0b83b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -58,6 +58,7 @@
final class ActivityRecord {
static final String TAG = ActivityManagerService.TAG;
static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
+ final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
@@ -443,25 +444,18 @@
noDisplay = ent != null && ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
- // If we know the system has determined the component, then
- // we can consider this to be a home activity...
- String homePackageName = supervisor.getHomePackageName();
- if (homePackageName != null && homePackageName.equals(packageName)) {
- mActivityType = HOME_ACTIVITY_TYPE;
- } else if ((!_componentSpecified || _launchedFromUid == Process.myUid()
+ if ((!_componentSpecified || _launchedFromUid == Process.myUid()
|| _launchedFromUid == 0) &&
Intent.ACTION_MAIN.equals(_intent.getAction()) &&
_intent.hasCategory(Intent.CATEGORY_HOME) &&
_intent.getCategories().size() == 1 &&
_intent.getData() == null &&
_intent.getType() == null &&
- (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+ isNotResolverActivity()) {
// This sure looks like a home activity!
mActivityType = HOME_ACTIVITY_TYPE;
- if (isNotResolverActivity()) {
- supervisor.setHomePackageName(userId, packageName);
- }
- } else if (realActivity.getClassName().contains("com.android.systemui.recent")) {
+ } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
mActivityType = RECENTS_ACTIVITY_TYPE;
} else {
mActivityType = APPLICATION_ACTIVITY_TYPE;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 18ff819..4d66946 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -334,20 +334,16 @@
mCurrentUser = service.mCurrentUserId;
}
- private boolean okToShow(ActivityRecord r) {
+ boolean okToShow(ActivityRecord r) {
return r.userId == mCurrentUser
|| (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
}
final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = mTaskHistory.get(taskNdx);
- final ArrayList<ActivityRecord> activities = task.mActivities;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = activities.get(activityNdx);
- if (!r.finishing && r != notTop && okToShow(r)) {
- return r;
- }
+ ActivityRecord r = mTaskHistory.get(taskNdx).topRunningActivityLocked(notTop);
+ if (r != null) {
+ return r;
}
}
return null;
@@ -1087,10 +1083,24 @@
// At this point, nothing else needs to be shown
if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
behindFullscreen = true;
- } else if (task.mActivities.indexOf(r) == 0 && task.mOnTopOfHome) {
- if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
- showHomeBehindStack = true;
- behindFullscreen = true;
+ } else if (task.mOnTopOfHome) {
+ // Work our way down from r to bottom of task and see if there are any
+ // visible activities below r.
+ int rIndex = task.mActivities.indexOf(r);
+ for ( --rIndex; rIndex >= 0; --rIndex) {
+ final ActivityRecord blocker = task.mActivities.get(rIndex);
+ if (!blocker.finishing && blocker.visible) {
+ if (DEBUG_VISBILITY) Slog.v(TAG, "Home visibility for " +
+ r + " blocked by " + blocker);
+ break;
+ }
+ }
+ if (rIndex < 0) {
+ // Got to task bottom without finding a visible activity, show home.
+ if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
+ showHomeBehindStack = true;
+ behindFullscreen = true;
+ }
}
} else {
if (DEBUG_VISBILITY) Slog.v(
@@ -3405,11 +3415,16 @@
}
}
- void handleAppDiedLocked(ProcessRecord app, boolean restarting) {
+ /**
+ * Reset local parameters because an app's activity died.
+ * @param app The app of the activity that died.
+ * @return true if home should be launched next.
+ */
+ boolean handleAppDiedLocked(ProcessRecord app) {
if (!containsApp(app)) {
- return;
+ return false;
}
- // TODO: handle the case where an app spans multiple stacks.
+
if (mPausingActivity != null && mPausingActivity.app == app) {
if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
"App died while pausing: " + mPausingActivity);
@@ -3419,28 +3434,32 @@
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
- final ActivityRecord top = topRunningActivityLocked(null);
- final boolean launchHomeTaskNext =
- top != null && top.app == app && top.task.mOnTopOfHome;
- // Remove this application's activities from active lists.
- boolean hasVisibleActivities = removeHistoryRecordsForAppLocked(app);
-
- if (!restarting) {
- ActivityStack stack = mStackSupervisor.getFocusedStack();
- if (stack == null || launchHomeTaskNext) {
- mStackSupervisor.resumeHomeActivity(null);
- } else if (!mStackSupervisor.resumeTopActivitiesLocked(stack, null, null)) {
- // If there was nothing to resume, and we are not already
- // restarting this process, but there is a visible activity that
- // is hosted by the process... then make sure all visible
- // activities are running, taking care of restarting this
- // process.
- if (hasVisibleActivities) {
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
- }
+ // Determine if the top task is exiting and should return to home. Do this before it gets
+ // removed in removeHistoryRecordsForAppsLocked.
+ boolean launchHomeNext = false;
+ int top = mTaskHistory.size() - 1;
+ while (top >= 0) {
+ final TaskRecord topTask = mTaskHistory.get(top);
+ if (topTask.mActivities.isEmpty()) {
+ // Not possible, but just in case.
+ --top;
+ continue;
}
+ ActivityRecord r = topTask.topRunningActivityLocked(null);
+ if (r != null) {
+ // r will be launched next.
+ break;
+ }
+ // There is an activity in topTask that is finishing. If topTask belongs to the app
+ // return to home depending on the task flag.
+ launchHomeNext = topTask.mOnTopOfHome;
+ break;
}
+
+ removeHistoryRecordsForAppLocked(app);
+
+ return launchHomeNext;
}
void handleAppCrashLocked(ProcessRecord app) {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 1ee13ec..f718706 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -203,12 +203,6 @@
*/
final PowerManager.WakeLock mGoingToSleep;
- /**
- * The name of the current home activity for each user.
- * TODO: Remove entries when user is deleted.
- */
- final SparseArray<String> mHomePackageNames = new SparseArray<String>();
-
public ActivityStackSupervisor(ActivityManagerService service, Context context,
Looper looper) {
mService = service;
@@ -1932,10 +1926,28 @@
}
void handleAppDiedLocked(ProcessRecord app, boolean restarting) {
- // Just in case.
+ boolean launchHomeTaskNext = false;
+ final ActivityStack focusedStack = getFocusedStack();
final int numStacks = mStacks.size();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- mStacks.get(stackNdx).handleAppDiedLocked(app, restarting);
+ final ActivityStack stack = mStacks.get(stackNdx);
+ // Only update launchHomeTaskNext for the focused stack.
+ launchHomeTaskNext |= (stack == focusedStack && stack.handleAppDiedLocked(app));
+ }
+
+ if (!restarting) {
+ if (launchHomeTaskNext) {
+ resumeHomeActivity(null);
+ } else {
+ if (!resumeTopActivitiesLocked(focusedStack, null, null)) {
+ // If there was nothing to resume, and we are not already
+ // restarting this process, but there is a visible activity that
+ // is hosted by the process... then make sure all visible
+ // activities are running, taking care of restarting this
+ // process.
+ ensureActivitiesVisibleLocked(null, 0);
+ }
+ }
}
}
@@ -2267,11 +2279,6 @@
boolean switchUserLocked(int userId, UserStartedState uss) {
mCurrentUser = userId;
- final String homePackageName = mService.getHomePackageName();
- if (homePackageName != null) {
- setHomePackageName(mCurrentUser, homePackageName);
- }
-
mStartingUsers.add(uss);
boolean haveActivities = false;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -2373,12 +2380,6 @@
pw.print(prefix); pw.print("mStackState="); pw.println(stackStateToString(mStackState));
pw.print(prefix); pw.println("mSleepTimeout: " + mSleepTimeout);
pw.print(prefix); pw.println("mCurTaskId: " + mCurTaskId);
- pw.print(prefix); pw.print("mHomePackageNames:");
- for (int i = 0; i < mHomePackageNames.size(); ++i) {
- pw.print(" ("); pw.print(mHomePackageNames.keyAt(i)); pw.print(",");
- pw.print(mHomePackageNames.valueAt(i)); pw.print(")");
- }
- pw.println();
}
ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -2635,14 +2636,4 @@
}
}
}
-
- String getHomePackageName() {
- return mHomePackageNames.get(mCurrentUser);
- }
-
- void setHomePackageName(int userId, String homePackageName) {
- if (DEBUG_SWITCH) Slog.d(TAG, "setHomePackageName: user=" + userId + " package="
- + homePackageName);
- mHomePackageNames.put(userId, homePackageName);
- }
}
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index be08973..2c49bb9 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -61,7 +61,6 @@
static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
- static long COMMIT_PERIOD = 3*60*60*1000; // Commit current stats every 3 hours.
final ActivityManagerService mAm;
final File mBaseDir;
@@ -160,7 +159,7 @@
public boolean shouldWriteNowLocked(long now) {
if (now > (mLastWriteTime+WRITE_PERIOD)) {
if (SystemClock.elapsedRealtime()
- > (mProcessStats.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
+ > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD)) {
mCommitPending = true;
}
return true;
@@ -358,7 +357,7 @@
boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
boolean sepProcStates, int[] procStates, long now, String reqPackage) {
ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
- screenStates, memStates, procStates, now, reqPackage);
+ screenStates, memStates, procStates, procStates, now, reqPackage);
if (procs.size() > 0) {
if (header != null) {
pw.println(header);
@@ -457,7 +456,7 @@
if (curTime < minTime) {
// Need to add in older stats to reach desired time.
ArrayList<String> files = getCommittedFiles(0, false, true);
- if (files.size() > 0) {
+ if (files != null && files.size() > 0) {
current.setDataPosition(0);
ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
current.recycle();
@@ -520,7 +519,7 @@
static private void dumpHelp(PrintWriter pw) {
pw.println("Process stats (procstats) dump options:");
pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
- pw.println(" [--details] [--full-details] [--current] [--one-day]");
+ pw.println(" [--details] [--full-details] [--current] [--hours]");
pw.println(" [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
pw.println(" --checkin: perform a checkin: print and delete old committed states.");
pw.println(" --c: print only state in checkin format.");
@@ -532,7 +531,7 @@
pw.println(" --details: dump all execution details, not just summary.");
pw.println(" --full-details: dump only detail information, for all saved state.");
pw.println(" --current: only dump current state.");
- pw.println(" --one-day: dump stats aggregated across about one day.");
+ pw.println(" --hours: aggregate over about N last hours.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
pw.println(" --reset: reset current stats, without committing.");
pw.println(" --clear: clear all stats; does both --reset and deletes old stats.");
@@ -562,7 +561,7 @@
boolean dumpDetails = false;
boolean dumpFullDetails = false;
boolean dumpAll = false;
- boolean oneDay = false;
+ int aggregateHours = 0;
String reqPackage = null;
boolean csvSepScreenStats = false;
int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
@@ -632,8 +631,20 @@
dumpDetails = true;
} else if ("--full-details".equals(arg)) {
dumpFullDetails = true;
- } else if ("--one-day".equals(arg)) {
- oneDay = true;
+ } else if ("--hours".equals(arg)) {
+ i++;
+ if (i >= args.length) {
+ pw.println("Error: argument required for --hours");
+ dumpHelp(pw);
+ return;
+ }
+ try {
+ aggregateHours = Integer.parseInt(args[i]);
+ } catch (NumberFormatException e) {
+ pw.println("Error: --hours argument not an int -- " + args[i]);
+ dumpHelp(pw);
+ return;
+ }
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
@@ -750,8 +761,9 @@
*/
}
return;
- } else if (oneDay) {
- ParcelFileDescriptor pfd = getStatsOverTime(24*60*60*1000);
+ } else if (aggregateHours != 0) {
+ ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
+ - (ProcessStats.COMMIT_PERIOD/2));
if (pfd == null) {
pw.println("Unable to build stats!");
return;
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index f0bba4f..385253e 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -139,6 +139,16 @@
return null;
}
+ ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
+ for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+ ActivityRecord r = mActivities.get(activityNdx);
+ if (!r.finishing && r != notTop && stack.okToShow(r)) {
+ return r;
+ }
+ }
+ return null;
+ }
+
/**
* Reorder the history stack so that the activity at the given index is
* brought to the front.
@@ -418,6 +428,7 @@
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
pw.print(" rootWasReset="); pw.print(rootWasReset);
pw.print(" userId="); pw.print(userId);
+ pw.print(" mTaskType="); pw.print(mTaskType);
pw.print(" numFullscreen="); pw.print(numFullscreen);
pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
}
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index d4583b5..b8e1b04 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -194,6 +194,21 @@
}
@Override
+ public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getInstalledPrintServices();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index f98a805..798cea3 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -33,7 +33,6 @@
import android.print.IPrintSpoolerClient;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
-import android.print.PrintManager;
import android.util.Slog;
import android.util.TimedRemoteCaller;
@@ -91,7 +90,7 @@
public static interface PrintSpoolerCallbacks {
public void onPrintJobQueued(PrintJobInfo printJob);
public void onAllPrintJobsForServiceHandled(ComponentName printService);
- public void onPrintJobStateChanged(PrintJobId printJobId, int appId);
+ public void onPrintJobStateChanged(PrintJobInfo printJob);
}
public RemotePrintSpooler(Context context, int userId,
@@ -280,30 +279,6 @@
}
}
- public final void forgetPrintJobs(List<PrintJobId> printJobIds) {
- throwIfCalledOnMainThread();
- synchronized (mLock) {
- throwIfDestroyedLocked();
- mCanUnbind = false;
- }
- try {
- getRemoteInstanceLazy().forgetPrintJobs(printJobIds);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error forgeting print jobs", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error forgeting print jobs", te);
- } finally {
- if (DEBUG) {
- Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
- + "] forgetPrintJobs()");
- }
- synchronized (mLock) {
- mCanUnbind = true;
- mLock.notifyAll();
- }
- }
- }
-
public final void destroy() {
throwIfCalledOnMainThread();
if (DEBUG) {
@@ -323,18 +298,15 @@
.append(String.valueOf(mDestroyed)).println();
pw.append(prefix).append("bound=")
.append((mRemoteInstance != null) ? "true" : "false").println();
- pw.append(prefix).append("print jobs:").println();
- if (mRemoteInstance != null) {
- List<PrintJobInfo> printJobs = getPrintJobInfos(null,
- PrintJobInfo.STATE_ANY, PrintManager.APP_ID_ANY);
- if (printJobs != null) {
- final int printJobCount = printJobs.size();
- for (int i = 0; i < printJobCount; i++) {
- PrintJobInfo printJob = printJobs.get(i);
- pw.append(prefix).append(prefix).append(printJob.toString());
- pw.println();
- }
- }
+
+ pw.flush();
+
+ try {
+ getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
+ } catch (TimeoutException te) {
+ /* ignore */
+ } catch (RemoteException re) {
+ /* ignore */
}
}
}
@@ -346,8 +318,8 @@
}
}
- private void onPrintJobStateChanged(PrintJobId printJobId, int appId) {
- mCallbacks.onPrintJobStateChanged(printJobId, appId);
+ private void onPrintJobStateChanged(PrintJobInfo printJob) {
+ mCallbacks.onPrintJobStateChanged(printJob);
}
private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
@@ -625,12 +597,12 @@
}
@Override
- public void onPrintJobStateChanged(PrintJobId printJobId, int appId) {
+ public void onPrintJobStateChanged(PrintJobInfo printJob) {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
- spooler.onPrintJobStateChanged(printJobId, appId);
+ spooler.onPrintJobStateChanged(printJob);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index e5f5842..bc70fe3 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -33,7 +33,6 @@
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.UserManager;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
@@ -52,6 +51,7 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.R;
import com.android.internal.os.BackgroundThread;
@@ -62,6 +62,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -93,8 +94,8 @@
private final Set<ComponentName> mEnabledServices =
new ArraySet<ComponentName>();
- private final CreatedPrintJobTracker mCreatedPrintJobTracker =
- new CreatedPrintJobTracker();
+ private final PrintJobForAppCache mPrintJobForAppCache =
+ new PrintJobForAppCache();
private final Object mLock;
@@ -155,23 +156,22 @@
public PrintJobInfo print(String printJobName, final IPrintClient client,
final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
int appId) {
- PrintJobId printJobId = new PrintJobId();
-
- // Track this job so we can forget it when the creator dies.
- if (!mCreatedPrintJobTracker.onPrintJobCreatedLocked(client.asBinder(), printJobId)) {
- // Not adding a print job means the client is dead - done.
- return null;
- }
-
// Create print job place holder.
final PrintJobInfo printJob = new PrintJobInfo();
- printJob.setId(printJobId);
+ printJob.setId(new PrintJobId());
printJob.setAppId(appId);
printJob.setLabel(printJobName);
printJob.setAttributes(attributes);
printJob.setState(PrintJobInfo.STATE_CREATED);
printJob.setCopies(1);
+ // Track this job so we can forget it when the creator dies.
+ if (!mPrintJobForAppCache.onPrintJobCreated(client.asBinder(), appId,
+ printJob)) {
+ // Not adding a print job means the client is dead - done.
+ return null;
+ }
+
// Spin the spooler to add the job and show the config UI.
new AsyncTask<Void, Void, Void>() {
@Override
@@ -185,10 +185,42 @@
}
public List<PrintJobInfo> getPrintJobInfos(int appId) {
- return mSpooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY, appId);
+ List<PrintJobInfo> cachedPrintJobs = mPrintJobForAppCache.getPrintJobs(appId);
+ // Note that the print spooler is not storing print jobs that
+ // are in a terminal state as it is non-trivial to properly update
+ // the spooler state for when to forget print jobs in terminal state.
+ // Therefore, we fuse the cached print jobs for running apps (some
+ // jobs are in a terminal state) with the ones that the print
+ // spooler knows about (some jobs are being processed).
+ ArrayMap<PrintJobId, PrintJobInfo> result =
+ new ArrayMap<PrintJobId, PrintJobInfo>();
+
+ // Add the cached print jobs for running apps.
+ final int cachedPrintJobCount = cachedPrintJobs.size();
+ for (int i = 0; i < cachedPrintJobCount; i++) {
+ PrintJobInfo cachedPrintJob = cachedPrintJobs.get(i);
+ result.put(cachedPrintJob.getId(), cachedPrintJob);
+ }
+
+ // Add everything else the spooler knows about.
+ List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(null,
+ PrintJobInfo.STATE_ANY, appId);
+ if (printJobs != null) {
+ final int printJobCount = printJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ result.put(printJob.getId(), printJob);
+ }
+ }
+
+ return new ArrayList<PrintJobInfo>(result.values());
}
public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+ PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId);
+ if (printJob != null) {
+ return printJob;
+ }
return mSpooler.getPrintJobInfo(printJobId, appId);
}
@@ -242,6 +274,12 @@
}
}
+ public List<PrintServiceInfo> getInstalledPrintServices() {
+ synchronized (mLock) {
+ return mInstalledServices;
+ }
+ }
+
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -398,9 +436,10 @@
}
@Override
- public void onPrintJobStateChanged(PrintJobId printJobId, int appId) {
+ public void onPrintJobStateChanged(PrintJobInfo printJob) {
+ mPrintJobForAppCache.onPrintJobStateChanged(printJob);
mHandler.obtainMessage(UserStateHandler.MSG_DISPATCH_PRINT_JOB_STATE_CHANGED,
- appId, 0, printJobId).sendToTarget();
+ printJob.getAppId(), 0, printJob.getId()).sendToTarget();
}
@Override
@@ -525,6 +564,9 @@
pw.println();
}
+ pw.append(prefix).append(tab).append("cached print jobs:").println();
+ mPrintJobForAppCache.dump(pw, prefix + tab + tab);
+
pw.append(prefix).append(tab).append("discovery mediator:").println();
if (mPrinterDiscoverySession != null) {
mPrinterDiscoverySession.dump(pw, prefix + tab + tab);
@@ -1424,34 +1466,19 @@
}
}
- private final class CreatedPrintJobTracker {
- private final ArrayMap<IBinder, List<PrintJobId>> mCreatedPrintJobs =
- new ArrayMap<IBinder, List<PrintJobId>>();
+ private final class PrintJobForAppCache {
+ private final SparseArray<List<PrintJobInfo>> mPrintJobsForRunningApp =
+ new SparseArray<List<PrintJobInfo>>();
- public boolean onPrintJobCreatedLocked(final IBinder creator, PrintJobId printJobId) {
+ public boolean onPrintJobCreated(final IBinder creator, final int appId,
+ PrintJobInfo printJob) {
try {
creator.linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
creator.unlinkToDeath(this, 0);
- UserManager userManager = (UserManager) mContext.getSystemService(
- Context.USER_SERVICE);
- // If the death is a result of the user being removed, then
- // do nothing since the spooler data for this user will be
- // wiped and we cannot bind to the spooler at this point.
- if (userManager.getUserInfo(mUserId) == null) {
- return;
- }
- List<PrintJobId> printJobIds = null;
synchronized (mLock) {
- printJobIds = mCreatedPrintJobs.remove(creator);
- if (printJobIds == null) {
- return;
- }
- printJobIds = new ArrayList<PrintJobId>(printJobIds);
- }
- if (printJobIds != null) {
- mSpooler.forgetPrintJobs(printJobIds);
+ mPrintJobsForRunningApp.remove(appId);
}
}
}, 0);
@@ -1460,14 +1487,93 @@
return false;
}
synchronized (mLock) {
- List<PrintJobId> printJobIds = mCreatedPrintJobs.get(creator);
- if (printJobIds == null) {
- printJobIds = new ArrayList<PrintJobId>();
- mCreatedPrintJobs.put(creator, printJobIds);
+ List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId);
+ if (printJobsForApp == null) {
+ printJobsForApp = new ArrayList<PrintJobInfo>();
+ mPrintJobsForRunningApp.put(appId, printJobsForApp);
}
- printJobIds.add(printJobId);
+ printJobsForApp.add(printJob);
}
return true;
}
+
+ public void onPrintJobStateChanged(PrintJobInfo printJob) {
+ synchronized (mLock) {
+ List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(
+ printJob.getAppId());
+ if (printJobsForApp == null) {
+ return;
+ }
+ final int printJobCount = printJobsForApp.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo oldPrintJob = printJobsForApp.get(i);
+ if (oldPrintJob.getId().equals(printJob.getId())) {
+ printJobsForApp.set(i, printJob);
+ }
+ }
+ }
+ }
+
+ public PrintJobInfo getPrintJob(PrintJobId printJobId, int appId) {
+ synchronized (mLock) {
+ List<PrintJobInfo> printJobsForApp = mPrintJobsForRunningApp.get(appId);
+ if (printJobsForApp == null) {
+ return null;
+ }
+ final int printJobCount = printJobsForApp.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobsForApp.get(i);
+ if (printJob.getId().equals(printJobId)) {
+ return printJob;
+ }
+ }
+ }
+ return null;
+ }
+
+ public List<PrintJobInfo> getPrintJobs(int appId) {
+ synchronized (mLock) {
+ List<PrintJobInfo> printJobs = null;
+ if (appId == PrintManager.APP_ID_ANY) {
+ final int bucketCount = mPrintJobsForRunningApp.size();
+ for (int i = 0; i < bucketCount; i++) {
+ List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
+ if (printJobs == null) {
+ printJobs = new ArrayList<PrintJobInfo>();
+ }
+ printJobs.addAll(bucket);
+ }
+ } else {
+ List<PrintJobInfo> bucket = mPrintJobsForRunningApp.get(appId);
+ if (bucket != null) {
+ if (printJobs == null) {
+ printJobs = new ArrayList<PrintJobInfo>();
+ }
+ printJobs.addAll(bucket);
+ }
+ }
+ if (printJobs != null) {
+ return printJobs;
+ }
+ return Collections.emptyList();
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ String tab = " ";
+ final int bucketCount = mPrintJobsForRunningApp.size();
+ for (int i = 0; i < bucketCount; i++) {
+ final int appId = mPrintJobsForRunningApp.keyAt(i);
+ pw.append(prefix).append("appId=" + appId).append(':').println();
+ List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
+ final int printJobCount = bucket.size();
+ for (int j = 0; j < printJobCount; j++) {
+ PrintJobInfo printJob = bucket.get(j);
+ pw.append(prefix).append(tab).append(printJob.toString()).println();
+ }
+ }
+ }
+ }
}
}
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index beeb899..2798104 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -162,6 +162,7 @@
void moveStack(TaskStack stack, boolean toTop) {
mStackHistory.remove(stack);
mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
+ mService.moveStackWindowsLocked(stack);
}
public boolean isPrivate() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index e330f8b..80c50cc 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4715,7 +4715,7 @@
}
}
- private void moveStackWindowsLocked(TaskStack stack) {
+ void moveStackWindowsLocked(TaskStack stack) {
DisplayContent displayContent = stack.getDisplayContent();
// First remove all of the windows from the list.
@@ -4782,7 +4782,6 @@
}
stack.moveTaskToTop(task);
displayContent.moveStack(stack, true);
- moveStackWindowsLocked(stack);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -10142,16 +10141,6 @@
return mSafeMode;
}
- @Override
- public void showAssistant() {
- // TODO: What permission?
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
- != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- mPolicy.showAssistant();
- }
-
void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
mPolicy.dump(" ", pw, args);
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 1e3b058..632efe0 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -346,6 +346,8 @@
LABEL_ATTR = 0x01010001,
ICON_ATTR = 0x01010002,
NAME_ATTR = 0x01010003,
+ PERMISSION_ATTR = 0x01010006,
+ RESOURCE_ATTR = 0x01010025,
DEBUGGABLE_ATTR = 0x0101000f,
VERSION_CODE_ATTR = 0x0101021b,
VERSION_NAME_ATTR = 0x0101021c,
@@ -372,6 +374,7 @@
COMPATIBLE_WIDTH_LIMIT_DP_ATTR = 0x01010365,
LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
PUBLIC_KEY_ATTR = 0x010103a6,
+ CATEGORY_ATTR = 0x010103e8,
};
const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -424,6 +427,61 @@
printf("\n");
}
+Vector<String8> getNfcAidCategories(AssetManager& assets, String8 xmlPath, bool offHost,
+ String8 *outError = NULL)
+{
+ Asset* aidAsset = assets.openNonAsset(xmlPath, Asset::ACCESS_BUFFER);
+ if (aidAsset == NULL) {
+ if (outError != NULL) *outError = "xml resource does not exist";
+ return Vector<String8>();
+ }
+
+ const String8 serviceTagName(offHost ? "offhost-apdu-service" : "host-apdu-service");
+
+ bool withinApduService = false;
+ Vector<String8> categories;
+
+ String8 error;
+ ResXMLTree tree;
+ tree.setTo(aidAsset->getBuffer(true), aidAsset->getLength());
+
+ size_t len;
+ int depth = 0;
+ ResXMLTree::event_code_t code;
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::END_TAG) {
+ depth--;
+ String8 tag(tree.getElementName(&len));
+
+ if (depth == 0 && tag == serviceTagName) {
+ withinApduService = false;
+ }
+
+ } else if (code == ResXMLTree::START_TAG) {
+ depth++;
+ String8 tag(tree.getElementName(&len));
+
+ if (depth == 1) {
+ if (tag == serviceTagName) {
+ withinApduService = true;
+ }
+ } else if (depth == 2 && withinApduService) {
+ if (tag == "aid-group") {
+ String8 category = getAttribute(tree, CATEGORY_ATTR, &error);
+ if (error != "") {
+ if (outError != NULL) *outError = error;
+ return Vector<String8>();
+ }
+
+ categories.add(category);
+ }
+ }
+ }
+ }
+ aidAsset->close();
+ return categories;
+}
+
/*
* Handle the "dump" command, to extract select data from an archive.
*/
@@ -631,12 +689,31 @@
bool hasOtherServices = false;
bool hasWallpaperService = false;
bool hasImeService = false;
+ bool hasAccessibilityService = false;
+ bool hasPrintService = false;
bool hasWidgetReceivers = false;
+ bool hasDeviceAdminReceiver = false;
bool hasIntentFilter = false;
+ bool hasPaymentService = false;
bool actMainActivity = false;
bool actWidgetReceivers = false;
+ bool actDeviceAdminEnabled = false;
bool actImeService = false;
bool actWallpaperService = false;
+ bool actAccessibilityService = false;
+ bool actPrintService = false;
+ bool actHostApduService = false;
+ bool actOffHostApduService = false;
+ bool hasMetaHostPaymentCategory = false;
+ bool hasMetaOffHostPaymentCategory = false;
+
+ // These permissions are required by services implementing services
+ // the system binds to (IME, Accessibility, PrintServices, etc.)
+ bool hasBindDeviceAdminPermission = false;
+ bool hasBindInputMethodPermission = false;
+ bool hasBindAccessibilityServicePermission = false;
+ bool hasBindPrintServicePermission = false;
+ bool hasBindNfcServicePermission = false;
// These two implement the implicit permissions that are granted
// to pre-1.6 applications.
@@ -747,6 +824,13 @@
hasOtherActivities |= withinActivity;
hasOtherReceivers |= withinReceiver;
hasOtherServices |= withinService;
+ } else {
+ if (withinService) {
+ hasPaymentService |= (actHostApduService && hasMetaHostPaymentCategory &&
+ hasBindNfcServicePermission);
+ hasPaymentService |= (actOffHostApduService && hasMetaOffHostPaymentCategory &&
+ hasBindNfcServicePermission);
+ }
}
withinActivity = false;
withinService = false;
@@ -760,11 +844,18 @@
hasOtherActivities |= !actMainActivity;
} else if (withinReceiver) {
hasWidgetReceivers |= actWidgetReceivers;
- hasOtherReceivers |= !actWidgetReceivers;
+ hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
+ hasBindDeviceAdminPermission);
+ hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
} else if (withinService) {
hasImeService |= actImeService;
hasWallpaperService |= actWallpaperService;
- hasOtherServices |= (!actImeService && !actWallpaperService);
+ hasAccessibilityService |= (actAccessibilityService &&
+ hasBindAccessibilityServicePermission);
+ hasPrintService |= (actPrintService && hasBindPrintServicePermission);
+ hasOtherServices |= (!actImeService && !actWallpaperService &&
+ !actAccessibilityService && !actPrintService &&
+ !actHostApduService && !actOffHostApduService);
}
}
withinIntentFilter = false;
@@ -1109,6 +1200,13 @@
withinReceiver = false;
withinService = false;
hasIntentFilter = false;
+ hasMetaHostPaymentCategory = false;
+ hasMetaOffHostPaymentCategory = false;
+ hasBindDeviceAdminPermission = false;
+ hasBindInputMethodPermission = false;
+ hasBindAccessibilityServicePermission = false;
+ hasBindPrintServicePermission = false;
+ hasBindNfcServicePermission = false;
if (withinApplication) {
if(tag == "activity") {
withinActivity = true;
@@ -1166,6 +1264,16 @@
" %s\n", error.string());
goto bail;
}
+
+ String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
+ if (error == "") {
+ if (permission == "android.permission.BIND_DEVICE_ADMIN") {
+ hasBindDeviceAdminPermission = true;
+ }
+ } else {
+ fprintf(stderr, "ERROR getting 'android:permission' attribute for"
+ " receiver '%s': %s\n", receiverName.string(), error.string());
+ }
} else if (tag == "service") {
withinService = true;
serviceName = getAttribute(tree, NAME_ATTR, &error);
@@ -1175,6 +1283,22 @@
" service: %s\n", error.string());
goto bail;
}
+
+ String8 permission = getAttribute(tree, PERMISSION_ATTR, &error);
+ if (error == "") {
+ if (permission == "android.permission.BIND_INPUT_METHOD") {
+ hasBindInputMethodPermission = true;
+ } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
+ hasBindAccessibilityServicePermission = true;
+ } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
+ hasBindPrintServicePermission = true;
+ } else if (permission == "android.permission.BIND_NFC_SERVICE") {
+ hasBindNfcServicePermission = true;
+ }
+ } else {
+ fprintf(stderr, "ERROR getting 'android:permission' attribute for"
+ " service '%s': %s\n", serviceName.string(), error.string());
+ }
}
} else if (withinSupportsInput && tag == "input-type") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -1186,10 +1310,60 @@
goto bail;
}
}
- } else if ((depth == 4) && (tag == "intent-filter")) {
- hasIntentFilter = true;
- withinIntentFilter = true;
- actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false;
+ } else if (depth == 4) {
+ if (tag == "intent-filter") {
+ hasIntentFilter = true;
+ withinIntentFilter = true;
+ actMainActivity = false;
+ actWidgetReceivers = false;
+ actImeService = false;
+ actWallpaperService = false;
+ actAccessibilityService = false;
+ actPrintService = false;
+ actDeviceAdminEnabled = false;
+ actHostApduService = false;
+ actOffHostApduService = false;
+ } else if (withinService && tag == "meta-data") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute for"
+ " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+ goto bail;
+ }
+
+ if (name == "android.nfc.cardemulation.host_apdu_service" ||
+ name == "android.nfc.cardemulation.off_host_apdu_service") {
+ bool offHost = true;
+ if (name == "android.nfc.cardemulation.host_apdu_service") {
+ offHost = false;
+ }
+
+ String8 xmlPath = getResolvedAttribute(&res, tree, RESOURCE_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:resource' attribute for"
+ " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+ goto bail;
+ }
+
+ Vector<String8> categories = getNfcAidCategories(assets, xmlPath,
+ offHost, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting AID category for service '%s'\n",
+ serviceName.string());
+ goto bail;
+ }
+
+ const size_t catLen = categories.size();
+ for (size_t i = 0; i < catLen; i++) {
+ bool paymentCategory = (categories[i] == "payment");
+ if (offHost) {
+ hasMetaOffHostPaymentCategory |= paymentCategory;
+ } else {
+ hasMetaHostPaymentCategory |= paymentCategory;
+ }
+ }
+ }
+ }
} else if ((depth == 5) && withinIntentFilter){
String8 action;
if (tag == "action") {
@@ -1206,12 +1380,22 @@
} else if (withinReceiver) {
if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
actWidgetReceivers = true;
+ } else if (action == "android.app.action.DEVICE_ADMIN_ENABLED") {
+ actDeviceAdminEnabled = true;
}
} else if (withinService) {
if (action == "android.view.InputMethod") {
actImeService = true;
} else if (action == "android.service.wallpaper.WallpaperService") {
actWallpaperService = true;
+ } else if (action == "android.accessibilityservice.AccessibilityService") {
+ actAccessibilityService = true;
+ } else if (action == "android.printservice.PrintService") {
+ actPrintService = true;
+ } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
+ actHostApduService = true;
+ } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
+ actOffHostApduService = true;
}
}
if (action == "android.intent.action.SEARCH") {
@@ -1411,12 +1595,24 @@
if (hasWidgetReceivers) {
printf("app-widget\n");
}
+ if (hasDeviceAdminReceiver) {
+ printf("device-admin\n");
+ }
if (hasImeService) {
printf("ime\n");
}
if (hasWallpaperService) {
printf("wallpaper\n");
}
+ if (hasAccessibilityService) {
+ printf("accessibility\n");
+ }
+ if (hasPrintService) {
+ printf("print\n");
+ }
+ if (hasPaymentService) {
+ printf("payment\n");
+ }
if (hasOtherActivities) {
printf("other-activities\n");
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index f0c3a75..fd7a645 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -458,11 +458,6 @@
}
@Override
- public void showAssistant() {
-
- }
-
- @Override
public IBinder getFocusedWindowToken() {
// TODO Auto-generated method stub
return null;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 76bd636..798bc2e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1456,9 +1456,6 @@
public void setCountryCode(String countryCode, boolean persist) {
if (persist) {
mPersistedCountryCode = countryCode;
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.WIFI_COUNTRY_CODE,
- countryCode);
}
sendMessage(CMD_SET_COUNTRY_CODE, countryCode);
mWifiP2pChannel.sendMessage(WifiP2pService.SET_COUNTRY_CODE, countryCode);
@@ -1691,8 +1688,8 @@
* Set the country code from the system setting value, if any.
*/
private void setCountryCode() {
- String countryCode = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.WIFI_COUNTRY_CODE);
+ String countryCode = mContext.getResources().getString(
+ R.string.config_wifi_default_country_code);
if (countryCode != null && !countryCode.isEmpty()) {
setCountryCode(countryCode, false);
} else {
@@ -2417,13 +2414,6 @@
case CMD_BOOT_COMPLETED:
String countryCode = mPersistedCountryCode;
if (TextUtils.isEmpty(countryCode) == false) {
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.WIFI_COUNTRY_CODE,
- countryCode);
- // it may be that the state transition that should send this info
- // to the driver happened between mPersistedCountryCode getting set
- // and now, so simply persisting it here would mean we have sent
- // nothing to the driver. Send the cmd so it might be set now.
sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode);
}
break;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 625ffb8..50e8e3d 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -2545,12 +2545,6 @@
mServiceTransactionId = 0;
mServiceDiscReqId = null;
- String countryCode = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.WIFI_COUNTRY_CODE);
- if (countryCode != null && !countryCode.isEmpty()) {
- mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode);
- }
-
updatePersistentNetworks(RELOAD);
}