diff options
Diffstat (limited to 'core/java')
17 files changed, 210 insertions, 275 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index aa7692b..7a20929 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -43,6 +43,7 @@ import com.google.android.collect.Maps; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; @@ -2259,6 +2260,9 @@ public class AccountManager { } /** + * Deprecated in favor of {@link #newChooseAccountIntent(Account, List, String[], String, + * String, String[], Bundle)}. + * * Returns an intent to an {@link Activity} that prompts the user to choose from a list of * accounts. * The caller will then typically start the activity by calling @@ -2273,14 +2277,13 @@ public class AccountManager { * null, null, null);</pre> * @param selectedAccount if specified, indicates that the {@link Account} is the currently * selected one, according to the caller's definition of selected. - * @param allowableAccounts an optional {@link ArrayList} of accounts that are allowed to be + * @param allowableAccounts an optional {@link List} of accounts that are allowed to be * shown. If not specified then this field will not limit the displayed accounts. * @param allowableAccountTypes an optional string array of account types. These are used * both to filter the shown accounts and to filter the list of account types that are shown * when adding an account. If not specified then this field will not limit the displayed * account types when adding an account. - * @param alwaysPromptForAccount if set the account chooser screen is always shown, otherwise - * it is only shown when there is more than one account from which to choose + * @param alwaysPromptForAccount boolean that is ignored. * @param descriptionOverrideText if non-null this string is used as the description in the * accounts chooser screen rather than the default * @param addAccountAuthTokenType this string is passed as the {@link #addAccount} @@ -2291,7 +2294,9 @@ public class AccountManager { * parameter * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow. */ - static public Intent newChooseAccountIntent(Account selectedAccount, + @Deprecated + static public Intent newChooseAccountIntent( + Account selectedAccount, ArrayList<Account> allowableAccounts, String[] allowableAccountTypes, boolean alwaysPromptForAccount, @@ -2299,20 +2304,67 @@ public class AccountManager { String addAccountAuthTokenType, String[] addAccountRequiredFeatures, Bundle addAccountOptions) { + return newChooseAccountIntent( + selectedAccount, + allowableAccounts, + allowableAccountTypes, + descriptionOverrideText, + addAccountAuthTokenType, + addAccountRequiredFeatures, + addAccountOptions); + } + + /** + * Returns an intent to an {@link Activity} that prompts the user to choose from a list of + * accounts. + * The caller will then typically start the activity by calling + * <code>startActivityForResult(intent, ...);</code>. + * <p> + * On success the activity returns a Bundle with the account name and type specified using + * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}. + * <p> + * The most common case is to call this with one account type, e.g.: + * <p> + * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, null, null, null, + * null);</pre> + * @param selectedAccount if specified, indicates that the {@link Account} is the currently + * selected one, according to the caller's definition of selected. + * @param allowableAccounts an optional {@link List} of accounts that are allowed to be + * shown. If not specified then this field will not limit the displayed accounts. + * @param allowableAccountTypes an optional string array of account types. These are used + * both to filter the shown accounts and to filter the list of account types that are shown + * when adding an account. If not specified then this field will not limit the displayed + * account types when adding an account. + * @param descriptionOverrideText if non-null this string is used as the description in the + * accounts chooser screen rather than the default + * @param addAccountAuthTokenType this string is passed as the {@link #addAccount} + * authTokenType parameter + * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount} + * requiredFeatures parameter + * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options + * parameter + * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow. + */ + static public Intent newChooseAccountIntent( + Account selectedAccount, + List<Account> allowableAccounts, + String[] allowableAccountTypes, + String descriptionOverrideText, + String addAccountAuthTokenType, + String[] addAccountRequiredFeatures, + Bundle addAccountOptions) { Intent intent = new Intent(); ComponentName componentName = ComponentName.unflattenFromString( Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity)); intent.setClassName(componentName.getPackageName(), componentName.getClassName()); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST, - allowableAccounts); + new ArrayList<Account>(allowableAccounts)); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY, allowableAccountTypes); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE, addAccountOptions); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount); - intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, - alwaysPromptForAccount); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE, descriptionOverrideText); intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING, diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index c06b462..133df2b 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -88,9 +88,10 @@ public class ChooseTypeAndAccountActivity extends Activity public static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount"; /** - * If true then display the account selection list even if there is just - * one account to choose from. boolean. + * Deprecated. Providing this extra to {@link ChooseTypeAndAccountActivity} + * will have no effect. */ + @Deprecated public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT = "alwaysPromptForAccount"; @@ -117,7 +118,6 @@ public class ChooseTypeAndAccountActivity extends Activity private Set<String> mSetOfRelevantAccountTypes; private String mSelectedAccountName = null; private boolean mSelectedAddNewAccount = false; - private boolean mAlwaysPromptForAccount = false; private String mDescriptionOverride; private ArrayList<Account> mAccounts; @@ -188,7 +188,6 @@ public class ChooseTypeAndAccountActivity extends Activity mSetOfAllowableAccounts = getAllowableAccountSet(intent); mSetOfRelevantAccountTypes = getReleventAccountTypes(intent); - mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false); mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE); mAccounts = getAcceptableAccountChoices(AccountManager.get(this)); @@ -218,15 +217,6 @@ public class ChooseTypeAndAccountActivity extends Activity } else { startChooseAccountTypeActivity(); } - return; - } - - // if there is only one allowable account return it - if (!mAlwaysPromptForAccount && mAccounts.size() == 1) { - Account account = mAccounts.get(0); - super.onCreate(savedInstanceState); - setResultAndFinish(account.name, account.type); - return; } } diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index e7deae8..30cdfd3 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -123,7 +123,10 @@ public class SystemSensorManager extends SensorManager { SensorEventQueue queue = mSensorListeners.get(listener); if (queue == null) { Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; - queue = new SensorEventQueue(listener, looper, this); + final String fullClassName = listener.getClass().getEnclosingClass() != null ? + listener.getClass().getEnclosingClass().getName() : + listener.getClass().getName(); + queue = new SensorEventQueue(listener, looper, this, fullClassName); if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) { queue.dispose(); return false; @@ -166,12 +169,17 @@ public class SystemSensorManager extends SensorManager { protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); + if (listener == null) throw new IllegalArgumentException("listener cannot be null"); + if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false; synchronized (mTriggerListeners) { TriggerEventQueue queue = mTriggerListeners.get(listener); if (queue == null) { - queue = new TriggerEventQueue(listener, mMainLooper, this); + final String fullClassName = listener.getClass().getEnclosingClass() != null ? + listener.getClass().getEnclosingClass().getName() : + listener.getClass().getName(); + queue = new TriggerEventQueue(listener, mMainLooper, this, fullClassName); if (!queue.addSensor(sensor, 0, 0)) { queue.dispose(); return false; @@ -234,7 +242,8 @@ public class SystemSensorManager extends SensorManager { } // Initialize a client for data_injection. if (mInjectEventQueue == null) { - mInjectEventQueue = new InjectEventQueue(mMainLooper, this); + mInjectEventQueue = new InjectEventQueue(mMainLooper, this, + mContext.getPackageName()); } } else { // If data injection is being disabled clean up the native resources. @@ -296,10 +305,11 @@ public class SystemSensorManager extends SensorManager { protected static final int OPERATING_MODE_NORMAL = 0; protected static final int OPERATING_MODE_DATA_INJECTION = 1; - BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) { + BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) { + if (packageName == null) packageName = ""; nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance, new WeakReference<>(this), looper.getQueue(), mScratch, - manager.mContext.getPackageName(), mode, manager.mContext.getOpPackageName()); + packageName, mode, manager.mContext.getOpPackageName()); mCloseGuard.open("dispose"); mManager = manager; } @@ -419,8 +429,8 @@ public class SystemSensorManager extends SensorManager { private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); public SensorEventQueue(SensorEventListener listener, Looper looper, - SystemSensorManager manager) { - super(looper, manager, OPERATING_MODE_NORMAL); + SystemSensorManager manager, String packageName) { + super(looper, manager, OPERATING_MODE_NORMAL, packageName); mListener = listener; } @@ -486,8 +496,8 @@ public class SystemSensorManager extends SensorManager { private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>(); public TriggerEventQueue(TriggerEventListener listener, Looper looper, - SystemSensorManager manager) { - super(looper, manager, OPERATING_MODE_NORMAL); + SystemSensorManager manager, String packageName) { + super(looper, manager, OPERATING_MODE_NORMAL, packageName); mListener = listener; } @@ -540,8 +550,8 @@ public class SystemSensorManager extends SensorManager { } final class InjectEventQueue extends BaseEventQueue { - public InjectEventQueue(Looper looper, SystemSensorManager manager) { - super(looper, manager, OPERATING_MODE_DATA_INJECTION); + public InjectEventQueue(Looper looper, SystemSensorManager manager, String packageName) { + super(looper, manager, OPERATING_MODE_DATA_INJECTION, packageName); } int injectSensorData(int handle, float[] values,int accuracy, long timestamp) { diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index c8ae5d4..c36683b 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1935,21 +1935,21 @@ public abstract class CameraMetadata<TKey> { /** * <p>Same as FACE_PRIORITY scene mode, except that the camera - * device will choose higher sensivity values ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}) + * device will choose higher sensitivity values ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}) * under low light conditions.</p> * <p>The camera device may be tuned to expose the images in a reduced * sensitivity range to produce the best quality images. For example, * if the {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange} gives range of [100, 1600], * the camera device auto-exposure routine tuning process may limit the actual - * exposure sensivity range to [100, 1200] to ensure that the noise level isn't - * exessive to compromise the image quality. Under this situation, the image under + * exposure sensitivity range to [100, 1200] to ensure that the noise level isn't + * exessive in order to preserve the image quality. Under this situation, the image under * low light may be under-exposed when the sensor max exposure time (bounded by the * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange} when {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is one of the - * ON_* modes) and effecitve max sensitivity are reached. This scene mode allows the + * ON_* modes) and effective max sensitivity are reached. This scene mode allows the * camera device auto-exposure routine to increase the sensitivity up to the max * sensitivity specified by {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange} when the scene is too * dark and the max exposure time is reached. The captured images may be noisier - * compared with the images captured in normal FACE_PRIORITY mode, therefore, it is + * compared with the images captured in normal FACE_PRIORITY mode; therefore, it is * recommended that the application only use this scene mode when it is capable of * reducing the noise level of the captured images.</p> * <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}, diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index de7ca0c..dc8ff8f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -431,7 +431,8 @@ public class ConnectivityManager { public static final int TYPE_MOBILE_IA = 14; /** - * Emergency PDN connection for emergency calls + * Emergency PDN connection for emergency services. This + * may include IMS and MMS in emergency situations. * {@hide} */ public static final int TYPE_MOBILE_EMERGENCY = 15; diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 78f8b95..46c28a6 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -112,7 +112,7 @@ interface IConnectivityManager void startLegacyVpn(in VpnProfile profile); - LegacyVpnInfo getLegacyVpnInfo(); + LegacyVpnInfo getLegacyVpnInfo(int userId); VpnInfo[] getAllVpnInfo(); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 658051c..514d24a 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -133,7 +133,8 @@ public final class NetworkCapabilities implements Parcelable { /** * Indicates this is a network that has the ability to reach a carrier's - * Emergency IMS servers, used for network signaling during emergency calls. + * Emergency IMS servers or other services, used for network signaling + * during emergency calls. */ public static final int NET_CAPABILITY_EIMS = 10; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4e13758..fff355b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -574,7 +574,22 @@ public final class Settings { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MANAGE_OVERLAY_PERMISSION = - "android.settings.MANAGE_OVERLAY_PERMISSION"; + "android.settings.action.MANAGE_OVERLAY_PERMISSION"; + + /** + * Activity Action: Show settings to toggle apps' capablity to + * to read/write system settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MANAGE_WRITE_SETTINGS = + "android.settings.action.MANAGE_WRITE_SETTINGS"; /** * Activity Action: Show screen of details about a particular application. diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index a55a08c..dc1d6f6 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -137,7 +137,12 @@ public class Html { } /** - * Returns an HTML representation of the provided Spanned text. + * Returns an HTML representation of the provided Spanned text. A best effort is + * made to add HTML tags corresponding to spans. Also note that HTML metacharacters + * (such as "<" and "&") within the input text are escaped. + * + * @param text input text to convert + * @return string containing input converted to HTML */ public static String toHtml(Spanned text) { StringBuilder out = new StringBuilder(); diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java index d114d32..5c5deb4 100644 --- a/core/java/android/text/SpannableStringInternal.java +++ b/core/java/android/text/SpannableStringInternal.java @@ -214,10 +214,6 @@ import java.lang.reflect.Array; Object ret1 = null; for (int i = 0; i < spanCount; i++) { - if (kind != null && !kind.isInstance(spans[i])) { - continue; - } - int spanStart = data[i * COLUMNS + START]; int spanEnd = data[i * COLUMNS + END]; @@ -237,6 +233,11 @@ import java.lang.reflect.Array; } } + // verify span class as late as possible, since it is expensive + if (kind != null && !kind.isInstance(spans[i])) { + continue; + } + if (count == 0) { ret1 = spans[i]; count++; diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index cdff395..efc9e1a 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -744,7 +744,8 @@ public class StaticLayout extends Layout { && (ellipsize == TextUtils.TruncateAt.END || (mMaximumVisibleLineCount == 1 && ellipsize != TextUtils.TruncateAt.MARQUEE)); - if (remainingLineCount < breakCount && ellipsisMayBeApplied) { + if (remainingLineCount > 0 && remainingLineCount < breakCount && + ellipsisMayBeApplied) { // Treat the last line and overflowed lines as a single line. breaks[remainingLineCount - 1] = breaks[breakCount - 1]; // Calculate width and flag. diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index d1af9dc..e3ce6f2 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -61,8 +61,6 @@ import java.util.Set; */ public class AppSecurityPermissions { - public static final int WHICH_PERSONAL = 1<<0; - public static final int WHICH_DEVICE = 1<<1; public static final int WHICH_NEW = 1<<2; public static final int WHICH_ALL = 0xffff; @@ -75,7 +73,8 @@ public class AppSecurityPermissions { = new HashMap<String, MyPermissionGroupInfo>(); private final List<MyPermissionGroupInfo> mPermGroupsList = new ArrayList<MyPermissionGroupInfo>(); - private final PermissionGroupInfoComparator mPermGroupComparator = new PermissionGroupInfoComparator(); + private final PermissionGroupInfoComparator mPermGroupComparator = + new PermissionGroupInfoComparator(); private final PermissionInfoComparator mPermComparator = new PermissionInfoComparator(); private final List<MyPermissionInfo> mPermsList = new ArrayList<MyPermissionInfo>(); private final CharSequence mNewPermPrefix; @@ -85,8 +84,6 @@ public class AppSecurityPermissions { CharSequence mLabel; final ArrayList<MyPermissionInfo> mNewPermissions = new ArrayList<MyPermissionInfo>(); - final ArrayList<MyPermissionInfo> mPersonalPermissions = new ArrayList<MyPermissionInfo>(); - final ArrayList<MyPermissionInfo> mDevicePermissions = new ArrayList<MyPermissionInfo>(); final ArrayList<MyPermissionInfo> mAllPermissions = new ArrayList<MyPermissionInfo>(); MyPermissionGroupInfo(PermissionInfo perm) { @@ -352,13 +349,6 @@ public class AppSecurityPermissions { } for (int i=0; i<strList.length; i++) { String permName = strList[i]; - // If we are only looking at an existing app, then we only - // care about permissions that have actually been granted to it. - if (installedPkgInfo != null && info != installedPkgInfo) { - if ((flagsList[i]&PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) { - continue; - } - } try { PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0); if (tmpPermInfo == null) { @@ -431,10 +421,6 @@ public class AppSecurityPermissions { private List<MyPermissionInfo> getPermissionList(MyPermissionGroupInfo grp, int which) { if (which == WHICH_NEW) { return grp.mNewPermissions; - } else if (which == WHICH_PERSONAL) { - return grp.mPersonalPermissions; - } else if (which == WHICH_DEVICE) { - return grp.mDevicePermissions; } else { return grp.mAllPermissions; } @@ -577,15 +563,8 @@ public class AppSecurityPermissions { private static class PermissionGroupInfoComparator implements Comparator<MyPermissionGroupInfo> { private final Collator sCollator = Collator.getInstance(); - PermissionGroupInfoComparator() { - } + @Override public final int compare(MyPermissionGroupInfo a, MyPermissionGroupInfo b) { - if (((a.flags^b.flags)&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) { - return ((a.flags&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) ? -1 : 1; - } - if (a.priority != b.priority) { - return a.priority > b.priority ? -1 : 1; - } return sCollator.compare(a.mLabel, b.mLabel); } } @@ -628,11 +607,6 @@ public class AppSecurityPermissions { if (pInfo.mNew) { addPermToList(group.mNewPermissions, pInfo); } - if ((group.flags&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) { - addPermToList(group.mPersonalPermissions, pInfo); - } else { - addPermToList(group.mDevicePermissions, pInfo); - } } } } @@ -652,12 +626,5 @@ public class AppSecurityPermissions { mPermGroupsList.add(pgrp); } Collections.sort(mPermGroupsList, mPermGroupComparator); - if (localLOGV) { - for (MyPermissionGroupInfo grp : mPermGroupsList) { - Log.i(TAG, "Group " + grp.name + " personal=" - + ((grp.flags&PermissionGroupInfo.FLAG_PERSONAL_INFO) != 0) - + " priority=" + grp.priority); - } - } } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 96e033a..d897f49 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -16,6 +16,12 @@ package android.widget; +import java.text.BreakIterator; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + import android.R; import android.annotation.Nullable; import android.app.PendingIntent; @@ -106,12 +112,6 @@ import com.android.internal.util.GrowingArrayUtils; import com.android.internal.util.Preconditions; import com.android.internal.widget.EditableInputConnection; -import java.text.BreakIterator; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; - /** * Helper class used by TextView to handle editable text views. @@ -127,6 +127,7 @@ public class Editor { private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20; private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f; private static final int UNSET_X_VALUE = -1; + private static final int UNSET_LINE = -1; // Tag used when the Editor maintains its own separate UndoManager. private static final String UNDO_OWNER_TAG = "Editor"; @@ -3510,7 +3511,11 @@ public class Editor { // Minimum touch target size for handles private int mMinSize; // Indicates the line of text that the handle is on. - protected int mPrevLine = -1; + protected int mPrevLine = UNSET_LINE; + // Indicates the line of text that the user was touching. This can differ from mPrevLine + // when selecting text when the handles jump to the end / start of words which may be on + // a different line. + protected int mPreviousLineTouched = UNSET_LINE; public HandleView(Drawable drawableLtr, Drawable drawableRtl) { super(mTextView.getContext()); @@ -3801,6 +3806,7 @@ public class Editor { mLastParentX = positionListener.getPositionX(); mLastParentY = positionListener.getPositionY(); mIsDragging = true; + mPreviousLineTouched = UNSET_LINE; break; } @@ -4015,8 +4021,12 @@ public class Editor { Layout layout = mTextView.getLayout(); int offset; if (layout != null) { - int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + if (mPreviousLineTouched == UNSET_LINE) { + mPreviousLineTouched = mTextView.getLineAtCoordinate(y); + } + int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y); offset = mTextView.getOffsetAtCoordinate(currLine, x); + mPreviousLineTouched = currLine; } else { offset = mTextView.getOffsetForPosition(x, y); } @@ -4092,9 +4102,13 @@ public class Editor { return; } + if (mPreviousLineTouched == UNSET_LINE) { + mPreviousLineTouched = mTextView.getLineAtCoordinate(y); + } + boolean positionCursor = false; final int selectionEnd = mTextView.getSelectionEnd(); - int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y); int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); if (initialOffset >= selectionEnd) { @@ -4138,9 +4152,9 @@ public class Editor { } else { final float xDiff = x - mPrevX; if (atRtl) { - isExpanding = xDiff > 0 || currLine > mPrevLine; + isExpanding = xDiff > 0 || currLine > mPreviousLineTouched; } else { - isExpanding = xDiff < 0 || currLine < mPrevLine; + isExpanding = xDiff < 0 || currLine < mPreviousLineTouched; } } @@ -4204,6 +4218,7 @@ public class Editor { offset = getNextCursorOffset(selectionEnd, false); mTouchWordDelta = 0.0f; } + mPreviousLineTouched = currLine; positionAtCursorOffset(offset, false); } mPrevX = x; @@ -4218,8 +4233,9 @@ public class Editor { @Override public boolean onTouchEvent(MotionEvent event) { boolean superResult = super.onTouchEvent(event); - if (event.getActionMasked() == MotionEvent.ACTION_UP) { - // Reset the touch word offset when the user has lifted their finger. + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + // Reset the touch word offset and x value when the user + // re-engages the handle. mTouchWordDelta = 0.0f; mPrevX = UNSET_X_VALUE; } @@ -4280,9 +4296,13 @@ public class Editor { return; } + if (mPreviousLineTouched == UNSET_LINE) { + mPreviousLineTouched = mTextView.getLineAtCoordinate(y); + } + boolean positionCursor = false; final int selectionStart = mTextView.getSelectionStart(); - int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + int currLine = getCurrentLineAdjustedForSlop(layout, mPreviousLineTouched, y); int initialOffset = mTextView.getOffsetAtCoordinate(currLine, x); if (initialOffset <= selectionStart) { @@ -4326,9 +4346,9 @@ public class Editor { } else { final float xDiff = x - mPrevX; if (atRtl) { - isExpanding = xDiff < 0 || currLine < mPrevLine; + isExpanding = xDiff < 0 || currLine < mPreviousLineTouched; } else { - isExpanding = xDiff > 0 || currLine > mPrevLine; + isExpanding = xDiff > 0 || currLine > mPreviousLineTouched; } } @@ -4392,6 +4412,7 @@ public class Editor { offset = getNextCursorOffset(selectionStart, true); mTouchWordDelta = 0.0f; } + mPreviousLineTouched = currLine; positionAtCursorOffset(offset, false); } mPrevX = x; @@ -4406,8 +4427,9 @@ public class Editor { @Override public boolean onTouchEvent(MotionEvent event) { boolean superResult = super.onTouchEvent(event); - if (event.getActionMasked() == MotionEvent.ACTION_UP) { - // Reset the touch word offset when the user has lifted their finger. + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + // Reset the touch word offset and x value when the user + // re-engages the handle. mTouchWordDelta = 0.0f; mPrevX = UNSET_X_VALUE; } @@ -4416,10 +4438,16 @@ public class Editor { } private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) { + final int trueLine = mTextView.getLineAtCoordinate(y); if (layout == null || prevLine > layout.getLineCount() || layout.getLineCount() <= 0 || prevLine < 0) { // Invalid parameters, just return whatever line is at y. - return mTextView.getLineAtCoordinate(y); + return trueLine; + } + + if (Math.abs(trueLine - prevLine) >= 2) { + // Only stick to lines if we're within a line of the previous selection. + return trueLine; } final float verticalOffset = mTextView.viewportToContentVerticalOffset(); diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index a1e6cc8..e13b96f 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -91,6 +91,7 @@ public class ImageView extends View { private boolean mColorMod = false; private Drawable mDrawable = null; + private ImageViewBitmapDrawable mRecycleableBitmapDrawable = null; private ColorStateList mDrawableTintList = null; private PorterDuff.Mode mDrawableTintMode = null; private boolean mHasDrawableTint = false; @@ -588,18 +589,16 @@ public class ImageView extends View { */ @android.view.RemotableViewMethod public void setImageBitmap(Bitmap bm) { - // if this is used frequently, may handle bitmaps explicitly - // to reduce the intermediate drawable object - if (mDrawable instanceof ImageViewBitmapDrawable) { - ImageViewBitmapDrawable recycledDrawable = (ImageViewBitmapDrawable) mDrawable; - // Hacky fix to force setImageDrawable to do a full setImageDrawable - // instead of doing an object reference comparison - mDrawable = null; - recycledDrawable.setBitmap(bm); - setImageDrawable(recycledDrawable); + // Hacky fix to force setImageDrawable to do a full setImageDrawable + // instead of doing an object reference comparison + mDrawable = null; + if (mRecycleableBitmapDrawable == null) { + mRecycleableBitmapDrawable = new ImageViewBitmapDrawable( + mContext.getResources(), bm); } else { - setImageDrawable(new ImageViewBitmapDrawable(mContext.getResources(), bm)); + mRecycleableBitmapDrawable.setBitmap(bm); } + setImageDrawable(mRecycleableBitmapDrawable); } public void setImageState(int[] state, boolean merge) { @@ -868,6 +867,10 @@ public class ImageView extends View { } private void updateDrawable(Drawable d) { + if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) { + mRecycleableBitmapDrawable.setBitmap(null); + } + if (mDrawable != null) { mDrawable.setCallback(null); unscheduleDrawable(mDrawable); diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java index 8c6b79b..7278d5c 100644 --- a/core/java/com/android/internal/logging/MetricsConstants.java +++ b/core/java/com/android/internal/logging/MetricsConstants.java @@ -22,6 +22,7 @@ package com.android.internal.logging; */ public interface MetricsConstants { // These constants must match those in the analytic pipeline, do not edit. + // Add temporary values to the top of MetricsLogger instead. public static final int VIEW_UNKNOWN = 0; public static final int MAIN_SETTINGS = 1; public static final int ACCESSIBILITY = 2; @@ -229,6 +230,29 @@ public interface MetricsConstants { public static final int ACTION_NOTE_CONTROLS = 204; public static final int ACTION_NOTE_INFO = 205; public static final int ACTION_APP_NOTE_SETTINGS = 206; + public static final int VOLUME_DIALOG = 207; + public static final int VOLUME_DIALOG_DETAILS = 208; + public static final int ACTION_VOLUME_SLIDER = 209; + public static final int ACTION_VOLUME_STREAM = 210; + public static final int ACTION_VOLUME_KEY = 211; + public static final int ACTION_VOLUME_ICON = 212; + public static final int ACTION_RINGER_MODE = 213; + public static final int ACTION_ACTIVITY_CHOOSER_SHOWN = 214; + public static final int ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215; + public static final int ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216; + public static final int ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217; + public static final int ACTION_BRIGHTNESS = 218; + public static final int ACTION_BRIGHTNESS_AUTO = 219; + public static final int BRIGHTNESS_DIALOG = 220; + public static final int SYSTEM_ALERT_WINDOW_APPS = 221; + public static final int DREAMING = 222; + public static final int DOZING = 223; + public static final int OVERVIEW_ACTIVITY = 224; + public static final int ABOUT_LEGAL_SETTINGS = 225; + public static final int ACTION_SEARCH_RESULTS = 226; + + // These constants must match those in the analytic pipeline, do not edit. + // Add temporary values to the top of MetricsLogger instead. //aliases public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY; diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 66fa8fc..cbe535f 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -26,25 +26,8 @@ import android.view.View; * @hide */ public class MetricsLogger implements MetricsConstants { - public static final int VOLUME_DIALOG = 207; - public static final int VOLUME_DIALOG_DETAILS = 208; - public static final int ACTION_VOLUME_SLIDER = 209; - public static final int ACTION_VOLUME_STREAM = 210; - public static final int ACTION_VOLUME_KEY = 211; - public static final int ACTION_VOLUME_ICON = 212; - public static final int ACTION_RINGER_MODE = 213; - public static final int ACTION_ACTIVITY_CHOOSER_SHOWN = 214; - public static final int ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215; - public static final int ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216; - public static final int ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217; - public static final int ACTION_BRIGHTNESS = 218; - public static final int ACTION_BRIGHTNESS_AUTO = 219; - public static final int BRIGHTNESS_DIALOG = 220; - public static final int SYSTEM_ALERT_WINDOW_APPS = 221; - public static final int DREAMING = 222; - public static final int DOZING = 223; - public static final int OVERVIEW_ACTIVITY = 224; // Temporary constants go here, to await migration to MetricsConstants. + // next value is 227; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java b/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java deleted file mode 100644 index 0a01ae9..0000000 --- a/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.android.internal.os.storage; - -import android.app.ProgressDialog; -import android.app.Service; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.os.PowerManager; -import android.os.storage.StorageManager; -import android.os.storage.StorageVolume; -import android.util.Slog; -import android.view.WindowManager; -import android.widget.Toast; - -import com.android.internal.R; - -/** - * Takes care of unmounting and formatting external storage. - * - * @deprecated Please use {@link Intent#ACTION_MASTER_CLEAR} broadcast with extra - * {@link Intent#EXTRA_WIPE_EXTERNAL_STORAGE} to wipe and factory reset, or call - * {@link StorageManager#wipeAdoptableDisks} directly to format external storages. - */ -public class ExternalStorageFormatter extends Service { - static final String TAG = "ExternalStorageFormatter"; - - public static final String FORMAT_ONLY = "com.android.internal.os.storage.FORMAT_ONLY"; - public static final String FORMAT_AND_FACTORY_RESET = "com.android.internal.os.storage.FORMAT_AND_FACTORY_RESET"; - - public static final String EXTRA_ALWAYS_RESET = "always_reset"; - - public static final ComponentName COMPONENT_NAME - = new ComponentName("android", ExternalStorageFormatter.class.getName()); - - private StorageManager mStorageManager; - - private PowerManager.WakeLock mWakeLock; - - private ProgressDialog mProgressDialog = null; - - private boolean mFactoryReset = false; - private boolean mAlwaysReset = false; - private String mReason = null; - - @Override - public void onCreate() { - super.onCreate(); - - mStorageManager = getSystemService(StorageManager.class); - - mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE)) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExternalStorageFormatter"); - mWakeLock.acquire(); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (FORMAT_AND_FACTORY_RESET.equals(intent.getAction())) { - mFactoryReset = true; - } - if (intent.getBooleanExtra(EXTRA_ALWAYS_RESET, false)) { - mAlwaysReset = true; - } - - mReason = intent.getStringExtra(Intent.EXTRA_REASON); - StorageVolume userVol = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME); - if (userVol == null) { - Slog.w(TAG, "Missing explicit storage volume; assuming default"); - userVol = mStorageManager.getPrimaryVolume(); - } - - final String volumeId = userVol.getId(); - - mProgressDialog = new ProgressDialog(this); - mProgressDialog.setIndeterminate(true); - mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - mProgressDialog.setMessage(getText(R.string.progress_unmounting)); - mProgressDialog.show(); - - new FormatTask(volumeId).start(); - - return Service.START_REDELIVER_INTENT; - } - - private class FormatTask extends Thread { - private final String mVolumeId; - - public FormatTask(String volumeId) { - mVolumeId = volumeId; - } - - @Override - public void run() { - boolean success = false; - try { - mStorageManager.format(mVolumeId); - success = true; - } catch (Exception e) { - Slog.w(TAG, "Failed to format", e); - Toast.makeText(ExternalStorageFormatter.this, - R.string.format_error, Toast.LENGTH_LONG).show(); - } - if (success) { - if (mFactoryReset) { - Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - intent.putExtra(Intent.EXTRA_REASON, mReason); - sendBroadcast(intent); - // Intent handling is asynchronous -- assume it will happen soon. - stopSelf(); - return; - } - } - // If we didn't succeed, or aren't doing a full factory - // reset, then it is time to remount the storage. - if (!success && mAlwaysReset) { - Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - intent.putExtra(Intent.EXTRA_REASON, mReason); - sendBroadcast(intent); - } else { - try { - mStorageManager.mount(mVolumeId); - } catch (Exception e) { - Slog.w(TAG, "Failed to mount", e); - } - } - stopSelf(); - } - } - - @Override - public void onDestroy() { - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - } - mWakeLock.release(); - super.onDestroy(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } -} |
