diff options
Diffstat (limited to 'core/java/android')
31 files changed, 777 insertions, 688 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 31de98d..1e3d5be 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -308,6 +308,8 @@ public abstract class AccessibilityService extends Service { * android:accessibilityFlags="flagDefault" * android:settingsActivity="foo.bar.TestBackActivity" * android:canRetrieveWindowContent="true" + * android:canRequestTouchExplorationMode="true" + * android:canRequestEnhancedWebAccessibility="true" * . . . * /></pre> */ diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index d82b9a3..40f45b7 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -29,6 +29,7 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; +import android.util.SparseArray; import android.util.TypedValue; import android.util.Xml; import android.view.View; @@ -38,7 +39,12 @@ import android.view.accessibility.AccessibilityNodeInfo; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import com.android.internal.R; + import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * This class describes an {@link AccessibilityService}. The system notifies an @@ -61,6 +67,49 @@ public class AccessibilityServiceInfo implements Parcelable { private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service"; /** + * Capability: This accessibility service can retrieve the active window content. + */ + public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001; + + /** + * Capability: This accessibility service can request touch exploration mode in which + * touched items are spoken aloud and the UI can be explored via gestures. + */ + public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002; + + /** + * Capability: This accessibility service can request enhanced web accessibility + * enhancements. For example, installing scripts to make app content more accessible. + */ + public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004; + + /** + * Capability: This accessibility service can request to filter the key event stream. + */ + public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008; + + private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos = + new SparseArray<CapabilityInfo>(); + static { + sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, + new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, + R.string.capability_title_canRetrieveWindowContent, + R.string.capability_desc_canRetrieveWindowContent)); + sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, + new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, + R.string.capability_title_canRequestTouchExploration, + R.string.capability_desc_canRequestTouchExploration)); + sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, + new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, + R.string.capability_title_canRequestEnhancedWebAccessibility, + R.string.capability_desc_canRequestEnhancedWebAccessibility)); + sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, + new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, + R.string.capability_title_canRequestFilterKeyEvents, + R.string.capability_desc_canRequestFilterKeyEvents)); + } + + /** * Denotes spoken feedback. */ public static final int FEEDBACK_SPOKEN = 0x0000001; @@ -152,9 +201,11 @@ public class AccessibilityServiceInfo implements Parcelable { * <p> * For accessibility services targeting API version higher than * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set - * this flag have to request the - * {@link android.Manifest.permission#CAN_REQUEST_TOUCH_EXPLORATION_MODE} - * permission or the flag will be ignored. + * this flag have to declare this capability in their meta-data by setting + * the attribute {@link android.R.attr#canRequestTouchExplorationMode + * canRequestTouchExplorationMode} to true, otherwise this flag will + * be ignored. For how to declare the meta-data of a service refer to + * {@value AccessibilityService#SERVICE_META_DATA}. * </p> * <p> * Services targeting API version equal to or lower than @@ -175,9 +226,11 @@ public class AccessibilityServiceInfo implements Parcelable { * device will not have enhanced web accessibility enabled since there may be * another enabled service that requested it. * <p> - * Clients that want to set this flag have to request the - * {@link android.Manifest.permission#CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY} - * permission or the flag will be ignored. + * Services that want to set this flag have to declare this capability + * in their meta-data by setting the attribute {@link android.R.attr + * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to + * true, otherwise this flag will be ignored. For how to declare the meta-data + * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. * </p> */ public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008; @@ -192,6 +245,25 @@ public class AccessibilityServiceInfo implements Parcelable { public static final int FLAG_REPORT_VIEW_IDS = 0x00000010; /** + * This flag requests from the system to filter key events. If this flag + * is set the accessibility service will receive the key events before + * applications allowing it implement global shortcuts. Setting this flag + * does not guarantee that this service will filter key events since only + * one service can do so at any given time. This avoids user confusion due + * to behavior change in case different key filtering services are enabled. + * If there is already another key filtering service enabled, this one will + * not receive key events. + * <p> + * Services that want to set this flag have to declare this capability + * in their meta-data by setting the attribute {@link android.R.attr + * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true, + * otherwise this flag will be ignored. For how to declare the meta-data + * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. + * </p> + */ + public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020; + + /** * The event types an {@link AccessibilityService} is interested in. * <p> * <strong>Can be dynamically set at runtime.</strong> @@ -259,6 +331,9 @@ public class AccessibilityServiceInfo implements Parcelable { * @see #DEFAULT * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE + * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY + * @see #FLAG_REQUEST_FILTER_KEY_EVENTS + * @see #FLAG_REPORT_VIEW_IDS */ public int flags; @@ -279,9 +354,9 @@ public class AccessibilityServiceInfo implements Parcelable { private String mSettingsActivityName; /** - * Flag whether this accessibility service can retrieve window content. + * Bit mask with capabilities of this service. */ - private boolean mCanRetrieveWindowContent; + private int mCapabilities; /** * Resource id of the description of the accessibility service. @@ -360,9 +435,22 @@ public class AccessibilityServiceInfo implements Parcelable { com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); mSettingsActivityName = asAttributes.getString( com.android.internal.R.styleable.AccessibilityService_settingsActivity); - mCanRetrieveWindowContent = asAttributes.getBoolean( - com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent, - false); + if (asAttributes.getBoolean(com.android.internal.R.styleable + .AccessibilityService_canRetrieveWindowContent, false)) { + mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; + } + if (asAttributes.getBoolean(com.android.internal.R.styleable + .AccessibilityService_canRequestTouchExplorationMode, false)) { + mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; + } + if (asAttributes.getBoolean(com.android.internal.R.styleable + .AccessibilityService_canRequestEnhancedWebAccessibility, false)) { + mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY; + } + if (asAttributes.getBoolean(com.android.internal.R.styleable + .AccessibilityService_canRequestFilterKeyEvents, false)) { + mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; + } TypedValue peekedValue = asAttributes.peekValue( com.android.internal.R.styleable.AccessibilityService_description); if (peekedValue != null) { @@ -446,9 +534,26 @@ public class AccessibilityServiceInfo implements Parcelable { * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> * </p> * @return True if window content can be retrieved. + * + * @deprecated Use {@link #getCapabilities()}. */ public boolean getCanRetrieveWindowContent() { - return mCanRetrieveWindowContent; + return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; + } + + /** + * Returns the bit mask of capabilities this accessibility service has such as + * being able to retrieve the active window content, etc. + * + * @return The capability bit mask. + * + * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT + * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION + * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY + * @see #CAPABILITY_FILTER_KEY_EVENTS + */ + public int getCapabilities() { + return mCapabilities; } /** @@ -502,7 +607,7 @@ public class AccessibilityServiceInfo implements Parcelable { parcel.writeString(mId); parcel.writeParcelable(mResolveInfo, 0); parcel.writeString(mSettingsActivityName); - parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0); + parcel.writeInt(mCapabilities); parcel.writeInt(mDescriptionResId); parcel.writeString(mNonLocalizedDescription); } @@ -516,7 +621,7 @@ public class AccessibilityServiceInfo implements Parcelable { mId = parcel.readString(); mResolveInfo = parcel.readParcelable(null); mSettingsActivityName = parcel.readString(); - mCanRetrieveWindowContent = (parcel.readInt() == 1); + mCapabilities = parcel.readInt(); mDescriptionResId = parcel.readInt(); mNonLocalizedDescription = parcel.readString(); } @@ -567,7 +672,7 @@ public class AccessibilityServiceInfo implements Parcelable { stringBuilder.append(", "); stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); stringBuilder.append(", "); - stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent); + appendCapabilities(stringBuilder, mCapabilities); return stringBuilder.toString(); } @@ -628,6 +733,20 @@ public class AccessibilityServiceInfo implements Parcelable { stringBuilder.append("]"); } + private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { + stringBuilder.append("capabilities:"); + stringBuilder.append("["); + while (capabilities != 0) { + final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); + stringBuilder.append(capabilityToString(capabilityBit)); + capabilities &= ~capabilityBit; + if (capabilities != 0) { + stringBuilder.append(", "); + } + } + stringBuilder.append("]"); + } + /** * Returns the string representation of a feedback type. For example, * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. @@ -699,12 +818,77 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; + case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: + return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; + case FLAG_REPORT_VIEW_IDS: + return "FLAG_REPORT_VIEW_IDS"; + case FLAG_REQUEST_FILTER_KEY_EVENTS: + return "FLAG_REQUEST_FILTER_KEY_EVENTS"; default: return null; } } /** + * Returns the string representation of a capability. For example, + * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented + * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. + * + * @param capability The capability. + * @return The string representation. + */ + public static String capabilityToString(int capability) { + switch (capability) { + case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: + return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; + case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: + return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; + case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: + return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; + case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: + return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; + default: + return "UNKNOWN"; + } + } + + /** + * @hide + * @return The list of {@link CapabilityInfo} objects. + */ + public List<CapabilityInfo> getCapabilityInfos() { + if (mCapabilities == 0) { + return Collections.emptyList(); + } + int capabilities = mCapabilities; + List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); + while (capabilities != 0) { + final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); + capabilities &= ~capabilityBit; + CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit); + if (capabilityInfo != null) { + capabilityInfos.add(capabilityInfo); + } + } + return capabilityInfos; + } + + /** + * @hide + */ + public static final class CapabilityInfo { + public final int capability; + public final int titleResId; + public final int descResId; + + public CapabilityInfo(int capability, int titleResId, int descResId) { + this.capability = capability; + this.titleResId = titleResId; + this.descResId = descResId; + } + } + + /** * @see Parcelable.Creator */ public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 241a64a..b4a12c4 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -405,6 +405,23 @@ public class AccountManager { } /** + * Returns the accounts visible to the specified package, in an environment where some apps + * are not authorized to view all accounts. This method can only be called by system apps. + * @param type The type of accounts to return, null to retrieve all accounts + * @param packageName The package name of the app for which the accounts are to be returned + * @return An array of {@link Account}, one per matching account. Empty + * (never null) if no accounts of the specified type have been added. + */ + public Account[] getAccountsByTypeForPackage(String type, String packageName) { + try { + return mService.getAccountsByTypeForPackage(type, packageName); + } catch (RemoteException re) { + // possible security exception + throw new RuntimeException(re); + } + } + + /** * Lists all accounts of a particular type. The account type is a * string token corresponding to the authenticator and useful domain * of the account. For example, there are types corresponding to Google diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index 2aba163..58eb66f 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -34,13 +34,11 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; -import android.widget.Toast; import com.android.internal.R; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.Set; @@ -110,6 +108,7 @@ public class ChooseTypeAndAccountActivity extends Activity private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts"; private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName"; private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount"; + private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountList"; private static final int SELECTED_ITEM_NONE = -1; @@ -169,6 +168,7 @@ public class ChooseTypeAndAccountActivity extends Activity mSelectedAddNewAccount = savedInstanceState.getBoolean( KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false); + mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST); } else { mPendingRequest = REQUEST_NULL; mExistingAccounts = null; @@ -266,6 +266,7 @@ public class ChooseTypeAndAccountActivity extends Activity mAccounts.get(mSelectedItemIndex).name); } } + outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts); } public void onCancelButtonClicked(View view) { diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 8141813..86e279f 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -32,6 +32,7 @@ interface IAccountManager { AuthenticatorDescription[] getAuthenticatorTypes(); Account[] getAccounts(String accountType); Account[] getAccountsForPackage(String packageName, int uid); + Account[] getAccountsByTypeForPackage(String type, String packageName); Account[] getAccountsAsUser(String accountType, int userId); void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features); void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a26bdbc..6b5df7f 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1353,8 +1353,8 @@ public class Activity extends ContextThemeWrapper * of the assist Intent. The default implementation does nothing. * * <p>This function will be called after any global assist callbacks that had - * been registered with {@link Application#registerOnProvideAssistData - * Application.registerOnProvideAssistData}. + * been registered with {@link Application#registerOnProvideAssistDataListener + * Application.registerOnProvideAssistDataListener}. */ public void onProvideAssistData(Bundle data) { } diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 0d7f0a7..75e4bab 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -17,17 +17,14 @@ package android.app; import java.util.ArrayList; -import java.util.List; import android.content.ComponentCallbacks; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; -import android.content.RestrictionEntry; import android.content.res.Configuration; import android.os.Bundle; -import android.os.UserManager; /** * Base class for those who need to maintain global application state. You can @@ -49,7 +46,7 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { new ArrayList<ComponentCallbacks>(); private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks = new ArrayList<ActivityLifecycleCallbacks>(); - private ArrayList<OnProvideAssistData> mAssistCallbacks = null; + private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null; /** @hide */ public LoadedApk mLoadedApk; @@ -65,10 +62,10 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } /** - * Callback interface for use with {@link Application#registerOnProvideAssistData} - * and {@link Application#unregisterOnProvideAssistData}. + * Callback interface for use with {@link Application#registerOnProvideAssistDataListener} + * and {@link Application#unregisterOnProvideAssistDataListener}. */ - public interface OnProvideAssistData { + public interface OnProvideAssistDataListener { /** * This is called when the user is requesting an assist, to build a full * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current @@ -158,16 +155,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } } - public void registerOnProvideAssistData(OnProvideAssistData callback) { + public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) { synchronized (this) { if (mAssistCallbacks == null) { - mAssistCallbacks = new ArrayList<OnProvideAssistData>(); + mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>(); } mAssistCallbacks.add(callback); } } - public void unregisterOnProvideAssistData(OnProvideAssistData callback) { + public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) { synchronized (this) { if (mAssistCallbacks != null) { mAssistCallbacks.remove(callback); @@ -280,7 +277,7 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } if (callbacks != null) { for (int i=0; i<callbacks.length; i++) { - ((OnProvideAssistData)callbacks[i]).onProvideAssistData(activity, data); + ((OnProvideAssistDataListener)callbacks[i]).onProvideAssistData(activity, data); } } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 8284b2c..17e8dd9 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1537,14 +1537,21 @@ public class DevicePolicyManager { return false; } + /** - * Used to determine if a particular package has been registered as a Device Owner admin. - * Device Owner admins cannot be deactivated by the user unless the Device Owner itself allows - * it. And Device Owner packages cannot be uninstalled, once registered. - * @param packageName the package name to check against the registered device owner. - * @return whether or not the package is registered as the Device Owner. + * Used to determine if a particular package has been registered as a Device Owner app. + * A device owner app is a special device admin that cannot be deactivated by the user, once + * activated as a device admin. It also cannot be uninstalled. To check if a particular + * package is currently registered as the device owner app, pass in the package name from + * {@link Context#getPackageName()} to this method.<p/>This is useful for device + * admin apps that want to check if they are also registered as the device owner app. The + * exact mechanism by which a device admin app is registered as a device owner app is defined by + * the setup process. + * @param packageName the package name of the app, to compare with the registered device owner + * app, if any. + * @return whether or not the package is registered as the device owner app. */ - public boolean isDeviceOwner(String packageName) { + public boolean isDeviceOwnerApp(String packageName) { if (mService != null) { try { return mService.isDeviceOwner(packageName); @@ -1555,6 +1562,14 @@ public class DevicePolicyManager { return false; } + /** + * @hide + * Redirect to isDeviceOwnerApp. + */ + public boolean isDeviceOwner(String packageName) { + return isDeviceOwnerApp(packageName); + } + /** @hide */ public String getDeviceOwner() { if (mService != null) { diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 2e9c9e3..3498bb8 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -20,7 +20,6 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.ParcelUuid; @@ -30,11 +29,14 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -357,9 +359,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; - private Handler mServiceRecordHandler; - private BluetoothAdapterCallback mCallback; - private int mClientIf; + private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; /** * Get a handle to the default local Bluetooth adapter. @@ -394,7 +394,7 @@ public final class BluetoothAdapter { mService = managerService.registerAdapter(mManagerCallback); } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; - mServiceRecordHandler = null; + mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>(); } /** @@ -1409,72 +1409,38 @@ public final class BluetoothAdapter { } /** - * Register an callback to receive async results, such as LE scan result. + * Callback interface used to deliver LE scan results. * - * <p>This is an asynchronous call. The callback - * {@link BluetoothAdapterCallback#onCallbackRegistration} - * is used to notify success or failure if the function returns true. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks. - * @return If true, the callback will be called to notify success or failure, - * false on immediate error - */ - public boolean registerCallback(BluetoothAdapterCallback callback) { - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - mCallback = callback; - UUID uuid = UUID.randomUUID(); - if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid); - - iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback); - return true; - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } - } - - /** - * Unregister the registered callback. - */ - public boolean unRegisterCallback(BluetoothAdapterCallback callback) { - if (callback != mCallback) return false; - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - - iGatt.unregisterClient(mClientIf); - return true; - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } + * @see #startLeScan(LeScanCallback) + * @see #startLeScan(UUID[], LeScanCallback) + */ + public interface LeScanCallback { + /** + * Callback reporting an LE device found during a device scan initiated + * by the {@link BluetoothAdapter#startLeScan} function. + * + * @param device Identifies the remote device + * @param rssi The RSSI value for the remote device as reported by the + * Bluetooth hardware. 0 if no RSSI value is available. + * @param scanRecord The content of the advertisement record offered by + * the remote device. + */ + public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } /** * Starts a scan for Bluetooth LE devices. * * <p>Results of the scan are reported using the - * {@link BluetoothAdapterCallback#onLeScan} callback. + * {@link LeScanCallback#onLeScan} callback. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * + * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully */ - public boolean startLeScan() { - if (DBG) Log.d(TAG, "startLeScan()"); - if (mClientIf == 0) return false; - - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - iGatt.startScan(mClientIf, false); - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } - - return true; + public boolean startLeScan(LeScanCallback callback) { + return startLeScan(null, callback); } /** @@ -1482,155 +1448,281 @@ public final class BluetoothAdapter { * advertise given services. * * <p>Devices which advertise all specified services are reported using the - * {@link BluetoothAdapterCallback#onLeScan} callback. + * {@link LeScanCallback#onLeScan} callback. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param serviceUuids Array of services to look for + * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully */ - public boolean startLeScan(UUID[] serviceUuids) { - if (DBG) Log.d(TAG, "startLeScan() - with UUIDs"); - if (mClientIf == 0) return false; + public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { + if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(serviceUuids[i]); - } - iGatt.startScanWithUuids(mClientIf, false, uuids); - } catch (RemoteException e) { - Log.e(TAG,"",e); + if (callback == null) { + if (DBG) Log.e(TAG, "startLeScan: null callback"); return false; } - return true; + synchronized(mLeScanClients) { + if (mLeScanClients.containsKey(callback)) { + if (DBG) Log.e(TAG, "LE Scan has already started"); + return false; + } + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); + + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + if (wrapper.scanStarted()) { + mLeScanClients.put(callback, wrapper); + return true; + } + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + return false; } /** * Stops an ongoing Bluetooth LE device scan. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - */ - public void stopLeScan() { - if (DBG) Log.d(TAG, "stopScan()"); - if (mClientIf == 0) return; - - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - iGatt.stopScan(mClientIf, false); - } catch (RemoteException e) { - Log.e(TAG,"",e); + * + * @param callback used to identify which scan to stop + * must be the same handle used to start the scan + */ + public void stopLeScan(LeScanCallback callback) { + if (DBG) Log.d(TAG, "stopLeScan()"); + GattCallbackWrapper wrapper; + synchronized(mLeScanClients) { + wrapper = mLeScanClients.remove(callback); + if (wrapper == null) return; } + wrapper.stopLeScan(); } /** * Bluetooth GATT interface callbacks */ - private final IBluetoothGattCallback mBluetoothGattCallback = - new IBluetoothGattCallback.Stub() { - /** - * Application interface registered - app is ready to go - */ - public void onClientRegistered(int status, int clientIf) { - if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status - + " clientIf=" + clientIf); - mClientIf = clientIf; - mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ? - BluetoothAdapterCallback.CALLBACK_REGISTERED : - BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE); - } + private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { + private static final int LE_CALLBACK_REG_TIMEOUT = 2000; + private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; + + private final LeScanCallback mLeScanCb; + // mLeHandle 0: not registered + // -1: scan stopped + // >0: registered and scan started + private int mLeHandle; + private final UUID[] mScanFilter; + private WeakReference<BluetoothAdapter> mBluetoothAdapter; + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, + LeScanCallback leScanCb, UUID[] uuid) { + mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + } - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - // no op + public boolean scanStarted() { + boolean started = false; + synchronized(this) { + if (mLeHandle == -1) return false; + + int count = 0; + // wait for callback registration and LE scan to start + while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { + try { + wait(LE_CALLBACK_REG_TIMEOUT); + } catch (InterruptedException e) { + Log.e(TAG, "Callback reg wait interrupted: " + e); + } + count++; + } + started = (mLeHandle > 0); } + return started; + } - /** - * Callback reporting an LE scan result. - * @hide - */ - public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - - try { - mCallback.onLeScan(getRemoteDevice(address), rssi, advData); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); + public void stopLeScan() { + synchronized(this) { + if (mLeHandle <= 0) { + Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); + return; + } + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + iGatt.stopScan(mLeHandle, false); + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop scan and unregister" + e); + } + } else { + Log.e(TAG, "stopLeScan, BluetoothAdapter is null"); } + mLeHandle = -1; + notifyAll(); } + } - public void onGetService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid) { - // no op - } + /** + * Application interface registered - app is ready to go + */ + public void onClientRegistered(int status, int clientIf) { + if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + + " clientIf=" + clientIf); + synchronized(this) { + if (mLeHandle == -1) { + if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled"); + } - public void onGetIncludedService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int inclSrvcType, int inclSrvcInstId, - ParcelUuid inclSrvcUuid) { - // no op + if (status == BluetoothGatt.GATT_SUCCESS) { + mLeHandle = clientIf; + IBluetoothGatt iGatt = null; + try { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } + } else { + Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); + mLeHandle = -1; + } + } catch (RemoteException e) { + Log.e(TAG, "fail to start le scan: " + e); + mLeHandle = -1; + } + if (mLeHandle == -1) { + // registration succeeded but start scan failed + if (iGatt != null) { + try { + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "fail to unregister callback: " + mLeHandle + + " error: " + e); + } + } + } + } else { + // registration failed + mLeHandle = -1; + } + notifyAll(); } + } - public void onGetCharacteristic(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int charProps) { - // no op - } + public void onClientConnectionState(int status, int clientIf, + boolean connected, String address) { + // no op + } - public void onGetDescriptor(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descUuid) { - // no op - } + /** + * Callback reporting an LE scan result. + * @hide + */ + public void onScanResult(String address, int rssi, byte[] advData) { + if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - public void onSearchComplete(String address, int status) { - // no op + // Check null in case the scan has been stopped + synchronized(this) { + if (mLeHandle <= 0) return; } - - public void onCharacteristicRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, byte[] value) { - // no op + try { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter == null) { + Log.d(TAG, "onScanResult, BluetoothAdapter null"); + return; + } + mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); } + } - public void onCharacteristicWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid) { - // no op - } + public void onGetService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid) { + // no op + } + + public void onGetIncludedService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int inclSrvcType, int inclSrvcInstId, + ParcelUuid inclSrvcUuid) { + // no op + } - public void onNotify(String address, int srvcType, + public void onGetCharacteristic(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + int charProps) { + // no op + } + + public void onGetDescriptor(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descUuid) { + // no op + } + + public void onSearchComplete(String address, int status) { + // no op + } + + public void onCharacteristicRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, byte[] value) { + // no op + } + + public void onCharacteristicWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid) { + // no op + } + + public void onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value) { - // no op - } + // no op + } - public void onDescriptorRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid, byte[] value) { - // no op - } + public void onDescriptorRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid, byte[] value) { + // no op + } - public void onDescriptorWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid) { - // no op - } + public void onDescriptorWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid) { + // no op + } - public void onExecuteWrite(String address, int status) { - // no op - } + public void onExecuteWrite(String address, int status) { + // no op + } - public void onReadRemoteRssi(String address, int rssi, int status) { - // no op - } - }; + public void onReadRemoteRssi(String address, int rssi, int status) { + // no op + } + } } diff --git a/core/java/android/bluetooth/BluetoothAdapterCallback.java b/core/java/android/bluetooth/BluetoothAdapterCallback.java deleted file mode 100644 index a726bc9..0000000 --- a/core/java/android/bluetooth/BluetoothAdapterCallback.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.bluetooth; - -import android.bluetooth.BluetoothDevice; - -/** - * This abstract class is used to implement {@link BluetoothAdapter} callbacks. - */ -public abstract class BluetoothAdapterCallback { - - /** - * Indicates the callback has been registered successfully - */ - public static final int CALLBACK_REGISTERED = 0; - - /** - * Indicates the callback registration has failed - */ - public static final int CALLBACK_REGISTRATION_FAILURE = 1; - - /** - * Callback to inform change in registration state of the application. - * - * @param status Returns {@link #CALLBACK_REGISTERED} if the application - * was successfully registered. - */ - public void onCallbackRegistration(int status) { - } - - /** - * Callback reporting an LE device found during a device scan initiated - * by the {@link BluetoothAdapter#startLeScan} function. - * - * @param device Identifies the remote device - * @param rssi The RSSI value for the remote device as reported by the - * Bluetooth hardware. 0 if no RSSI value is available. - * @param scanRecord The content of the advertisement record offered by - * the remote device. - */ - public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { - } -} diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index 19083b5..172f3bc 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -127,7 +127,7 @@ public final class BluetoothManager { try { IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt(); + IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return connectedDevices; connectedDevices = iGatt.getDevicesMatchingConnectionStates( @@ -172,7 +172,7 @@ public final class BluetoothManager { try { IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt(); + IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) return devices; devices = iGatt.getDevicesMatchingConnectionStates(states); } catch (RemoteException e) { @@ -203,7 +203,7 @@ public final class BluetoothManager { try { IBluetoothManager managerService = mAdapter.getBluetoothManager(); - IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt(); + IBluetoothGatt iGatt = managerService.getBluetoothGatt(); if (iGatt == null) { Log.e(TAG, "Fail to get GATT Server connection"); return null; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 1ab1eb8..67bd952 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2425,8 +2425,8 @@ public class Intent implements Parcelable, Cloneable { * which is of type <code>ArrayList<RestrictionEntry></code>. It can also * contain an extra {@link #EXTRA_RESTRICTIONS_INTENT}, which is of type <code>Intent</code>. * The activity specified by that intent will be launched for a result which must contain - * the extra {@link #EXTRA_RESTRICTIONS_LIST}. The keys and values of the returned restrictions - * will be persisted. + * one of the extras {@link #EXTRA_RESTRICTIONS_LIST} or {@link #EXTRA_RESTRICTIONS_BUNDLE}. + * The keys and values of the returned restrictions will be persisted. * @see RestrictionEntry */ public static final String ACTION_GET_RESTRICTION_ENTRIES = diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index d64bff9..d8d5f2b 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -17,6 +17,7 @@ package android.content.res; import android.os.Trace; +import android.view.View; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; @@ -80,16 +81,16 @@ public class Resources { private static final Object sSync = new Object(); /*package*/ static Resources mSystem = null; - + // Information about preloaded resources. Note that they are not // protected by a lock, because while preloading in zygote we are all // single-threaded, and after that these are immutable. - private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables + private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables; + private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables = new LongSparseArray<Drawable.ConstantState>(); private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists = new LongSparseArray<ColorStateList>(); - private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables - = new LongSparseArray<Drawable.ConstantState>(); + private static boolean sPreloaded; private static int sPreloadedDensity; @@ -120,6 +121,12 @@ public class Resources { private CompatibilityInfo mCompatibilityInfo; + static { + sPreloadedDrawables = new LongSparseArray[2]; + sPreloadedDrawables[0] = new LongSparseArray<Drawable.ConstantState>(); + sPreloadedDrawables[1] = new LongSparseArray<Drawable.ConstantState>(); + } + /** @hide */ public static int selectDefaultTheme(int curTheme, int targetSdkVersion) { return selectSystemTheme(curTheme, targetSdkVersion, @@ -1982,6 +1989,7 @@ public class Resources { ActivityInfo.CONFIG_LAYOUT_DIRECTION); private boolean verifyPreloadConfig(int changingConfigurations, int resourceId, String name) { + // We dont want to preloadd a Drawable when there is both a LTR and RTL version of it if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_DENSITY)) & VARYING_CONFIGS) != 0) { String resName; @@ -1995,6 +2003,17 @@ public class Resources { + " (" + resName + ") that varies with configuration!!"); return false; } + if (TRACE_FOR_PRELOAD) { + String resName; + try { + resName = getResourceName(resourceId); + } catch (NotFoundException e) { + resName = "?"; + } + Log.w(TAG, "Preloading " + name + " resource #0x" + + Integer.toHexString(resourceId) + + " (" + resName + ")"); + } return true; } @@ -2022,11 +2041,11 @@ public class Resources { if (dr != null) { return dr; } - + final int layoutDirection = mConfiguration.getLayoutDirection(); Drawable.ConstantState cs = isColorDrawable ? sPreloadedColorDrawables.get(key) : (sPreloadedDensity == mConfiguration.densityDpi - ? sPreloadedDrawables.get(key) : null); + ? sPreloadedDrawables[layoutDirection].get(key) : null); if (cs != null) { dr = cs.newDrawable(this); } else { @@ -2100,11 +2119,12 @@ public class Resources { cs = dr.getConstantState(); if (cs != null) { if (mPreloading) { - if (verifyPreloadConfig(cs.getChangingConfigurations(), value.resourceId, "drawable")) { + if (verifyPreloadConfig(cs.getChangingConfigurations(), value.resourceId, + "drawable")) { if (isColorDrawable) { sPreloadedColorDrawables.put(key, cs); } else { - sPreloadedDrawables.put(key, cs); + sPreloadedDrawables[layoutDirection].put(key, cs); } } } else { diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 0856e27..b2034b2 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -107,6 +107,11 @@ public class UsbDeviceConnection { * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write, * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer * is a read. + * <p> + * This method transfers data starting from index 0 in the buffer. + * To specify a different offset, use + * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}. + * </p> * * @param requestType request type for this transaction * @param request request ID for this transaction @@ -118,11 +123,7 @@ public class UsbDeviceConnection { * @param timeout in milliseconds * @return length of data transferred (or zero) for success, * or negative value for failure - * - * @deprecated Use {@link #controlTransfer(int, int, int, int, byte[], int, int, int)} - * which accepts a buffer start index. */ - @Deprecated public int controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout) { return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout); @@ -142,22 +143,27 @@ public class UsbDeviceConnection { * @param index index field for this transaction * @param buffer buffer for data portion of transaction, * or null if no data needs to be sent or received - * @param start the index of the first byte in the buffer to send or receive + * @param offset the index of the first byte in the buffer to send or receive * @param length the length of the data to send or receive * @param timeout in milliseconds * @return length of data transferred (or zero) for success, * or negative value for failure */ public int controlTransfer(int requestType, int request, int value, int index, - byte[] buffer, int start, int length, int timeout) { - checkBounds(buffer, start, length); + byte[] buffer, int offset, int length, int timeout) { + checkBounds(buffer, offset, length); return native_control_request(requestType, request, value, index, - buffer, start, length, timeout); + buffer, offset, length, timeout); } /** * Performs a bulk transaction on the given endpoint. - * The direction of the transfer is determined by the direction of the endpoint + * The direction of the transfer is determined by the direction of the endpoint. + * <p> + * This method transfers data starting from index 0 in the buffer. + * To specify a different offset, use + * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}. + * </p> * * @param endpoint the endpoint for this transaction * @param buffer buffer for data to send or receive @@ -165,11 +171,7 @@ public class UsbDeviceConnection { * @param timeout in milliseconds * @return length of data transferred (or zero) for success, * or negative value for failure - * - * @deprecated Use {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)} - * which accepts a buffer start index. */ - @Deprecated public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) { return bulkTransfer(endpoint, buffer, 0, length, timeout); @@ -177,20 +179,20 @@ public class UsbDeviceConnection { /** * Performs a bulk transaction on the given endpoint. - * The direction of the transfer is determined by the direction of the endpoint + * The direction of the transfer is determined by the direction of the endpoint. * * @param endpoint the endpoint for this transaction * @param buffer buffer for data to send or receive - * @param start the index of the first byte in the buffer to send or receive + * @param offset the index of the first byte in the buffer to send or receive * @param length the length of the data to send or receive * @param timeout in milliseconds * @return length of data transferred (or zero) for success, * or negative value for failure */ public int bulkTransfer(UsbEndpoint endpoint, - byte[] buffer, int start, int length, int timeout) { - checkBounds(buffer, start, length); - return native_bulk_request(endpoint.getAddress(), buffer, start, length, timeout); + byte[] buffer, int offset, int length, int timeout) { + checkBounds(buffer, offset, length); + return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout); } /** @@ -235,9 +237,9 @@ public class UsbDeviceConnection { private native boolean native_claim_interface(int interfaceID, boolean force); private native boolean native_release_interface(int interfaceID); private native int native_control_request(int requestType, int request, int value, - int index, byte[] buffer, int start, int length, int timeout); + int index, byte[] buffer, int offset, int length, int timeout); private native int native_bulk_request(int endpoint, byte[] buffer, - int start, int length, int timeout); + int offset, int length, int timeout); private native UsbRequest native_request_wait(); private native String native_get_serial(); } diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index 2b359eb..ab4cd9b 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,8 +22,7 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2013 - * STOPSHIP - make sure we expose LinkProperties through ConnectivityManager + * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index d9846ec..61eef1f 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -51,6 +51,7 @@ public class Environment { private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled"; private static UserEnvironment sCurrentUser; + private static boolean sUserRequired; private static final Object sLock = new Object(); @@ -223,7 +224,7 @@ public class Environment { * @hide */ public static File getMediaStorageDirectory() { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getMediaStorageDirectory(); } @@ -318,7 +319,7 @@ public class Environment { * @see #isExternalStorageRemovable() */ public static File getExternalStorageDirectory() { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageDirectory(); } @@ -465,7 +466,7 @@ public class Environment { * using it such as with {@link File#mkdirs File.mkdirs()}. */ public static File getExternalStoragePublicDirectory(String type) { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStoragePublicDirectory(type); } @@ -474,7 +475,7 @@ public class Environment { * @hide */ public static File getExternalStorageAndroidDataDir() { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageAndroidDataDir(); } @@ -483,7 +484,7 @@ public class Environment { * @hide */ public static File getExternalStorageAppDataDirectory(String packageName) { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageAppDataDirectory(packageName); } @@ -492,7 +493,7 @@ public class Environment { * @hide */ public static File getExternalStorageAppMediaDirectory(String packageName) { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageAppMediaDirectory(packageName); } @@ -501,7 +502,7 @@ public class Environment { * @hide */ public static File getExternalStorageAppObbDirectory(String packageName) { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageAppObbDirectory(packageName); } @@ -510,7 +511,7 @@ public class Environment { * @hide */ public static File getExternalStorageAppFilesDirectory(String packageName) { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageAppFilesDirectory(packageName); } @@ -519,7 +520,7 @@ public class Environment { * @hide */ public static File getExternalStorageAppCacheDirectory(String packageName) { - throwIfSystem(); + throwIfUserRequired(); return sCurrentUser.getExternalStorageAppCacheDirectory(packageName); } @@ -650,9 +651,15 @@ public class Environment { } } - private static void throwIfSystem() { - if (Process.myUid() == Process.SYSTEM_UID) { - Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable()); + /** {@hide} */ + public static void setUserRequired(boolean userRequired) { + sUserRequired = userRequired; + } + + private static void throwIfUserRequired() { + if (sUserRequired) { + Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment", + new Throwable()); } } diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 94de448..14d8f07 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -413,27 +413,32 @@ public class Handler { /** * Runs the specified task synchronously. - * + * <p> * If the current thread is the same as the handler thread, then the runnable * runs immediately without being enqueued. Otherwise, posts the runnable * to the handler and waits for it to complete before returning. - * + * </p><p> * This method is dangerous! Improper use can result in deadlocks. * Never call this method while any locks are held or use it in a * possibly re-entrant manner. - * + * </p><p> * This method is occasionally useful in situations where a background thread * must synchronously await completion of a task that must run on the * handler's thread. However, this problem is often a symptom of bad design. * Consider improving the design (if possible) before resorting to this method. - * + * </p><p> * One example of where you might want to use this method is when you just * set up a Handler thread and need to perform some initialization steps on * it before continuing execution. - * + * </p><p> * If timeout occurs then this method returns <code>false</code> but the runnable * will remain posted on the handler and may already be in progress or * complete at a later time. + * </p><p> + * When using this method, be sure to use {@link Looper#quitSafely} when + * quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely. + * (TODO: We should fix this by making MessageQueue aware of blocking runnables.) + * </p> * * @param r The Runnable that will be executed synchronously. * @param timeout The timeout in milliseconds, or 0 to wait indefinitely. diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java index daf1f59..2904105 100644 --- a/core/java/android/os/HandlerThread.java +++ b/core/java/android/os/HandlerThread.java @@ -48,6 +48,7 @@ public class HandlerThread extends Thread { protected void onLooperPrepared() { } + @Override public void run() { mTid = Process.myTid(); Looper.prepare(); @@ -83,12 +84,25 @@ public class HandlerThread extends Thread { } return mLooper; } - + /** - * Ask the currently running looper to quit. If the thread has not - * been started or has finished (that is if {@link #getLooper} returns - * null), then false is returned. Otherwise the looper is asked to - * quit and true is returned. + * Quits the handler thread's looper. + * <p> + * Causes the handler thread's looper to terminate without processing any + * more messages in the message queue. + * </p><p> + * Any attempt to post messages to the queue after the looper is asked to quit will fail. + * For example, the {@link Handler#sendMessage(Message)} method will return false. + * </p><p class="note"> + * Using this method may be unsafe because some messages may not be delivered + * before the looper terminates. Consider using {@link #quitSafely} instead to ensure + * that all pending work is completed in an orderly manner. + * </p> + * + * @return True if the looper looper has been asked to quit or false if the + * thread had not yet started running. + * + * @see #quitSafely */ public boolean quit() { Looper looper = getLooper(); @@ -98,7 +112,34 @@ public class HandlerThread extends Thread { } return false; } - + + /** + * Quits the handler thread's looper safely. + * <p> + * Causes the handler thread's looper to terminate as soon as all remaining messages + * in the message queue that are already due to be delivered have been handled. + * Pending delayed messages with due times in the future will not be delivered. + * </p><p> + * Any attempt to post messages to the queue after the looper is asked to quit will fail. + * For example, the {@link Handler#sendMessage(Message)} method will return false. + * </p><p> + * If the thread has not been started or has finished (that is if + * {@link #getLooper} returns null), then false is returned. + * Otherwise the looper is asked to quit and true is returned. + * </p> + * + * @return True if the looper looper has been asked to quit or false if the + * thread had not yet started running. + */ + public boolean quitSafely() { + Looper looper = getLooper(); + if (looper != null) { + looper.quitSafely(); + return true; + } + return false; + } + /** * Returns the identifier of this thread. See Process.myTid(). */ diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index fa28765..d5cf771 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -202,18 +202,37 @@ public final class Looper { /** * Quits the looper. * <p> + * Causes the {@link #loop} method to terminate without processing any + * more messages in the message queue. + * </p><p> + * Any attempt to post messages to the queue after the looper is asked to quit will fail. + * For example, the {@link Handler#sendMessage(Message)} method will return false. + * </p><p class="note"> + * Using this method may be unsafe because some messages may not be delivered + * before the looper terminates. Consider using {@link #quitSafely} instead to ensure + * that all pending work is completed in an orderly manner. + * </p> + * + * @see #quitSafely + */ + public void quit() { + mQueue.quit(false); + } + + /** + * Quits the looper safely. + * <p> * Causes the {@link #loop} method to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. - * However delayed messages with due times in the future may not be handled before - * the loop terminates. + * However pending delayed messages with due times in the future will not be + * delivered before the loop terminates. * </p><p> - * Any attempt to post messages to the queue after {@link #quit} has been called - * will fail. For example, the {@link Handler#sendMessage(Message)} method will - * return false when the looper is being terminated. + * Any attempt to post messages to the queue after the looper is asked to quit will fail. + * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p> */ - public void quit() { - mQueue.quit(); + public void quitSafely() { + mQueue.quit(true); } /** diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index c058bfc..bf7e5ca 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -219,7 +219,7 @@ public final class MessageQueue { } } - void quit() { + void quit(boolean safe) { if (!mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit."); } @@ -229,6 +229,12 @@ public final class MessageQueue { return; } mQuiting = true; + + if (safe) { + removeAllFutureMessagesLocked(); + } else { + removeAllMessagesLocked(); + } } nativeWake(mPtr); } @@ -473,4 +479,42 @@ public final class MessageQueue { } } } + + private void removeAllMessagesLocked() { + Message p = mMessages; + while (p != null) { + Message n = p.next; + p.recycle(); + p = n; + } + mMessages = null; + } + + private void removeAllFutureMessagesLocked() { + final long now = SystemClock.uptimeMillis(); + Message p = mMessages; + if (p != null) { + if (p.when > now) { + removeAllMessagesLocked(); + } else { + Message n; + for (;;) { + n = p.next; + if (n == null) { + return; + } + if (n.when > now) { + break; + } + p = n; + } + p.next = null; + do { + p = n; + n = p.next; + p.recycle(); + } while (n != null); + } + } + } } diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java index 60ec0d7..2314057 100644 --- a/core/java/android/os/StatFs.java +++ b/core/java/android/os/StatFs.java @@ -57,9 +57,9 @@ public class StatFs { } /** - * The size, in bytes, of a block on the file system. This corresponds to - * the Unix {@code statfs.f_bsize} field. + * @deprecated Use {@link #getBlockSizeLong()} instead. */ + @Deprecated public int getBlockSize() { return (int) mStat.f_bsize; } @@ -73,27 +73,25 @@ public class StatFs { } /** - * The total number of blocks on the file system. This corresponds to the - * Unix {@code statfs.f_blocks} field. + * @deprecated Use {@link #getBlockCountLong()} instead. */ + @Deprecated public int getBlockCount() { return (int) mStat.f_blocks; } /** - * The size, in bytes, of a block on the file system. This corresponds to - * the Unix {@code statfs.f_bsize} field. + * The total number of blocks on the file system. This corresponds to the + * Unix {@code statfs.f_blocks} field. */ public long getBlockCountLong() { return mStat.f_blocks; } /** - * The total number of blocks that are free on the file system, including - * reserved blocks (that are not available to normal applications). This - * corresponds to the Unix {@code statfs.f_bfree} field. Most applications - * will want to use {@link #getAvailableBlocks()} instead. + * @deprecated Use {@link #getFreeBlocksLong()} instead. */ + @Deprecated public int getFreeBlocks() { return (int) mStat.f_bfree; } @@ -109,17 +107,18 @@ public class StatFs { } /** - * The number of bytes that are free on the file system, including - * reserved blocks (that are not available to normal applications). + * The number of bytes that are free on the file system, including reserved + * blocks (that are not available to normal applications). Most applications + * will want to use {@link #getAvailableBytes()} instead. */ public long getFreeBytes() { return mStat.f_bfree * mStat.f_bsize; } /** - * The number of blocks that are free on the file system and available to - * applications. This corresponds to the Unix {@code statfs.f_bavail} field. + * @deprecated Use {@link #getAvailableBlocksLong()} instead. */ + @Deprecated public int getAvailableBlocks() { return (int) mStat.f_bavail; } @@ -139,4 +138,11 @@ public class StatFs { public long getAvailableBytes() { return mStat.f_bavail * mStat.f_bsize; } + + /** + * The total number of bytes supported by the file system. + */ + public long getTotalBytes() { + return mStat.f_blocks * mStat.f_bsize; + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3df4e99..4de5933 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -714,6 +714,17 @@ public final class Settings { */ public static final String EXTRA_AUTHORITIES = "authorities"; + /** + * Activity Extra: Limit available options in launched activity based on the given account + * types. + * <p> + * This can be passed as an extra field in an Activity Intent with one or more account types + * as a String[]. This field is used by some intents to alter the behavior of the called + * activity. + * <p> + * Example: The {@link #ACTION_ADD_ACCOUNT} intent restricts the account types to the specified + * list. + */ public static final String EXTRA_ACCOUNT_TYPES = "account_types"; public static final String EXTRA_INPUT_METHOD_ID = "input_method_id"; diff --git a/core/java/android/util/PropertyValueModel.java b/core/java/android/util/PropertyValueModel.java deleted file mode 100755 index eb9c47d..0000000 --- a/core/java/android/util/PropertyValueModel.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * A value model for a {@link Property property} of a host object. This class can be used for - * both reflective and non-reflective property implementations. - * - * @param <H> the host type, where the host is the object that holds this property - * @param <T> the value type - * - * @see Property - * @see ValueModel - */ -public class PropertyValueModel<H, T> extends ValueModel<T> { - private final H mHost; - private final Property<H, T> mProperty; - - private PropertyValueModel(H host, Property<H, T> property) { - mProperty = property; - mHost = host; - } - - /** - * Returns the host. - * - * @return the host - */ - public H getHost() { - return mHost; - } - - /** - * Returns the property. - * - * @return the property - */ - public Property<H, T> getProperty() { - return mProperty; - } - - @Override - public Class<T> getType() { - return mProperty.getType(); - } - - @Override - public T get() { - return mProperty.get(mHost); - } - - @Override - public void set(T value) { - mProperty.set(mHost, value); - } - - /** - * Return an appropriate PropertyValueModel for this host and property. - * - * @param host the host - * @param property the property - * @return the value model - */ - public static <H, T> PropertyValueModel<H, T> of(H host, Property<H, T> property) { - return new PropertyValueModel<H, T>(host, property); - } - - /** - * Return a PropertyValueModel for this {@code host} and a - * reflective property, constructed from this {@code propertyType} and {@code propertyName}. - * - * @param host - * @param propertyType the property type - * @param propertyName the property name - * @return a value model with this host and a reflective property with this type and name - * - * @see Property#of - */ - public static <H, T> PropertyValueModel<H, T> of(H host, Class<T> propertyType, - String propertyName) { - return of(host, Property.of((Class<H>) host.getClass(), propertyType, propertyName)); - } - - private static Class getNullaryMethodReturnType(Class c, String name) { - try { - return c.getMethod(name).getReturnType(); - } catch (NoSuchMethodException e) { - return null; - } - } - - private static Class getFieldType(Class c, String name) { - try { - return c.getField(name).getType(); - } catch (NoSuchFieldException e) { - return null; - } - } - - private static String capitalize(String name) { - if (name.isEmpty()) { - return name; - } - return Character.toUpperCase(name.charAt(0)) + name.substring(1); - } - - /** - * Return a PropertyValueModel for this {@code host} and and {@code propertyName}. - * - * @param host the host - * @param propertyName the property name - * @return a value model with this host and a reflective property with this name - */ - public static PropertyValueModel of(Object host, String propertyName) { - Class clazz = host.getClass(); - String suffix = capitalize(propertyName); - Class propertyType = getNullaryMethodReturnType(clazz, "get" + suffix); - if (propertyType == null) { - propertyType = getNullaryMethodReturnType(clazz, "is" + suffix); - } - if (propertyType == null) { - propertyType = getFieldType(clazz, propertyName); - } - if (propertyType == null) { - throw new NoSuchPropertyException(propertyName); - } - return of(host, propertyType, propertyName); - } -} diff --git a/core/java/android/util/ValueModel.java b/core/java/android/util/ValueModel.java deleted file mode 100755 index 4789682..0000000 --- a/core/java/android/util/ValueModel.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.util; - -/** - * A ValueModel is an abstraction for a 'slot' or place in memory in which a value - * may be stored and retrieved. A common implementation of ValueModel is a regular property of - * an object, whose value may be retrieved by calling the appropriate <em>getter</em> - * method and set by calling the corresponding <em>setter</em> method. - * - * @param <T> the value type - * - * @see PropertyValueModel - */ -public abstract class ValueModel<T> { - /** - * The empty model should be used in place of {@code null} to indicate that a - * model has not been set. The empty model has no value and does nothing when it is set. - */ - public static final ValueModel EMPTY = new ValueModel() { - @Override - public Class getType() { - return Object.class; - } - - @Override - public Object get() { - return null; - } - - @Override - public void set(Object value) { - - } - }; - - protected ValueModel() { - } - - /** - * Returns the type of this property. - * - * @return the property type - */ - public abstract Class<T> getType(); - - /** - * Returns the value of this property. - * - * @return the property value - */ - public abstract T get(); - - /** - * Sets the value of this property. - * - * @param value the new value for this property - */ - public abstract void set(T value); -}
\ No newline at end of file diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index be26d20..a0a63a6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2915,14 +2915,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ - int mUserPaddingLeftInitial = 0; + int mUserPaddingLeftInitial; /** * Cache initial right padding. * * @hide */ - int mUserPaddingRightInitial = 0; + int mUserPaddingRightInitial; /** * Default undefined padding @@ -3388,11 +3388,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, break; case com.android.internal.R.styleable.View_paddingStart: startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); - startPaddingDefined = true; + startPaddingDefined = (startPadding != UNDEFINED_PADDING); break; case com.android.internal.R.styleable.View_paddingEnd: endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); - endPaddingDefined = true; + endPaddingDefined = (endPadding != UNDEFINED_PADDING); break; case com.android.internal.R.styleable.View_scrollX: x = a.getDimensionPixelOffset(attr, 0); @@ -3712,10 +3712,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if // defined. - if (leftPaddingDefined) { + final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; + + if (leftPaddingDefined && !hasRelativePadding) { mUserPaddingLeftInitial = leftPadding; } - if (rightPaddingDefined) { + if (rightPaddingDefined && !hasRelativePadding) { mUserPaddingRightInitial = rightPadding; } } @@ -11952,26 +11954,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // left / right or right / left depending on the resolved layout direction. // If start / end padding are not defined, use the left / right ones. int resolvedLayoutDirection = getLayoutDirection(); - // Set user padding to initial values ... - mUserPaddingLeft = mUserPaddingLeftInitial; - mUserPaddingRight = mUserPaddingRightInitial; - // ... then resolve it. switch (resolvedLayoutDirection) { case LAYOUT_DIRECTION_RTL: if (mUserPaddingStart != UNDEFINED_PADDING) { mUserPaddingRight = mUserPaddingStart; + } else { + mUserPaddingRight = mUserPaddingRightInitial; } if (mUserPaddingEnd != UNDEFINED_PADDING) { mUserPaddingLeft = mUserPaddingEnd; + } else { + mUserPaddingLeft = mUserPaddingLeftInitial; } break; case LAYOUT_DIRECTION_LTR: default: if (mUserPaddingStart != UNDEFINED_PADDING) { mUserPaddingLeft = mUserPaddingStart; + } else { + mUserPaddingLeft = mUserPaddingLeftInitial; } if (mUserPaddingEnd != UNDEFINED_PADDING) { mUserPaddingRight = mUserPaddingEnd; + } else { + mUserPaddingRight = mUserPaddingRightInitial; } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 9c1b7a0..d52b1f3 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -795,9 +795,7 @@ public interface WindowManager extends ViewManager { * <p>This flag can be controlled in your theme through the * {@link android.R.attr#windowOverscan} attribute; this attribute * is automatically set for you in the standard overscan themes - * such as {@link android.R.style#Theme_NoTitleBar_Overscan}, - * {@link android.R.style#Theme_Black_NoTitleBar_Overscan}, - * {@link android.R.style#Theme_Light_NoTitleBar_Overscan}, + * such as * {@link android.R.style#Theme_Holo_NoActionBar_Overscan}, * {@link android.R.style#Theme_Holo_Light_NoActionBar_Overscan}, * {@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan}, and diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java index 41ab5f2..f1804f8 100644 --- a/core/java/android/widget/CheckBox.java +++ b/core/java/android/widget/CheckBox.java @@ -20,7 +20,6 @@ import android.content.Context; import android.util.AttributeSet; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; -import android.util.ValueModel; /** @@ -56,9 +55,7 @@ import android.util.ValueModel; * {@link android.R.styleable#View View Attributes} * </p> */ -public class CheckBox extends CompoundButton implements ValueEditor<Boolean> { - private ValueModel<Boolean> mValueModel = ValueModel.EMPTY; - +public class CheckBox extends CompoundButton { public CheckBox(Context context) { this(context, null); } @@ -82,22 +79,4 @@ public class CheckBox extends CompoundButton implements ValueEditor<Boolean> { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(CheckBox.class.getName()); } - - @Override - public ValueModel<Boolean> getValueModel() { - return mValueModel; - } - - @Override - public void setValueModel(ValueModel<Boolean> valueModel) { - mValueModel = valueModel; - setChecked(mValueModel.get()); - } - - @Override - public boolean performClick() { - boolean handled = super.performClick(); - mValueModel.set(isChecked()); - return handled; - } } diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java index ec81214..57e51c2 100644 --- a/core/java/android/widget/EditText.java +++ b/core/java/android/widget/EditText.java @@ -17,7 +17,6 @@ package android.widget; import android.content.Context; -import android.graphics.Rect; import android.text.Editable; import android.text.Selection; import android.text.Spannable; @@ -25,7 +24,6 @@ import android.text.TextUtils; import android.text.method.ArrowKeyMovementMethod; import android.text.method.MovementMethod; import android.util.AttributeSet; -import android.util.ValueModel; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -49,9 +47,7 @@ import android.view.accessibility.AccessibilityNodeInfo; * {@link android.R.styleable#TextView TextView Attributes}, * {@link android.R.styleable#View View Attributes} */ -public class EditText extends TextView implements ValueEditor<CharSequence> { - private ValueModel<CharSequence> mValueModel = ValueModel.EMPTY; - +public class EditText extends TextView { public EditText(Context context) { this(context, null); } @@ -132,21 +128,4 @@ public class EditText extends TextView implements ValueEditor<CharSequence> { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(EditText.class.getName()); } - - @Override - public ValueModel<CharSequence> getValueModel() { - return mValueModel; - } - - @Override - public void setValueModel(ValueModel<CharSequence> valueModel) { - mValueModel = valueModel; - setText(mValueModel.get()); - } - - @Override - void sendAfterTextChanged(Editable text) { - super.sendAfterTextChanged(text); - mValueModel.set(text); - } } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index c7914f3..f42999d 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -41,6 +41,7 @@ import android.view.ViewParent; import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeProvider; import android.widget.RemoteViews.RemoteView; import java.util.ArrayList; @@ -1715,11 +1716,17 @@ public class ListView extends AbsListView { } // Attempt to restore accessibility focus. - if (accessibilityFocusLayoutRestoreNode != null) { - accessibilityFocusLayoutRestoreNode.performAction( - AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); - } else if (accessibilityFocusLayoutRestoreView != null) { - accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + if (accessibilityFocusLayoutRestoreView != null) { + final AccessibilityNodeProvider provider = + accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider(); + if ((accessibilityFocusLayoutRestoreNode != null) && (provider != null)) { + final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId( + accessibilityFocusLayoutRestoreNode.getSourceNodeId()); + provider.performAction(virtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); + } else { + accessibilityFocusLayoutRestoreView.requestAccessibilityFocus(); + } } else if (accessibilityFocusPosition != INVALID_POSITION) { // Bound the position within the visible children. final int position = MathUtils.constrain( diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java index a6486a8..2737f94 100644 --- a/core/java/android/widget/SeekBar.java +++ b/core/java/android/widget/SeekBar.java @@ -18,7 +18,6 @@ package android.widget; import android.content.Context; import android.util.AttributeSet; -import android.util.ValueModel; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -34,7 +33,7 @@ import android.view.accessibility.AccessibilityNodeInfo; * * @attr ref android.R.styleable#SeekBar_thumb */ -public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> { +public class SeekBar extends AbsSeekBar { /** * A callback that notifies clients when the progress level has been @@ -70,9 +69,8 @@ public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> { void onStopTrackingTouch(SeekBar seekBar); } - private ValueModel<Integer> mValueModel = ValueModel.EMPTY; private OnSeekBarChangeListener mOnSeekBarChangeListener; - + public SeekBar(Context context) { this(context, null); } @@ -91,23 +89,9 @@ public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> { if (mOnSeekBarChangeListener != null) { mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser); - if (fromUser) { - mValueModel.set(getProgress()); - } } } - @Override - public ValueModel<Integer> getValueModel() { - return mValueModel; - } - - @Override - public void setValueModel(ValueModel<Integer> valueModel) { - mValueModel = valueModel; - setProgress(mValueModel.get()); - } - /** * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also * provides notifications of when the user starts and stops a touch gesture within the SeekBar. diff --git a/core/java/android/widget/ValueEditor.java b/core/java/android/widget/ValueEditor.java deleted file mode 100755 index 2b91abf..0000000 --- a/core/java/android/widget/ValueEditor.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.widget; - -import android.util.ValueModel; - -/** - * An interface for editors of simple values. Classes implementing this interface are normally - * UI controls (subclasses of {@link android.view.View View}) that can provide a suitable - * user interface to display and edit values of the specified type. This interface is - * intended to describe editors for simple types, like {@code boolean}, {@code int} or - * {@code String}, where the values themselves are immutable. - * <p> - * For example, {@link android.widget.CheckBox CheckBox} implements - * this interface for the Boolean type as it is capable of providing an appropriate - * mechanism for displaying and changing the value of a Boolean property. - * - * @param <T> the value type that this editor supports - */ -public interface ValueEditor<T> { - /** - * Return the last value model that was set. If no value model has been set, the editor - * should return the value {@link android.util.ValueModel#EMPTY}. - * - * @return the value model - */ - public ValueModel<T> getValueModel(); - - /** - * Sets the value model for this editor. When the value model is set, the editor should - * retrieve the value from the value model, using {@link android.util.ValueModel#get()}, - * and set its internal state accordingly. Likewise, when the editor's internal state changes - * it should update the value model by calling {@link android.util.ValueModel#set(T)} - * with the appropriate value. - * - * @param valueModel the new value model for this editor. - */ - public void setValueModel(ValueModel<T> valueModel); -} |