summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityThread.java102
-rw-r--r--core/java/android/app/SystemServiceRegistry.java4
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java34
-rw-r--r--core/java/android/content/Intent.java21
-rw-r--r--core/java/android/content/RestrictionEntry.java177
-rw-r--r--core/java/android/content/RestrictionsManager.java130
-rw-r--r--core/java/android/hardware/ICameraService.aidl7
-rw-r--r--core/java/android/hardware/fingerprint/Fingerprint.aidl (renamed from core/java/android/service/fingerprint/Fingerprint.aidl)2
-rw-r--r--core/java/android/hardware/fingerprint/Fingerprint.java (renamed from core/java/android/service/fingerprint/Fingerprint.java)2
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java (renamed from core/java/android/service/fingerprint/FingerprintManager.java)4
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintUtils.java (renamed from core/java/android/service/fingerprint/FingerprintUtils.java)2
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl (renamed from core/java/android/service/fingerprint/IFingerprintService.aidl)6
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl (renamed from core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl)2
-rw-r--r--core/java/android/net/Uri.java12
-rw-r--r--core/java/android/os/BatteryStats.java10
-rw-r--r--core/java/android/provider/CallLog.java8
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java7
-rw-r--r--core/java/android/text/DynamicLayout.java13
-rw-r--r--core/java/android/text/Layout.java28
-rw-r--r--core/java/android/text/StaticLayout.java91
-rw-r--r--core/java/android/view/ViewGroup.java4
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java2
-rw-r--r--core/java/android/widget/DayPickerView.java4
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java6
-rw-r--r--core/java/android/widget/SimpleMonthView.java94
-rw-r--r--core/java/android/widget/TextView.java116
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java14
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java2
29 files changed, 654 insertions, 258 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4880db1..81b1583 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -254,18 +254,21 @@ public final class ActivityThread {
}
}
+ static final class AcquiringProviderRecord {
+ IActivityManager.ContentProviderHolder holder;
+ boolean acquiring = true;
+ int requests = 1;
+ }
+
// The lock of mProviderMap protects the following variables.
- final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
- = new ArrayMap<ProviderKey, ProviderClientRecord>();
- final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
- = new ArrayMap<IBinder, ProviderRefCount>();
- final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
- = new ArrayMap<IBinder, ProviderClientRecord>();
- final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
- = new ArrayMap<ComponentName, ProviderClientRecord>();
+ final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>();
+ final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>();
+ final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>();
+ final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>();
+ final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
- = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
+ = new ArrayMap<>();
final GcIdler mGcIdler = new GcIdler();
boolean mGcIdlerScheduled = false;
@@ -345,7 +348,7 @@ public final class ActivityThread {
}
}
- final class ProviderClientRecord {
+ static final class ProviderClientRecord {
final String[] mNames;
final IContentProvider mProvider;
final ContentProvider mLocalProvider;
@@ -4693,22 +4696,57 @@ public final class ActivityThread {
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
- final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
+ final ProviderKey key = new ProviderKey(auth, userId);
+ final IContentProvider provider = acquireExistingProvider(c, key, stable);
if (provider != null) {
return provider;
}
+ AcquiringProviderRecord r;
+ boolean first = false;
+ synchronized (mAcquiringProviderMap) {
+ r = mAcquiringProviderMap.get(key);
+ if (r == null) {
+ r = new AcquiringProviderRecord();
+ mAcquiringProviderMap.put(key, r);
+ first = true;
+ } else {
+ r.requests++;
+ }
+ }
- // There is a possible race here. Another thread may try to acquire
- // the same provider at the same time. When this happens, we want to ensure
- // that the first one wins.
- // Note that we cannot hold the lock while acquiring and installing the
- // provider since it might take a long time to run and it could also potentially
- // be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
- try {
- holder = ActivityManagerNative.getDefault().getContentProvider(
- getApplicationThread(), auth, userId, stable);
- } catch (RemoteException ex) {
+ if (first) {
+ // Multiple threads may try to acquire the same provider at the same time.
+ // When this happens, we only let the first one really gets provider.
+ // Other threads just wait for its result.
+ // Note that we cannot hold the lock while acquiring and installing the
+ // provider since it might take a long time to run and it could also potentially
+ // be re-entrant in the case where the provider is in the same process.
+ try {
+ holder = ActivityManagerNative.getDefault().getContentProvider(
+ getApplicationThread(), auth, userId, stable);
+ } catch (RemoteException ex) {
+ }
+ synchronized (r) {
+ r.holder = holder;
+ r.acquiring = false;
+ r.notifyAll();
+ }
+ } else {
+ synchronized (r) {
+ while (r.acquiring) {
+ try {
+ r.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ holder = r.holder;
+ }
+ }
+ synchronized (mAcquiringProviderMap) {
+ if (--r.requests == 0) {
+ mAcquiringProviderMap.remove(key);
+ }
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -4792,8 +4830,12 @@ public final class ActivityThread {
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
+ return acquireExistingProvider(c, new ProviderKey(auth, userId), stable);
+ }
+
+ final IContentProvider acquireExistingProvider(
+ Context c, ProviderKey key, boolean stable) {
synchronized (mProviderMap) {
- final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
@@ -4804,7 +4846,7 @@ public final class ActivityThread {
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
- Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ Log.i(TAG, "Acquiring provider " + key.authority + " for user " + key.userId
+ ": existing object's process dead");
handleUnstableProviderDiedLocked(jBinder, true);
return null;
@@ -5126,18 +5168,12 @@ public final class ActivityThread {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
- // We need to transfer our new reference to the existing
- // ref count, releasing the old one... but only if
- // release is needed (that is, it is not running in the
- // system process).
+ // The provider has already been installed, so we need
+ // to increase reference count to the existing one, but
+ // only if release is needed (that is, it is not running
+ // in the system process or local to the process).
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
- try {
- ActivityManagerNative.getDefault().removeContentProvider(
- holder.connection, stable);
- } catch (RemoteException e) {
- //do nothing content provider object is dead any way
- }
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index a0f40f6..b3aa6be 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -99,8 +99,8 @@ import android.os.Vibrator;
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
-import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
import android.service.persistentdata.IPersistentDataBlockService;
import android.service.persistentdata.PersistentDataBlockManager;
import android.telecom.TelecomManager;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index be26eac..edb768d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -18,6 +18,7 @@ package android.bluetooth;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
@@ -206,6 +207,23 @@ public final class BluetoothAdapter {
"android.bluetooth.adapter.action.REQUEST_ENABLE";
/**
+ * Activity Action: Show a system activity that allows user to enable BLE scans even when
+ * Bluetooth is turned off.<p>
+ *
+ * Notification of result of this activity is posted using
+ * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
+ * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
+ * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
+ * error occurred.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
+ "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+
+ /**
* Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
* has changed.
* <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
@@ -916,6 +934,22 @@ public final class BluetoothAdapter {
}
/**
+ * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
+ *
+ * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
+ * fetch scan results even when Bluetooth is turned off.<p>
+ *
+ * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isBleScanAlwaysAvailable() {
+ // TODO: implement after Settings UI change.
+ return false;
+ }
+
+ /**
* Returns whether peripheral mode is supported.
*
* @hide
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7a99a79..514802e9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1041,6 +1041,18 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
/**
+ * Activity action: Activate the current SIM card. If SIM cards do not require activation,
+ * sending this intent is a no-op.
+ * <p>Input: No data should be specified. get*Extra may have an optional
+ * {@link #EXTRA_SIM_ACTIVATION_RESPONSE} field containing a PendingIntent through which to
+ * send the activation result.
+ * <p>Output: nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SIM_ACTIVATION_REQUEST =
+ "android.intent.action.SIM_ACTIVATION_REQUEST";
+ /**
* Activity Action: Send a message to someone specified by the data.
* <p>Input: {@link #getData} is URI describing the target.
* <p>Output: nothing.
@@ -3620,6 +3632,15 @@ public class Intent implements Parcelable, Cloneable {
/** {@hide} */
public static final String EXTRA_REASON = "android.intent.extra.REASON";
+ /**
+ * Optional {@link android.app.PendingIntent} extra used to deliver the result of the SIM
+ * activation request.
+ * TODO: Add information about the structure and response data used with the pending intent.
+ * @hide
+ */
+ public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
+ "android.intent.extra.SIM_ACTIVATION_RESPONSE";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index 6d79626..342ee38 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -20,6 +20,9 @@ import android.annotation.ArrayRes;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* Applications can expose restrictions for a restricted user on a
* multiuser device. The administrator can configure these restrictions that will then be
@@ -33,19 +36,19 @@ import android.os.Parcelable;
public class RestrictionEntry implements Parcelable {
/**
- * A type of restriction. Use this type for information that needs to be transferred across
- * but shouldn't be presented to the user in the UI. Stores a single String value.
+ * Hidden restriction type. Use this type for information that needs to be transferred
+ * across but shouldn't be presented to the user in the UI. Stores a single String value.
*/
public static final int TYPE_NULL = 0;
/**
- * A type of restriction. Use this for storing a boolean value, typically presented as
+ * Restriction of type "bool". Use this for storing a boolean value, typically presented as
* a checkbox in the UI.
*/
public static final int TYPE_BOOLEAN = 1;
/**
- * A type of restriction. Use this for storing a string value, typically presented as
+ * Restriction of type "choice". Use this for storing a string value, typically presented as
* a single-select list. Call {@link #setChoiceEntries(String[])} and
* {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
* and the corresponding values, respectively.
@@ -53,7 +56,7 @@ public class RestrictionEntry implements Parcelable {
public static final int TYPE_CHOICE = 2;
/**
- * A type of restriction. Use this for storing a string value, typically presented as
+ * Internal restriction type. Use this for storing a string value, typically presented as
* a single-select list. Call {@link #setChoiceEntries(String[])} and
* {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
* and the corresponding values, respectively.
@@ -64,8 +67,8 @@ public class RestrictionEntry implements Parcelable {
public static final int TYPE_CHOICE_LEVEL = 3;
/**
- * A type of restriction. Use this for presenting a multi-select list where more than one
- * entry can be selected, such as for choosing specific titles to white-list.
+ * Restriction of type "multi-select". Use this for presenting a multi-select list where more
+ * than one entry can be selected, such as for choosing specific titles to white-list.
* Call {@link #setChoiceEntries(String[])} and
* {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
* and the corresponding values, respectively.
@@ -75,18 +78,30 @@ public class RestrictionEntry implements Parcelable {
public static final int TYPE_MULTI_SELECT = 4;
/**
- * A type of restriction. Use this for storing an integer value. The range of values
+ * Restriction of type "integer". Use this for storing an integer value. The range of values
* is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}.
*/
public static final int TYPE_INTEGER = 5;
/**
- * A type of restriction. Use this for storing a string value.
+ * Restriction of type "string". Use this for storing a string value.
* @see #setSelectedString
* @see #getSelectedString
*/
public static final int TYPE_STRING = 6;
+ /**
+ * Restriction of type "bundle". Use this for storing {@link android.os.Bundle bundles} of
+ * restrictions
+ */
+ public static final int TYPE_BUNDLE = 7;
+
+ /**
+ * Restriction of type "bundle_array". Use this for storing arrays of
+ * {@link android.os.Bundle bundles} of restrictions
+ */
+ public static final int TYPE_BUNDLE_ARRAY = 8;
+
/** The type of restriction. */
private int mType;
@@ -100,13 +115,13 @@ public class RestrictionEntry implements Parcelable {
private String mDescription;
/** The user-visible set of choices used for single-select and multi-select lists. */
- private String [] mChoiceEntries;
+ private String[] mChoiceEntries;
/** The values corresponding to the user-visible choices. The value(s) of this entry will
* one or more of these, returned by {@link #getAllSelectedStrings()} and
* {@link #getSelectedString()}.
*/
- private String [] mChoiceValues;
+ private String[] mChoiceValues;
/* The chosen value, whose content depends on the type of the restriction. */
private String mCurrentValue;
@@ -115,6 +130,12 @@ public class RestrictionEntry implements Parcelable {
private String[] mCurrentValues;
/**
+ * List of nested restrictions. Used by {@link #TYPE_BUNDLE bundle} and
+ * {@link #TYPE_BUNDLE_ARRAY bundle_array} restrictions.
+ */
+ private RestrictionEntry[] mRestrictions;
+
+ /**
* Constructor for specifying the type and key, with no initial value;
*
* @param type the restriction type.
@@ -170,6 +191,35 @@ public class RestrictionEntry implements Parcelable {
}
/**
+ * Constructor for {@link #TYPE_BUNDLE}/{@link #TYPE_BUNDLE_ARRAY} type.
+ * @param key the unique key for this restriction
+ * @param restrictionEntries array of nested restriction entries. If the entry, being created
+ * represents a {@link #TYPE_BUNDLE_ARRAY bundle-array}, {@code restrictionEntries} array may
+ * only contain elements of type {@link #TYPE_BUNDLE bundle}.
+ * @param isBundleArray true if this restriction represents
+ * {@link #TYPE_BUNDLE_ARRAY bundle-array} type, otherwise the type will be set to
+ * {@link #TYPE_BUNDLE bundle}.
+ */
+ public RestrictionEntry(String key, RestrictionEntry[] restrictionEntries,
+ boolean isBundleArray) {
+ mKey = key;
+ if (isBundleArray) {
+ mType = TYPE_BUNDLE_ARRAY;
+ if (restrictionEntries != null) {
+ for (RestrictionEntry restriction : restrictionEntries) {
+ if (restriction.getType() != TYPE_BUNDLE) {
+ throw new IllegalArgumentException("bundle_array restriction can only have "
+ + "nested restriction entries of type bundle");
+ }
+ }
+ }
+ } else {
+ mType = TYPE_BUNDLE;
+ }
+ setRestrictions(restrictionEntries);
+ }
+
+ /**
* Sets the type for this restriction.
* @param type the type for this restriction.
*/
@@ -283,6 +333,22 @@ public class RestrictionEntry implements Parcelable {
}
/**
+ * Returns array of possible restriction entries that this entry may contain.
+ */
+ public RestrictionEntry[] getRestrictions() {
+ return mRestrictions;
+ }
+
+ /**
+ * Sets an array of possible restriction entries, that this entry may contain.
+ * <p>This method is only relevant for types {@link #TYPE_BUNDLE} and
+ * {@link #TYPE_BUNDLE_ARRAY}
+ */
+ public void setRestrictions(RestrictionEntry[] restrictions) {
+ mRestrictions = restrictions;
+ }
+
+ /**
* Returns the list of possible string values set earlier.
* @return the list of possible values.
*/
@@ -362,27 +428,30 @@ public class RestrictionEntry implements Parcelable {
this.mTitle = title;
}
- private boolean equalArrays(String[] one, String[] other) {
- if (one.length != other.length) return false;
- for (int i = 0; i < one.length; i++) {
- if (!one[i].equals(other[i])) return false;
- }
- return true;
- }
-
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof RestrictionEntry)) return false;
final RestrictionEntry other = (RestrictionEntry) o;
- // Make sure that either currentValue matches or currentValues matches.
- return mType == other.mType && mKey.equals(other.mKey)
- &&
- ((mCurrentValues == null && other.mCurrentValues == null
- && mCurrentValue != null && mCurrentValue.equals(other.mCurrentValue))
- ||
- (mCurrentValue == null && other.mCurrentValue == null
- && mCurrentValues != null && equalArrays(mCurrentValues, other.mCurrentValues)));
+ if (mType != other.mType || mKey.equals(other.mKey)) {
+ return false;
+ }
+ if (mCurrentValues == null && other.mCurrentValues == null
+ && mRestrictions == null && other.mRestrictions == null
+ && Objects.equals(mCurrentValue, other.mCurrentValue)) {
+ return true;
+ }
+ if (mCurrentValue == null && other.mCurrentValue == null
+ && mRestrictions == null && other.mRestrictions == null
+ && Arrays.equals(mCurrentValues, other.mCurrentValues)) {
+ return true;
+ }
+ if (mCurrentValue == null && other.mCurrentValue == null
+ && mCurrentValue == null && other.mCurrentValue == null
+ && Arrays.equals(mRestrictions, other.mRestrictions)) {
+ return true;
+ }
+ return false;
}
@Override
@@ -397,28 +466,28 @@ public class RestrictionEntry implements Parcelable {
result = 31 * result + value.hashCode();
}
}
+ } else if (mRestrictions != null) {
+ result = 31 * result + Arrays.hashCode(mRestrictions);
}
return result;
}
- private String[] readArray(Parcel in) {
- int count = in.readInt();
- String[] values = new String[count];
- for (int i = 0; i < count; i++) {
- values[i] = in.readString();
- }
- return values;
- }
-
public RestrictionEntry(Parcel in) {
mType = in.readInt();
mKey = in.readString();
mTitle = in.readString();
mDescription = in.readString();
- mChoiceEntries = readArray(in);
- mChoiceValues = readArray(in);
+ mChoiceEntries = in.readStringArray();
+ mChoiceValues = in.readStringArray();
mCurrentValue = in.readString();
- mCurrentValues = readArray(in);
+ mCurrentValues = in.readStringArray();
+ Parcelable[] parcelables = in.readParcelableArray(null);
+ if (parcelables != null) {
+ mRestrictions = new RestrictionEntry[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ mRestrictions[i] = (RestrictionEntry) parcelables[i];
+ }
+ }
}
@Override
@@ -426,27 +495,17 @@ public class RestrictionEntry implements Parcelable {
return 0;
}
- private void writeArray(Parcel dest, String[] values) {
- if (values == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(values.length);
- for (int i = 0; i < values.length; i++) {
- dest.writeString(values[i]);
- }
- }
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeString(mKey);
dest.writeString(mTitle);
dest.writeString(mDescription);
- writeArray(dest, mChoiceEntries);
- writeArray(dest, mChoiceValues);
+ dest.writeStringArray(mChoiceEntries);
+ dest.writeStringArray(mChoiceValues);
dest.writeString(mCurrentValue);
- writeArray(dest, mCurrentValues);
+ dest.writeStringArray(mCurrentValues);
+ dest.writeParcelableArray(mRestrictions, 0);
}
public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() {
@@ -461,6 +520,16 @@ public class RestrictionEntry implements Parcelable {
@Override
public String toString() {
- return "RestrictionsEntry {type=" + mType + ", key=" + mKey + ", value=" + mCurrentValue + "}";
+ return "RestrictionEntry{" +
+ "mType=" + mType +
+ ", mKey='" + mKey + '\'' +
+ ", mTitle='" + mTitle + '\'' +
+ ", mDescription='" + mDescription + '\'' +
+ ", mChoiceEntries=" + Arrays.toString(mChoiceEntries) +
+ ", mChoiceValues=" + Arrays.toString(mChoiceValues) +
+ ", mCurrentValue='" + mCurrentValue + '\'' +
+ ", mCurrentValues=" + Arrays.toString(mCurrentValues) +
+ ", mRestrictions=" + Arrays.toString(mRestrictions) +
+ '}';
}
}
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 21a6a0d..1fac06e 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -32,12 +32,14 @@ import android.util.Log;
import android.util.Xml;
import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -71,12 +73,15 @@ import java.util.List;
* android:key="string"
* android:title="string resource"
* android:restrictionType=["bool" | "string" | "integer"
- * | "choice" | "multi-select" | "hidden"]
+ * | "choice" | "multi-select" | "hidden"
+ * | "bundle" | "bundle_array"]
* android:description="string resource"
* android:entries="string-array resource"
* android:entryValues="string-array resource"
- * android:defaultValue="reference"
- * /&gt;
+ * android:defaultValue="reference" &gt;
+ * &lt;restriction ... /&gt;
+ * ...
+ * &lt;/restriction&gt;
* &lt;restriction ... /&gt;
* ...
* &lt;/restrictions&gt;
@@ -97,6 +102,9 @@ import java.util.List;
* administrator controlling the values, if the title is not sufficient.</li>
* </ul>
* <p>
+ * Only restrictions of type {@code bundle} and {@code bundle_array} can have one or multiple nested
+ * restriction elements.
+ * <p>
* In your manifest's <code>application</code> section, add the meta-data tag to point to
* the restrictions XML file as shown below:
* <pre>
@@ -537,9 +545,7 @@ public class RestrictionsManager {
XmlResourceParser xml =
appInfo.loadXmlMetaData(mContext.getPackageManager(), META_DATA_APP_RESTRICTIONS);
- List<RestrictionEntry> restrictions = loadManifestRestrictions(packageName, xml);
-
- return restrictions;
+ return loadManifestRestrictions(packageName, xml);
}
private List<RestrictionEntry> loadManifestRestrictions(String packageName,
@@ -550,23 +556,16 @@ public class RestrictionsManager {
} catch (NameNotFoundException nnfe) {
return null;
}
- ArrayList<RestrictionEntry> restrictions = new ArrayList<RestrictionEntry>();
+ ArrayList<RestrictionEntry> restrictions = new ArrayList<>();
RestrictionEntry restriction;
try {
int tagType = xml.next();
while (tagType != XmlPullParser.END_DOCUMENT) {
if (tagType == XmlPullParser.START_TAG) {
- if (xml.getName().equals(TAG_RESTRICTION)) {
- AttributeSet attrSet = Xml.asAttributeSet(xml);
- if (attrSet != null) {
- TypedArray a = appContext.obtainStyledAttributes(attrSet,
- com.android.internal.R.styleable.RestrictionEntry);
- restriction = loadRestriction(appContext, a);
- if (restriction != null) {
- restrictions.add(restriction);
- }
- }
+ restriction = loadRestrictionElement(appContext, xml);
+ if (restriction != null) {
+ restrictions.add(restriction);
}
}
tagType = xml.next();
@@ -582,7 +581,21 @@ public class RestrictionsManager {
return restrictions;
}
- private RestrictionEntry loadRestriction(Context appContext, TypedArray a) {
+ private RestrictionEntry loadRestrictionElement(Context appContext, XmlResourceParser xml)
+ throws IOException, XmlPullParserException {
+ if (xml.getName().equals(TAG_RESTRICTION)) {
+ AttributeSet attrSet = Xml.asAttributeSet(xml);
+ if (attrSet != null) {
+ TypedArray a = appContext.obtainStyledAttributes(attrSet,
+ com.android.internal.R.styleable.RestrictionEntry);
+ return loadRestriction(appContext, a, xml);
+ }
+ }
+ return null;
+ }
+
+ private RestrictionEntry loadRestriction(Context appContext, TypedArray a, XmlResourceParser xml)
+ throws IOException, XmlPullParserException {
String key = a.getString(R.styleable.RestrictionEntry_key);
int restrictionType = a.getInt(
R.styleable.RestrictionEntry_restrictionType, -1);
@@ -633,9 +646,90 @@ public class RestrictionsManager {
restriction.setSelectedState(
a.getBoolean(R.styleable.RestrictionEntry_defaultValue, false));
break;
+ case RestrictionEntry.TYPE_BUNDLE:
+ case RestrictionEntry.TYPE_BUNDLE_ARRAY:
+ final int outerDepth = xml.getDepth();
+ List<RestrictionEntry> restrictionEntries = new ArrayList<>();
+ while (XmlUtils.nextElementWithin(xml, outerDepth)) {
+ RestrictionEntry childEntry = loadRestrictionElement(appContext, xml);
+ if (childEntry == null) {
+ Log.w(TAG, "Child entry cannot be loaded for bundle restriction " + key);
+ } else {
+ restrictionEntries.add(childEntry);
+ if (restrictionType == RestrictionEntry.TYPE_BUNDLE_ARRAY
+ && childEntry.getType() != RestrictionEntry.TYPE_BUNDLE) {
+ Log.w(TAG, "bundle_array " + key
+ + " can only contain entries of type bundle");
+ }
+ }
+ }
+ restriction.setRestrictions(restrictionEntries.toArray(new RestrictionEntry[
+ restrictionEntries.size()]));
+ break;
default:
Log.w(TAG, "Unknown restriction type " + restrictionType);
}
return restriction;
}
+
+ /**
+ * Converts a list of restrictions to the corresponding bundle, using the following mapping:
+ * <table>
+ * <tr><th>RestrictionEntry</th><th>Bundle</th></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td>
+ * <td>{@link Bundle#putStringArray}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE}</td><td>{@link Bundle#putBundle}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE_ARRAY}</td>
+ * <td>{@link Bundle#putParcelableArray}</td></tr>
+ * </table>
+ * @param entries list of restrictions
+ */
+ public static Bundle convertRestrictionsToBundle(List<RestrictionEntry> entries) {
+ final Bundle bundle = new Bundle();
+ for (RestrictionEntry entry : entries) {
+ addRestrictionToBundle(bundle, entry);
+ }
+ return bundle;
+ }
+
+ private static Bundle addRestrictionToBundle(Bundle bundle, RestrictionEntry entry) {
+ switch (entry.getType()) {
+ case RestrictionEntry.TYPE_BOOLEAN:
+ bundle.putBoolean(entry.getKey(), entry.getSelectedState());
+ break;
+ case RestrictionEntry.TYPE_CHOICE:
+ case RestrictionEntry.TYPE_CHOICE_LEVEL:
+ case RestrictionEntry.TYPE_MULTI_SELECT:
+ bundle.putStringArray(entry.getKey(), entry.getAllSelectedStrings());
+ break;
+ case RestrictionEntry.TYPE_INTEGER:
+ bundle.putInt(entry.getKey(), entry.getIntValue());
+ break;
+ case RestrictionEntry.TYPE_STRING:
+ case RestrictionEntry.TYPE_NULL:
+ bundle.putString(entry.getKey(), entry.getSelectedString());
+ break;
+ case RestrictionEntry.TYPE_BUNDLE:
+ RestrictionEntry[] restrictions = entry.getRestrictions();
+ Bundle childBundle = convertRestrictionsToBundle(Arrays.asList(restrictions));
+ bundle.putBundle(entry.getKey(), childBundle);
+ break;
+ case RestrictionEntry.TYPE_BUNDLE_ARRAY:
+ restrictions = entry.getRestrictions();
+ Bundle[] bundleArray = new Bundle[restrictions.length];
+ for (int i = 0; i < restrictions.length; i++) {
+ bundleArray[i] = addRestrictionToBundle(new Bundle(), restrictions[i]);
+ }
+ bundle.putParcelableArray(entry.getKey(), bundleArray);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported restrictionEntry type: " + entry.getType());
+ }
+ return bundle;
+ }
+
}
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index d5dfaf6..9bc2f46 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -75,4 +75,11 @@ interface ICameraService
out BinderHolder device);
int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
+
+ /**
+ * Notify the camera service of a system event. Should only be called from system_server.
+ *
+ * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
+ */
+ oneway void notifySystemEvent(int eventId, int arg0);
}
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/hardware/fingerprint/Fingerprint.aidl
index c9fd989..4743354 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/core/java/android/hardware/fingerprint/Fingerprint.aidl
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.fingerprint;
+package android.hardware.fingerprint;
// @hide
parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java
index 37552eb..c307634 100644
--- a/core/java/android/service/fingerprint/Fingerprint.java
+++ b/core/java/android/hardware/fingerprint/Fingerprint.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.fingerprint;
+package android.hardware.fingerprint;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index bb90e40..e3572a2 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.service.fingerprint;
+package android.hardware.fingerprint;
import android.app.ActivityManagerNative;
import android.content.ContentResolver;
@@ -28,7 +28,7 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import android.util.Log;
import android.util.Slog;
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/hardware/fingerprint/FingerprintUtils.java
index 62acbb9..ae3d4a4 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/hardware/fingerprint/FingerprintUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.service.fingerprint;
+package android.hardware.fingerprint;
import android.content.ContentResolver;
import android.provider.Settings;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index e5d3ad4..c5a45e2 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.fingerprint;
+package android.hardware.fingerprint;
import android.os.Bundle;
-import android.service.fingerprint.IFingerprintServiceReceiver;
-import android.service.fingerprint.Fingerprint;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.Fingerprint;
import java.util.List;
/**
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index f025064..e82395f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.service.fingerprint;
+package android.hardware.fingerprint;
import android.os.Bundle;
import android.os.UserHandle;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index bf3d9aa..f305b2a 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,7 +366,6 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public String toSafeString() {
String scheme = getScheme();
String ssp = getSchemeSpecificPart();
- String authority = null;
if (scheme != null) {
if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
|| scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -385,9 +384,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
}
return builder.toString();
- } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
- ssp = null;
- authority = "//" + getAuthority() + "/...";
+ } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")
+ || scheme.equalsIgnoreCase("ftp")) {
+ ssp = "//" + ((getHost() != null) ? getHost() : "")
+ + ((getPort() != -1) ? (":" + getPort()) : "")
+ + "/...";
}
}
// Not a sensitive scheme, but let's still be conservative about
@@ -401,9 +402,6 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
if (ssp != null) {
builder.append(ssp);
}
- if (authority != null) {
- builder.append(authority);
- }
return builder.toString();
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8b3ecae..508fdee 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4415,7 +4415,7 @@ public abstract class BatteryStats implements Parcelable {
if (!checkin) {
pw.println(header);
}
- String[] lineArgs = new String[4];
+ String[] lineArgs = new String[5];
for (int i=0; i<count; i++) {
long duration = steps.getDurationAt(i);
int level = steps.getLevelAt(i);
@@ -4430,7 +4430,7 @@ public abstract class BatteryStats implements Parcelable {
case Display.STATE_ON: lineArgs[2] = "s+"; break;
case Display.STATE_DOZE: lineArgs[2] = "sd"; break;
case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break;
- default: lineArgs[1] = "?"; break;
+ default: lineArgs[2] = "?"; break;
}
} else {
lineArgs[2] = "";
@@ -4441,9 +4441,9 @@ public abstract class BatteryStats implements Parcelable {
lineArgs[3] = "";
}
if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) == 0) {
- lineArgs[3] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
+ lineArgs[4] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
} else {
- lineArgs[3] = "";
+ lineArgs[4] = "";
}
dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
} else {
@@ -4459,7 +4459,7 @@ public abstract class BatteryStats implements Parcelable {
case Display.STATE_ON: pw.print("screen-on"); break;
case Display.STATE_DOZE: pw.print("screen-doze"); break;
case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break;
- default: lineArgs[1] = "screen-?"; break;
+ default: pw.print("screen-?"); break;
}
haveModes = true;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 6517f35..7d57233 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -454,7 +454,6 @@ public class CallLog {
long start, int duration, Long dataUsage, boolean addForAllUsers) {
final ContentResolver resolver = context.getContentResolver();
int numberPresentation = PRESENTATION_ALLOWED;
- boolean isHidden = false;
TelecomManager tm = null;
try {
@@ -469,12 +468,6 @@ public class CallLog {
if (address != null) {
accountAddress = address.getSchemeSpecificPart();
}
- } else {
- // We could not find the account through telecom. For call log entries that
- // are added with a phone account which is not registered, we automatically
- // mark them as hidden. They are unhidden once the account is registered.
- Log.i(LOG_TAG, "Marking call log entry as hidden.");
- isHidden = true;
}
}
@@ -520,7 +513,6 @@ public class CallLog {
values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
values.put(PHONE_ACCOUNT_ID, accountId);
values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
- values.put(PHONE_ACCOUNT_HIDDEN, Integer.valueOf(isHidden ? 1 : 0));
values.put(NEW, Integer.valueOf(1));
if (callType == MISSED_TYPE) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8e5d245..f79ef35 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6375,6 +6375,14 @@ public final class Settings {
"wifi_scan_always_enabled";
/**
+ * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
+ * connectivity.
+ * @hide
+ */
+ public static final String BLE_SCAN_ALWAYS_AVAILABLE =
+ "ble_scan_always_enabled";
+
+ /**
* Used to save the Wifi_ON state prior to tethering.
* This state will be checked to restore Wifi after
* the user turns off tethering.
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index c2ebbc6..e94a312 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -181,7 +181,7 @@ public final class KeymasterDefs {
public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6;
public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7;
public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8;
- public static final int KM_ERROR_UNSUPPORTED_TAG_LENGTH = -9;
+ public static final int KM_ERROR_UNSUPPORTED_MAC_LENGTH = -9;
public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10;
public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11;
public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12;
@@ -237,8 +237,8 @@ public final class KeymasterDefs {
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_SIZE, "Unsupported key size");
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_BLOCK_MODE, "Unsupported block mode");
sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, "Incompatible block mode");
- sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG_LENGTH,
- "Unsupported authentication tag length");
+ sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_MAC_LENGTH,
+ "Unsupported MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PADDING_MODE, "Unsupported padding mode");
sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PADDING_MODE, "Incompatible padding mode");
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_DIGEST, "Unsupported digest");
@@ -261,6 +261,7 @@ public final class KeymasterDefs {
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG, "Unsupported tag");
sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag");
sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed");
+ sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 7d2e1ef..239b386 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -79,7 +79,8 @@ public class DynamicLayout extends Layout
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
- spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+ spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
+ ellipsize, ellipsizedWidth);
}
/**
@@ -95,7 +96,7 @@ public class DynamicLayout extends Layout
TextPaint paint,
int width, Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
- boolean includepad,
+ boolean includepad, int breakStrategy,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
super((ellipsize == null)
? display
@@ -120,6 +121,7 @@ public class DynamicLayout extends Layout
mObjects = new PackedObjectVector<Directions>(1);
mIncludePad = includepad;
+ mBreakStrategy = breakStrategy;
/*
* This is annoying, but we can't refer to the layout until
@@ -279,10 +281,9 @@ public class DynamicLayout extends Layout
sBuilder = null;
}
- // TODO: make sure reflowed is properly initialized
if (reflowed == null) {
reflowed = new StaticLayout(null);
- b = StaticLayout.Builder.obtain();
+ b = StaticLayout.Builder.obtain(text, where, where + after, getWidth());
}
b.setText(text, where, where + after)
@@ -292,7 +293,8 @@ public class DynamicLayout extends Layout
.setSpacingMult(getSpacingMultiplier())
.setSpacingAdd(getSpacingAdd())
.setEllipsizedWidth(mEllipsizedWidth)
- .setEllipsize(mEllipsizeAt);
+ .setEllipsize(mEllipsizeAt)
+ .setBreakStrategy(mBreakStrategy);
reflowed.generate(b, false, true);
int n = reflowed.getLineCount();
@@ -717,6 +719,7 @@ public class DynamicLayout extends Layout
private boolean mEllipsize;
private int mEllipsizedWidth;
private TextUtils.TruncateAt mEllipsizeAt;
+ private int mBreakStrategy;
private PackedIntVector mInts;
private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 22abb18..16ae5e2 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.IntDef;
import android.emoji.EmojiFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -33,6 +34,8 @@ import android.text.style.TabStopSpan;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
/**
@@ -43,6 +46,31 @@ import java.util.Arrays;
* For text that will not change, use a {@link StaticLayout}.
*/
public abstract class Layout {
+ /** @hide */
+ @IntDef({BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BreakStrategy {}
+
+ /**
+ * Value for break strategy indicating simple line breaking. Automatic hyphens are not added
+ * (though soft hyphens are respected), and modifying text generally doesn't affect the layout
+ * before it (which yields a more consistent user experience when editing), but layout may not
+ * be the highest quality.
+ */
+ public static final int BREAK_STRATEGY_SIMPLE = 0;
+
+ /**
+ * Value for break strategy indicating high quality line breaking, including automatic
+ * hyphenation and doing whole-paragraph optimization of line breaks.
+ */
+ public static final int BREAK_STRATEGY_HIGH_QUALITY = 1;
+
+ /**
+ * Value for break strategy indicating balanced line breaking. The breaks are chosen to
+ * make all lines as close to the same length as possible, including automatic hyphenation.
+ */
+ public static final int BREAK_STRATEGY_BALANCED = 2;
+
private static final ParagraphStyle[] NO_PARA_SPANS =
ArrayUtils.emptyArray(ParagraphStyle.class);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 4174df0..2bcb352 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -23,6 +23,7 @@ import android.text.style.LineHeightSpan;
import android.text.style.MetricAffectingSpan;
import android.text.style.TabStopSpan;
import android.util.Log;
+import android.util.Pools.SynchronizedPool;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
@@ -56,28 +57,23 @@ public class StaticLayout extends Layout {
mNativePtr = nNewBuilder();
}
- static Builder obtain() {
- Builder b = null;
- synchronized (sLock) {
- for (int i = 0; i < sCached.length; i++) {
- if (sCached[i] != null) {
- b = sCached[i];
- sCached[i] = null;
- break;
- }
- }
- }
+ public static Builder obtain(CharSequence source, int start, int end, int width) {
+ Builder b = sPool.acquire();
if (b == null) {
b = new Builder();
}
// set default initial values
- b.mWidth = 0;
+ b.mText = source;
+ b.mStart = start;
+ b.mEnd = end;
+ b.mWidth = width;
+ b.mAlignment = Alignment.ALIGN_NORMAL;
b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
b.mSpacingMult = 1.0f;
b.mSpacingAdd = 0.0f;
b.mIncludePad = true;
- b.mEllipsizedWidth = 0;
+ b.mEllipsizedWidth = width;
b.mEllipsize = null;
b.mMaxLines = Integer.MAX_VALUE;
@@ -85,18 +81,11 @@ public class StaticLayout extends Layout {
return b;
}
- static void recycle(Builder b) {
+ private static void recycle(Builder b) {
b.mPaint = null;
b.mText = null;
MeasuredText.recycle(b.mMeasuredText);
- synchronized (sLock) {
- for (int i = 0; i < sCached.length; i++) {
- if (sCached[i] == null) {
- sCached[i] = b;
- break;
- }
- }
- }
+ sPool.release(b);
}
// release any expensive state
@@ -129,6 +118,11 @@ public class StaticLayout extends Layout {
return this;
}
+ public Builder setAlignment(Alignment alignment) {
+ mAlignment = alignment;
+ return this;
+ }
+
public Builder setTextDir(TextDirectionHeuristic textDir) {
mTextDir = textDir;
return this;
@@ -166,6 +160,11 @@ public class StaticLayout extends Layout {
return this;
}
+ public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
+ mBreakStrategy = breakStrategy;
+ return this;
+ }
+
/**
* Measurement and break iteration is done in native code. The protocol for using
* the native code is as follows.
@@ -207,10 +206,8 @@ public class StaticLayout extends Layout {
}
public StaticLayout build() {
- // TODO: can optimize based on whether ellipsis is needed
- StaticLayout result = new StaticLayout(mText);
- result.generate(this, this.mIncludePad, this.mIncludePad);
- recycle(this);
+ StaticLayout result = new StaticLayout(this);
+ Builder.recycle(this);
return result;
}
@@ -230,6 +227,7 @@ public class StaticLayout extends Layout {
int mEnd;
TextPaint mPaint;
int mWidth;
+ Alignment mAlignment;
TextDirectionHeuristic mTextDir;
float mSpacingMult;
float mSpacingAdd;
@@ -237,6 +235,7 @@ public class StaticLayout extends Layout {
int mEllipsizedWidth;
TextUtils.TruncateAt mEllipsize;
int mMaxLines;
+ int mBreakStrategy;
Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -245,8 +244,7 @@ public class StaticLayout extends Layout {
Locale mLocale;
- private static final Object sLock = new Object();
- private static final Builder[] sCached = new Builder[3];
+ private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
}
public StaticLayout(CharSequence source, TextPaint paint,
@@ -316,10 +314,9 @@ public class StaticLayout extends Layout {
: new Ellipsizer(source),
paint, outerwidth, align, textDir, spacingmult, spacingadd);
- Builder b = Builder.obtain();
- b.setText(source, bufstart, bufend)
+ Builder b = Builder.obtain(source, bufstart, bufend, outerwidth)
.setPaint(paint)
- .setWidth(outerwidth)
+ .setAlignment(align)
.setTextDir(textDir)
.setSpacingMult(spacingmult)
.setSpacingAdd(spacingadd)
@@ -366,6 +363,35 @@ public class StaticLayout extends Layout {
mLines = new int[mLineDirections.length];
}
+ private StaticLayout(Builder b) {
+ super((b.mEllipsize == null)
+ ? b.mText
+ : (b.mText instanceof Spanned)
+ ? new SpannedEllipsizer(b.mText)
+ : new Ellipsizer(b.mText),
+ b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
+
+ if (b.mEllipsize != null) {
+ Ellipsizer e = (Ellipsizer) getText();
+
+ e.mLayout = this;
+ e.mWidth = b.mEllipsizedWidth;
+ e.mMethod = b.mEllipsize;
+ mEllipsizedWidth = b.mEllipsizedWidth;
+
+ mColumns = COLUMNS_ELLIPSIZE;
+ } else {
+ mColumns = COLUMNS_NORMAL;
+ mEllipsizedWidth = b.mWidth;
+ }
+
+ mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+ mLines = new int[mLineDirections.length];
+ mMaximumVisibleLineCount = b.mMaxLines;
+
+ generate(b, b.mIncludePad, b.mIncludePad);
+ }
+
/* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
CharSequence source = b.mText;
int bufStart = b.mStart;
@@ -477,10 +503,9 @@ public class StaticLayout extends Layout {
}
}
- int breakStrategy = 0; // 0 = kBreakStrategy_Greedy
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
firstWidth, firstWidthLineCount, restWidth,
- variableTabStops, TAB_INCREMENT, breakStrategy);
+ variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 87f3e94..31c3fe8 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5727,12 +5727,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
- resultSize = 0;
+ resultSize = size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
- resultSize = 0;
+ resultSize = size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 77082b0..ec527d5 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1562,7 +1562,7 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * Sets whether this node is visible to the user.
+ * Gets whether this node is visible to the user.
*
* @return Whether the node is visible to the user.
*/
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index e2f8efc..ec2528f 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -187,7 +187,6 @@ class DayPickerView extends ViewPager {
* @param setSelected whether to set the specified day as selected
*/
private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
- // Set the selected day
if (setSelected) {
mSelectedDay.setTimeInMillis(timeInMillis);
}
@@ -196,6 +195,9 @@ class DayPickerView extends ViewPager {
if (position != getCurrentItem()) {
setCurrentItem(position, animate);
}
+
+ mTempCalendar.setTimeInMillis(timeInMillis);
+ mAdapter.setSelectedDay(mTempCalendar);
}
public long getDate() {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 349f3f0..a50941b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -815,12 +815,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
mContext = context;
mIntent = intent;
- mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
-
- mLayoutInflater = LayoutInflater.from(context);
if (mIntent == null) {
throw new IllegalArgumentException("Non-null Intent must be specified.");
}
+
+ mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
+ mLayoutInflater = LayoutInflater.from(context);
mRequestedViews = new RemoteViewsFrameLayoutRefSet();
// Strip the previously injected app widget id from service intent
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 3fb096c..d9f1f0e 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -80,11 +80,12 @@ class SimpleMonthView extends View {
private final SimpleDateFormat mTitleFormatter;
private final SimpleDateFormat mDayOfWeekFormatter;
- private final int mMonthHeight;
- private final int mDayOfWeekHeight;
- private final int mDayHeight;
- private final int mCellWidth;
- private final int mDaySelectorRadius;
+ // Desired dimensions.
+ private final int mDesiredMonthHeight;
+ private final int mDesiredDayOfWeekHeight;
+ private final int mDesiredDayHeight;
+ private final int mDesiredCellWidth;
+ private final int mDesiredDaySelectorRadius;
// Next/previous drawables.
private final Drawable mPrevDrawable;
@@ -99,6 +100,13 @@ class SimpleMonthView extends View {
private int mMonth;
private int mYear;
+ // Dimensions as laid out.
+ private int mMonthHeight;
+ private int mDayOfWeekHeight;
+ private int mDayHeight;
+ private int mCellWidth;
+ private int mDaySelectorRadius;
+
private int mPaddedWidth;
private int mPaddedHeight;
@@ -158,11 +166,11 @@ class SimpleMonthView extends View {
super(context, attrs, defStyleAttr, defStyleRes);
final Resources res = context.getResources();
- mMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
- mDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
- mDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
- mCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
- mDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
+ mDesiredMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
+ mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
+ mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
+ mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
+ mDesiredDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
mPrevDrawable = context.getDrawable(R.drawable.ic_chevron_left);
mNextDrawable = context.getDrawable(R.drawable.ic_chevron_right);
@@ -400,7 +408,7 @@ class SimpleMonthView extends View {
final TextPaint p = mDayOfWeekPaint;
final int headerHeight = mMonthHeight;
final int rowHeight = mDayOfWeekHeight;
- final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+ final int colWidth = mCellWidth;
// Text is vertically centered within the day of week height.
final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
@@ -426,7 +434,7 @@ class SimpleMonthView extends View {
final TextPaint p = mDayPaint;
final int headerHeight = mMonthHeight + mDayOfWeekHeight;
final int rowHeight = mDayHeight;
- final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+ final int colWidth = mCellWidth;
// Text is vertically centered within the row height.
final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
@@ -627,9 +635,9 @@ class SimpleMonthView extends View {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int preferredHeight = mDayHeight * mNumWeeks + mDayOfWeekHeight + mMonthHeight
- + getPaddingTop() + getPaddingBottom();
- final int preferredWidth = mCellWidth * DAYS_IN_WEEK
+ final int preferredHeight = mDesiredDayHeight * mNumWeeks + mDesiredDayOfWeekHeight
+ + mDesiredMonthHeight + getPaddingTop() + getPaddingBottom();
+ final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK
+ getPaddingStart() + getPaddingEnd();
final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec);
final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec);
@@ -637,16 +645,46 @@ class SimpleMonthView extends View {
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- final int paddedLeft = getPaddingLeft();
- final int paddedTop = getPaddingTop();
- final int paddedRight = w - getPaddingRight();
- final int paddedBottom = h - getPaddingBottom();
- mPaddedWidth = paddedRight - paddedLeft;
- mPaddedHeight = paddedBottom - paddedTop;
-
- final int monthHeight = mMonthHeight;
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (!changed) {
+ return;
+ }
+
+ // Let's initialize a completely reasonable number of variables.
+ final int w = right - left;
+ final int h = bottom - top;
+ final int paddingLeft = getPaddingLeft();
+ final int paddingTop = getPaddingTop();
+ final int paddingRight = getPaddingRight();
+ final int paddingBottom = getPaddingBottom();
+ final int paddedRight = w - paddingRight;
+ final int paddedBottom = h - paddingBottom;
+ final int paddedWidth = paddedRight - paddingLeft;
+ final int paddedHeight = paddedBottom - paddingTop;
+ if (paddedWidth == mPaddedWidth || paddedHeight == mPaddedHeight) {
+ return;
+ }
+
+ mPaddedWidth = paddedWidth;
+ mPaddedHeight = paddedHeight;
+
+ // We may have been laid out smaller than our preferred size. If so,
+ // scale all dimensions to fit.
+ final int measuredPaddedHeight = getMeasuredHeight() - paddingTop - paddingBottom;
+ final float scaleH = paddedHeight / (float) measuredPaddedHeight;
+ final int monthHeight = (int) (mDesiredMonthHeight * scaleH);
final int cellWidth = mPaddedWidth / DAYS_IN_WEEK;
+ mMonthHeight = monthHeight;
+ mDayOfWeekHeight = (int) (mDesiredDayOfWeekHeight * scaleH);
+ mDayHeight = (int) (mDesiredDayHeight * scaleH);
+ mCellWidth = cellWidth;
+
+ // Compute the largest day selector radius that's still within the clip
+ // bounds and desired selector radius.
+ final int maxSelectorWidth = cellWidth / 2 + Math.min(paddingLeft, paddingRight);
+ final int maxSelectorHeight = mDayHeight / 2 + paddingBottom;
+ mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius,
+ Math.min(maxSelectorWidth, maxSelectorHeight));
// Vertically center the previous/next drawables within the month
// header, horizontally center within the day cell, then expand the
@@ -660,7 +698,7 @@ class SimpleMonthView extends View {
// Button bounds don't include padding, but hit area does.
prevDrawable.setBounds(iconLeft, iconTop, iconLeft + dW, iconTop + dH);
- mPrevHitArea.set(0, 0, paddedLeft + cellWidth, paddedTop + monthHeight);
+ mPrevHitArea.set(0, 0, paddingLeft + cellWidth, paddingTop + monthHeight);
}
final Drawable nextDrawable = mNextDrawable;
@@ -668,11 +706,11 @@ class SimpleMonthView extends View {
final int dW = nextDrawable.getIntrinsicWidth();
final int dH = nextDrawable.getIntrinsicHeight();
final int iconTop = (monthHeight - dH) / 2;
- final int iconRight = mPaddedWidth - (cellWidth - dW) / 2;
+ final int iconRight = paddedWidth - (cellWidth - dW) / 2;
// Button bounds don't include padding, but hit area does.
nextDrawable.setBounds(iconRight - dW, iconTop, iconRight, iconTop + dH);
- mNextHitArea.set(paddedRight - cellWidth, 0, w, paddedTop + monthHeight);
+ mNextHitArea.set(paddedRight - cellWidth, 0, w, paddingTop + monthHeight);
}
// Invalidate cached accessibility information.
@@ -753,7 +791,7 @@ class SimpleMonthView extends View {
// Compute left edge.
final int col = index % DAYS_IN_WEEK;
- final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+ final int colWidth = mCellWidth;
final int left = getPaddingLeft() + col * colWidth;
// Compute top edge.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 718ef93..2723080 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -543,6 +543,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private float mSpacingMult = 1.0f;
private float mSpacingAdd = 0.0f;
+ private int mBreakStrategy;
+
private int mMaximum = Integer.MAX_VALUE;
private int mMaxMode = LINES;
private int mMinimum = 0;
@@ -680,6 +682,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boolean elegant = false;
float letterSpacing = 0;
String fontFeatureSettings = null;
+ mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
final Resources.Theme theme = context.getTheme();
@@ -1133,6 +1136,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextView_fontFeatureSettings:
fontFeatureSettings = a.getString(attr);
break;
+
+ case com.android.internal.R.styleable.TextView_breakStrategy:
+ mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
}
}
a.recycle();
@@ -2960,6 +2966,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets the break strategy for breaking paragraphs into lines. The default value for
+ * TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for
+ * EditText is {@link Layout#BREAK_STRATEGY_SIMPLE}, the latter to avoid the
+ * text "dancing" when being edited.
+ *
+ * @attr ref android.R.styleable#TextView_breakStrategy
+ * @see #getBreakStrategy()
+ */
+ public void setBreakStrategy(@Layout.BreakStrategy int breakStrategy) {
+ mBreakStrategy = breakStrategy;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * @return the currently set break strategy.
+ *
+ * @attr ref android.R.styleable#TextView_breakStrategy
+ * @see #setBreakStrategy(int)
+ */
+ @Layout.BreakStrategy
+ public int getBreakStrategy() {
+ return mBreakStrategy;
+ }
+
+ /**
* Sets font feature settings. The format is the same as the CSS
* font-feature-settings attribute:
* http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
@@ -6492,27 +6527,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
hintBoring, mIncludePad, mEllipsize,
ellipsisWidth);
}
- } else if (shouldEllipsize) {
- mHintLayout = new StaticLayout(mHint,
- 0, mHint.length(),
- mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, mEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- mHintLayout = new StaticLayout(mHint, mTextPaint,
- hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
}
- } else if (shouldEllipsize) {
- mHintLayout = new StaticLayout(mHint,
- 0, mHint.length(),
- mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, mEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- mHintLayout = new StaticLayout(mHint, mTextPaint,
- hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
+ }
+ // TODO: code duplication with makeSingleLayout()
+ if (mHintLayout == null) {
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
+ mHint.length(), hintWidth)
+ .setPaint(mTextPaint)
+ .setAlignment(alignment)
+ .setTextDir(mTextDir)
+ .setSpacingMult(mSpacingMult)
+ .setSpacingAdd(mSpacingAdd)
+ .setIncludePad(mIncludePad)
+ .setBreakStrategy(mBreakStrategy);
+ if (shouldEllipsize) {
+ builder.setEllipsize(mEllipsize)
+ .setEllipsizedWidth(ellipsisWidth)
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ }
+ mHintLayout = builder.build();
}
}
@@ -6544,9 +6577,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Layout result = null;
if (mText instanceof Spannable) {
result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
- alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, getKeyListener() == null ? effectiveEllipsize : null,
- ellipsisWidth);
+ alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
+ getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
@@ -6583,29 +6615,27 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boring, mIncludePad, effectiveEllipsize,
ellipsisWidth);
}
- } else if (shouldEllipsize) {
- result = new StaticLayout(mTransformed,
- 0, mTransformed.length(),
- mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, effectiveEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- result = new StaticLayout(mTransformed, mTextPaint,
- wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
}
- } else if (shouldEllipsize) {
- result = new StaticLayout(mTransformed,
- 0, mTransformed.length(),
- mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, effectiveEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- result = new StaticLayout(mTransformed, mTextPaint,
- wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
}
}
+ if (result == null) {
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
+ 0, mTransformed.length(), wantWidth)
+ .setPaint(mTextPaint)
+ .setAlignment(alignment)
+ .setTextDir(mTextDir)
+ .setSpacingMult(mSpacingMult)
+ .setSpacingAdd(mSpacingAdd)
+ .setIncludePad(mIncludePad)
+ .setBreakStrategy(mBreakStrategy);
+ if (shouldEllipsize) {
+ builder.setEllipsize(effectiveEllipsize)
+ .setEllipsizedWidth(ellipsisWidth)
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ }
+ // TODO: explore always setting maxLines
+ result = builder.build();
+ }
return result;
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index c58d5cb..2365b48 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -25,8 +25,10 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.SpannableStringBuilder;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
+import android.text.style.TtsSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.util.StateSet;
@@ -155,13 +157,16 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
mHourView.setMinWidth(computeStableWidth(mHourView, 24));
mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
+ final SpannableStringBuilder amLabel = new SpannableStringBuilder()
+ .append(amPmStrings[0], new TtsSpan.VerbatimBuilder(amPmStrings[0]).build(), 0);
+
// Set up AM/PM labels.
mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
- mAmLabel.setText(amPmStrings[0]);
+ mAmLabel.setText(obtainVerbatim(amPmStrings[0]));
mAmLabel.setOnClickListener(mClickListener);
mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
- mPmLabel.setText(amPmStrings[1]);
+ mPmLabel.setText(obtainVerbatim(amPmStrings[1]));
mPmLabel.setOnClickListener(mClickListener);
// For the sake of backwards compatibility, attempt to extract the text
@@ -220,6 +225,11 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
}
+ private static final CharSequence obtainVerbatim(String text) {
+ return new SpannableStringBuilder().append(text,
+ new TtsSpan.VerbatimBuilder(text).build(), 0);
+ }
+
/**
* The legacy text color might have been poorly defined. Ensures that it
* has an appropriate activated state, using the selected state if one
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 93dc995..05ed3ab 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -104,7 +104,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 123 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;