Merge "Do not take screenshots when launching activities..." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 94b40279..078ed53 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13228,6 +13228,7 @@
field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB;
field public static final java.util.UUID EFFECT_TYPE_EQUALIZER;
+ field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER;
field public static final java.util.UUID EFFECT_TYPE_NS;
field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB;
field public static final java.util.UUID EFFECT_TYPE_VIRTUALIZER;
@@ -13385,6 +13386,7 @@
}
public class LoudnessEnhancer extends android.media.audiofx.AudioEffect {
+ ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException;
method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
method public void setTargetGain(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
field public static final int PARAM_TARGET_GAIN_MB = 0; // 0x0
@@ -25633,10 +25635,8 @@
ctor public TransitionManager();
method public static void beginDelayedTransition(android.view.ViewGroup);
method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
- method public static android.transition.Transition getDefaultTransition();
method public static void go(android.transition.Scene);
method public static void go(android.transition.Scene, android.transition.Transition);
- method public void setDefaultTransition(android.transition.Transition);
method public void setTransition(android.transition.Scene, android.transition.Transition);
method public void setTransition(android.transition.Scene, android.transition.Scene, android.transition.Transition);
method public void transitionTo(android.transition.Scene);
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 14f67c5..50fdb41 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -358,14 +358,20 @@
mListener = listener;
}
+ @Override
public void addSensorEvent(Sensor sensor) {
SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,
mManager.mTargetSdkLevel));
- mSensorsEvents.put(sensor.getHandle(), t);
+ synchronized (mSensorsEvents) {
+ mSensorsEvents.put(sensor.getHandle(), t);
+ }
}
+ @Override
public void removeSensorEvent(Sensor sensor) {
- mSensorsEvents.delete(sensor.getHandle());
+ synchronized (mSensorsEvents) {
+ mSensorsEvents.delete(sensor.getHandle());
+ }
}
// Called from native code.
@@ -374,9 +380,14 @@
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
long timestamp) {
final Sensor sensor = sHandleToSensor.get(handle);
- SensorEvent t = mSensorsEvents.get(handle);
+ SensorEvent t = null;
+ synchronized (mSensorsEvents) {
+ t = mSensorsEvents.get(handle);
+ }
+
if (t == null) {
- Log.e(TAG, "Error: Sensor Event is null for Sensor: " + sensor);
+ // This may happen if the client has unregistered and there are pending events in
+ // the queue waiting to be delivered. Ignore.
return;
}
// Copy from the values array.
@@ -427,14 +438,20 @@
mListener = listener;
}
+ @Override
public void addSensorEvent(Sensor sensor) {
TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor,
mManager.mTargetSdkLevel));
- mTriggerEvents.put(sensor.getHandle(), t);
+ synchronized (mTriggerEvents) {
+ mTriggerEvents.put(sensor.getHandle(), t);
+ }
}
+ @Override
public void removeSensorEvent(Sensor sensor) {
- mTriggerEvents.delete(sensor.getHandle());
+ synchronized (mTriggerEvents) {
+ mTriggerEvents.delete(sensor.getHandle());
+ }
}
// Called from native code.
@@ -443,7 +460,10 @@
protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
long timestamp) {
final Sensor sensor = sHandleToSensor.get(handle);
- TriggerEvent t = mTriggerEvents.get(handle);
+ TriggerEvent t = null;
+ synchronized (mTriggerEvents) {
+ t = mTriggerEvents.get(handle);
+ }
if (t == null) {
Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor);
return;
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 5a919fb..f9c1d31 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -35,10 +35,12 @@
public static final Bundle EMPTY;
static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ static final Parcel EMPTY_PARCEL;
static {
EMPTY = new Bundle();
EMPTY.mMap = ArrayMap.EMPTY;
+ EMPTY_PARCEL = Parcel.obtain();
}
// Invariant - exactly one of mMap / mParcelledData will be null
@@ -115,9 +117,13 @@
*/
public Bundle(Bundle b) {
if (b.mParcelledData != null) {
- mParcelledData = Parcel.obtain();
- mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
- mParcelledData.setDataPosition(0);
+ if (b.mParcelledData == EMPTY_PARCEL) {
+ mParcelledData = EMPTY_PARCEL;
+ } else {
+ mParcelledData = Parcel.obtain();
+ mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
+ mParcelledData.setDataPosition(0);
+ }
} else {
mParcelledData = null;
}
@@ -216,6 +222,18 @@
return;
}
+ if (mParcelledData == EMPTY_PARCEL) {
+ if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ + ": empty");
+ if (mMap == null) {
+ mMap = new ArrayMap<String, Object>(1);
+ } else {
+ mMap.erase();
+ }
+ mParcelledData = null;
+ return;
+ }
+
int N = mParcelledData.readInt();
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ ": reading " + N + " maps");
@@ -1652,11 +1670,20 @@
final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
try {
if (mParcelledData != null) {
- int length = mParcelledData.dataSize();
- parcel.writeInt(length);
- parcel.writeInt(BUNDLE_MAGIC);
- parcel.appendFrom(mParcelledData, 0, length);
+ if (mParcelledData == EMPTY_PARCEL) {
+ parcel.writeInt(0);
+ } else {
+ int length = mParcelledData.dataSize();
+ parcel.writeInt(length);
+ parcel.writeInt(BUNDLE_MAGIC);
+ parcel.appendFrom(mParcelledData, 0, length);
+ }
} else {
+ // Special case for empty bundles.
+ if (mMap == null || mMap.size() <= 0) {
+ parcel.writeInt(0);
+ return;
+ }
int lengthPos = parcel.dataPosition();
parcel.writeInt(-1); // dummy, will hold length
parcel.writeInt(BUNDLE_MAGIC);
@@ -1690,6 +1717,13 @@
}
void readFromParcelInner(Parcel parcel, int length) {
+ if (length == 0) {
+ // Empty Bundle or end of data.
+ mParcelledData = EMPTY_PARCEL;
+ mHasFds = false;
+ mFdsKnown = true;
+ return;
+ }
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
@@ -1716,8 +1750,12 @@
@Override
public synchronized String toString() {
if (mParcelledData != null) {
- return "Bundle[mParcelledData.dataSize=" +
- mParcelledData.dataSize() + "]";
+ if (mParcelledData == EMPTY_PARCEL) {
+ return "Bundle[EMPTY_PARCEL]";
+ } else {
+ return "Bundle[mParcelledData.dataSize=" +
+ mParcelledData.dataSize() + "]";
+ }
}
return "Bundle[" + mMap.toString() + "]";
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 02b1998..94b9617 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -611,11 +611,15 @@
here.fillInStackTrace();
Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
}
+ int startPos;
for (int i=0; i<N; i++) {
- if (DEBUG_ARRAY_MAP) Log.d(TAG, " Write #" + i + ": key=0x"
- + (val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0) + " " + val.keyAt(i));
+ if (DEBUG_ARRAY_MAP) startPos = dataPosition();
writeValue(val.keyAt(i));
writeValue(val.valueAt(i));
+ if (DEBUG_ARRAY_MAP) Log.d(TAG, " Write #" + i + " "
+ + (dataPosition()-startPos) + " bytes: key=0x"
+ + Integer.toHexString(val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0)
+ + " " + val.keyAt(i));
}
}
@@ -2303,11 +2307,14 @@
here.fillInStackTrace();
Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
}
+ int startPos;
while (N > 0) {
+ if (DEBUG_ARRAY_MAP) startPos = dataPosition();
Object key = readValue(loader);
- if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + ": key=0x"
- + (key != null ? key.hashCode() : 0) + " " + key);
Object value = readValue(loader);
+ if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + " "
+ + (dataPosition()-startPos) + " bytes: key=0x"
+ + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
outVal.append(key, value);
N--;
}
diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java
index 5800bd5..e1f1896 100644
--- a/core/java/android/transition/Scene.java
+++ b/core/java/android/transition/Scene.java
@@ -57,7 +57,7 @@
com.android.internal.R.id.scene_layoutid_cache);
if (scenes == null) {
scenes = new SparseArray<Scene>();
- sceneRoot.setTag(com.android.internal.R.id.scene_layoutid_cache, scenes);
+ sceneRoot.setTagInternal(com.android.internal.R.id.scene_layoutid_cache, scenes);
}
Scene scene = scenes.get(layoutId);
if (scene != null) {
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 9b1494d..3bf6790 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -82,6 +82,8 @@
* an {@link AutoTransition} instance.
*
* @param transition The default transition to be used for scene changes.
+ *
+ * @hide pending later changes
*/
public void setDefaultTransition(Transition transition) {
sDefaultTransition = transition;
@@ -93,6 +95,8 @@
*
* @return The current default transition.
* @see #setDefaultTransition(Transition)
+ *
+ * @hide pending later changes
*/
public static Transition getDefaultTransition() {
return sDefaultTransition;
@@ -105,7 +109,7 @@
* transition to run.
* @param transition The transition that will play when the given scene is
* entered. A value of null will result in the default behavior of
- * using the {@link #getDefaultTransition() default transition} instead.
+ * using the default transition instead.
*/
public void setTransition(Scene scene, Transition transition) {
mSceneTransitions.put(scene, transition);
@@ -121,7 +125,7 @@
* be run
* @param transition The transition that will play when the given scene is
* entered. A value of null will result in the default behavior of
- * using the {@link #getDefaultTransition() default transition} instead.
+ * using the default transition instead.
*/
public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
@@ -139,8 +143,8 @@
*
* @param scene The scene being entered
* @return The Transition to be used for the given scene change. If no
- * Transition was specified for this scene change, the {@link #getDefaultTransition()
- * default transition} will be used instead.
+ * Transition was specified for this scene change, the default transition
+ * will be used instead.
*/
private Transition getTransition(Scene scene) {
Transition transition = null;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index cd853b6..591267e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -181,11 +181,12 @@
} else {
mAlwaysUseOption = false;
}
- }
- final int initialHighlight = mAdapter.getInitialHighlight();
- if (initialHighlight >= 0) {
- mListView.setItemChecked(initialHighlight, true);
- onItemClick(null, null, initialHighlight, 0); // Other entries are not used
+ // Set the initial highlight if there was a preferred or last used choice
+ final int initialHighlight = mAdapter.getInitialHighlight();
+ if (initialHighlight >= 0) {
+ mListView.setItemChecked(initialHighlight, true);
+ onItemClick(null, null, initialHighlight, 0); // Other entries are not used
+ }
}
}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e82ad1e..490eab8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -97,6 +97,13 @@
the SIM card. -->
<string name="needPuk">Your SIM card is PUK-locked. Type the PUK code to unlock it.</string>
<string name="needPuk2">Type PUK2 to unblock SIM card.</string>
+ <!-- Displayed when user attempts to change SIM PIN1 without enabling PIN1. -->
+ <string name="enablePin">Unsuccessful, enable SIM/RUIM Lock.</string>
+ <!-- Displayed when a SIM PIN/PUK is entered incorrectly. -->
+ <plurals name="pinpuk_attempts">
+ <item quantity="one">You have <xliff:g id="number">%d</xliff:g> remaining attempt before SIM is locked.</item>
+ <item quantity="other">You have <xliff:g id="number">%d</xliff:g> remaining attempts before SIM is locked.</item>
+ </plurals>
<!-- Title for the dialog used to display the user's IMEI number [CHAR LIMIT=10] -->
<string name="imei">IMEI</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dc0841a..a5573c9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -612,6 +612,7 @@
<java-symbol type="string" name="more_item_label" />
<java-symbol type="string" name="needPuk" />
<java-symbol type="string" name="needPuk2" />
+ <java-symbol type="string" name="enablePin" />
<java-symbol type="string" name="new_app_action" />
<java-symbol type="string" name="new_app_description" />
<java-symbol type="string" name="noApplications" />
@@ -965,6 +966,7 @@
<java-symbol type="plurals" name="num_minutes_ago" />
<java-symbol type="plurals" name="num_seconds_ago" />
<java-symbol type="plurals" name="restr_pin_countdown" />
+ <java-symbol type="plurals" name="pinpuk_attempts" />
<java-symbol type="array" name="carrier_properties" />
<java-symbol type="array" name="config_data_usage_network_types" />
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index 072b842..c5b9c67 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index 74919ff..0320214 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index 4642d6f..38ba570 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
index 13bf13a..271606b 100644
--- a/data/fonts/Roboto-Light.ttf
+++ b/data/fonts/Roboto-Light.ttf
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
index 130672a..17ef355 100644
--- a/data/fonts/Roboto-LightItalic.ttf
+++ b/data/fonts/Roboto-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index 0ba95c9..7469063 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
index 309c22d..74efe4d 100644
--- a/data/fonts/Roboto-Thin.ttf
+++ b/data/fonts/Roboto-Thin.ttf
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
index 0b53ba4..f08ea51 100644
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ b/data/fonts/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
index f0fd409..1252d00 100644
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ b/data/fonts/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
index e67b02b0..e914a07 100644
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ b/data/fonts/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
index a08414b..8a570cf 100644
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ b/data/fonts/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
index 713fd30..a16b9cb 100644
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ b/data/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 25efe1e..ad084c2 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -346,6 +346,7 @@
RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
if (fragment == null) {
fragment = new RetainFragment();
+ fm.beginTransaction().add(fragment, TAG).commit();
}
return fragment;
}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 12f7bd9..1e1ef8c 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -120,8 +120,6 @@
.fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
/**
- * @hide
- * CANDIDATE FOR PUBLIC API
* UUID for Loudness Enhancer
*/
public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
diff --git a/media/java/android/media/audiofx/LoudnessEnhancer.java b/media/java/android/media/audiofx/LoudnessEnhancer.java
index eb2fb75..7dc4175 100644
--- a/media/java/android/media/audiofx/LoudnessEnhancer.java
+++ b/media/java/android/media/audiofx/LoudnessEnhancer.java
@@ -65,7 +65,6 @@
private final Object mParamListenerLock = new Object();
/**
- * @hide
* Class constructor.
* @param audioSession system-wide unique audio session identifier. The LoudnessEnhancer
* will be attached to the MediaPlayer or AudioTrack in the same audio session.
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 6faf7f8..179bcd1 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -50,6 +50,14 @@
android:authorities="com.android.documentsui.recents"
android:exported="false" />
+ <receiver android:name=".PackageReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
+ <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
+
<!-- TODO: remove when we have real clients -->
<activity android:name=".TestActivity" android:enabled="false">
<intent-filter>
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
index 891f0a0..d601194 100644
--- a/packages/DocumentsUI/res/layout/fragment_save.xml
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -51,15 +51,31 @@
android:singleLine="true"
android:selectAllOnFocus="true" />
- <Button
- android:id="@android:id/button1"
+ <FrameLayout
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/menu_save"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:padding="8dp" />
+ android:layout_height="match_parent">
+
+ <Button
+ android:id="@android:id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:text="@string/menu_save"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:padding="8dp" />
+
+ <ProgressBar
+ android:id="@android:id/progress"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone"
+ android:indeterminate="true"
+ android:padding="8dp"
+ style="?android:attr/progressBarStyle" />
+
+ </FrameLayout>
</LinearLayout>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 90be197..ba8c35f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -95,6 +95,11 @@
}
@Override
+ protected void onPreExecute() {
+ mActivity.setPending(true);
+ }
+
+ @Override
protected DocumentInfo doInBackground(Void... params) {
final ContentResolver resolver = mActivity.getContentResolver();
ContentProviderClient client = null;
@@ -120,6 +125,8 @@
} else {
Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show();
}
+
+ mActivity.setPending(false);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index d675e8d..a9278d7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -661,6 +661,13 @@
DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
}
+ public void setPending(boolean pending) {
+ final SaveFragment save = SaveFragment.get(getFragmentManager());
+ if (save != null) {
+ save.setPending(pending);
+ }
+ }
+
@Override
public void onBackPressed() {
if (!mState.stackTouched) {
@@ -1051,6 +1058,11 @@
}
@Override
+ protected void onPreExecute() {
+ setPending(true);
+ }
+
+ @Override
protected Uri doInBackground(Void... params) {
final ContentResolver resolver = getContentResolver();
final DocumentInfo cwd = getCurrentDirectory();
@@ -1083,6 +1095,8 @@
Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
.show();
}
+
+ setPending(false);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
new file mode 100644
index 0000000..aef63af
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/PackageReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+/**
+ * Clean up {@link RecentsProvider} when packages are removed.
+ */
+public class PackageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final ContentResolver resolver = context.getContentResolver();
+
+ final String action = intent.getAction();
+ if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+ resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE, null, null);
+
+ } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) {
+ final Uri data = intent.getData();
+ if (data != null) {
+ final String packageName = data.getSchemeSpecificPart();
+ resolver.call(RecentsProvider.buildRecent(), RecentsProvider.METHOD_PURGE_PACKAGE,
+ packageName, null);
+ }
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 4313fa7..f6e4349 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -16,24 +16,40 @@
package com.android.documentsui;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
import android.content.UriMatcher;
+import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.internal.util.Predicate;
+import com.google.android.collect.Sets;
+
+import libcore.io.IoUtils;
+
+import java.io.IOException;
+import java.util.Set;
+
public class RecentsProvider extends ContentProvider {
private static final String TAG = "RecentsProvider";
- public static final long MAX_HISTORY_IN_MILLIS = 45 * DateUtils.DAY_IN_MILLIS;
+ private static final long MAX_HISTORY_IN_MILLIS = 45 * DateUtils.DAY_IN_MILLIS;
private static final String AUTHORITY = "com.android.documentsui.recents";
@@ -43,6 +59,9 @@
private static final int URI_STATE = 2;
private static final int URI_RESUME = 3;
+ public static final String METHOD_PURGE = "purge";
+ public static final String METHOD_PURGE_PACKAGE = "purgePackage";
+
static {
sMatcher.addURI(AUTHORITY, "recent", URI_RECENT);
// state/authority/rootId/docId
@@ -231,4 +250,116 @@
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Unsupported Uri " + uri);
}
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ if (METHOD_PURGE.equals(method)) {
+ // Purge references to unknown authorities
+ final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
+ final Set<String> knownAuth = Sets.newHashSet();
+ for (ResolveInfo info : getContext()
+ .getPackageManager().queryIntentContentProviders(intent, 0)) {
+ knownAuth.add(info.providerInfo.authority);
+ }
+
+ purgeByAuthority(new Predicate<String>() {
+ @Override
+ public boolean apply(String authority) {
+ // Purge unknown authorities
+ return !knownAuth.contains(authority);
+ }
+ });
+
+ return null;
+
+ } else if (METHOD_PURGE_PACKAGE.equals(method)) {
+ // Purge references to authorities in given package
+ final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
+ intent.setPackage(arg);
+ final Set<String> packageAuth = Sets.newHashSet();
+ for (ResolveInfo info : getContext()
+ .getPackageManager().queryIntentContentProviders(intent, 0)) {
+ packageAuth.add(info.providerInfo.authority);
+ }
+
+ if (!packageAuth.isEmpty()) {
+ purgeByAuthority(new Predicate<String>() {
+ @Override
+ public boolean apply(String authority) {
+ // Purge authority matches
+ return packageAuth.contains(authority);
+ }
+ });
+ }
+
+ return null;
+
+ } else {
+ return super.call(method, arg, extras);
+ }
+ }
+
+ /**
+ * Purge all internal data whose authority matches the given
+ * {@link Predicate}.
+ */
+ private void purgeByAuthority(Predicate<String> predicate) {
+ final SQLiteDatabase db = mHelper.getWritableDatabase();
+ final DocumentStack stack = new DocumentStack();
+
+ Cursor cursor = db.query(TABLE_RECENT, null, null, null, null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ try {
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(RecentColumns.STACK));
+ DurableUtils.readFromArray(rawStack, stack);
+
+ if (stack.root != null && predicate.apply(stack.root.authority)) {
+ final String key = getCursorString(cursor, RecentColumns.KEY);
+ db.delete(TABLE_RECENT, RecentColumns.KEY + "=?", new String[] { key });
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ cursor = db.query(TABLE_STATE, new String[] {
+ StateColumns.AUTHORITY }, null, null, StateColumns.AUTHORITY, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final String authority = getCursorString(cursor, StateColumns.AUTHORITY);
+ if (predicate.apply(authority)) {
+ db.delete(TABLE_STATE, StateColumns.AUTHORITY + "=?", new String[] {
+ authority });
+ Log.d(TAG, "Purged state for " + authority);
+ }
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ cursor = db.query(TABLE_RESUME, null, null, null, null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ try {
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(ResumeColumns.STACK));
+ DurableUtils.readFromArray(rawStack, stack);
+
+ if (stack.root != null && predicate.apply(stack.root.authority)) {
+ final String packageName = getCursorString(
+ cursor, ResumeColumns.PACKAGE_NAME);
+ db.delete(TABLE_RESUME, ResumeColumns.PACKAGE_NAME + "=?",
+ new String[] { packageName });
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index fdbc3ab..58c5daf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
+
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -25,7 +27,9 @@
import android.content.Loader;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.LayoutInflater;
@@ -33,6 +37,7 @@
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
@@ -133,6 +138,13 @@
final State state = ((DocumentsActivity) context).getDisplayState();
state.showAdvanced = SettingsActivity.getDisplayAdvancedDevices(context);
+ if (state.action == ACTION_GET_CONTENT) {
+ mList.setOnItemLongClickListener(mItemLongClickListener);
+ } else {
+ mList.setOnItemLongClickListener(null);
+ mList.setLongClickable(false);
+ }
+
getLoaderManager().restartLoader(2, null, mCallbacks);
}
@@ -152,6 +164,13 @@
}
}
+ private void showAppDetails(ResolveInfo ri) {
+ final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ startActivity(intent);
+ }
+
private OnItemClickListener mItemListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -167,6 +186,19 @@
}
};
+ private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {
+ @Override
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ final Item item = mAdapter.getItem(position);
+ if (item instanceof AppItem) {
+ showAppDetails(((AppItem) item).info);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+
private static abstract class Item {
private final int mLayoutId;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index 23e047c..9d70c51 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -30,6 +30,7 @@
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
+import android.widget.ProgressBar;
import com.android.documentsui.model.DocumentInfo;
@@ -42,6 +43,7 @@
private DocumentInfo mReplaceTarget;
private EditText mDisplayName;
private Button mSave;
+ private ProgressBar mProgress;
private boolean mIgnoreNextEdit;
private static final String EXTRA_MIME_TYPE = "mime_type";
@@ -83,6 +85,8 @@
mSave.setOnClickListener(mSaveListener);
mSave.setEnabled(false);
+ mProgress = (ProgressBar) view.findViewById(android.R.id.progress);
+
return view;
}
@@ -92,7 +96,6 @@
if (mIgnoreNextEdit) {
mIgnoreNextEdit = false;
} else {
- Log.d(TAG, "onTextChanged!");
mReplaceTarget = null;
}
}
@@ -140,4 +143,9 @@
public void setSaveEnabled(boolean enabled) {
mSave.setEnabled(enabled);
}
+
+ public void setPending(boolean pending) {
+ mSave.setVisibility(pending ? View.INVISIBLE : View.VISIBLE);
+ mProgress.setVisibility(pending ? View.VISIBLE : View.GONE);
+ }
}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
index 71ce4dd..af6ff01 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java
@@ -127,7 +127,7 @@
final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
final RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
- row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_CREATE);
row.add(Root.COLUMN_TITLE, "_Test title which is really long");
row.add(Root.COLUMN_SUMMARY,
SystemClock.elapsedRealtime() + " summary which is also super long text");
@@ -147,6 +147,14 @@
return result;
}
+ @Override
+ public String createDocument(String parentDocumentId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ if (LAG) lagUntilCanceled(null);
+
+ return super.createDocument(parentDocumentId, mimeType, displayName);
+ }
+
/**
* Holds any outstanding or finished "network" fetching.
*/
@@ -386,6 +394,7 @@
if (MY_DOC_ID.equals(docId)) {
row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+ row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_SUPPORTS_CREATE);
} else if (MY_DOC_NULL.equals(docId)) {
// No MIME type
} else {
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
deleted file mode 100644
index 6402d3d..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
deleted file mode 100644
index 83be046..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
deleted file mode 100644
index a7e063a..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
deleted file mode 100644
index 53af5a5..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
deleted file mode 100644
index e4172ce..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
deleted file mode 100644
index e2c76217..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml b/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml
deleted file mode 100644
index 6c081bf..0000000
--- a/packages/Keyguard/res/drawable/lockscreen_forgot_password_button.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="true" android:drawable="@drawable/ic_lockscreen_forgotpassword_normal" />
- <item android:state_pressed="true" android:drawable="@drawable/ic_lockscreen_forgotpassword_pressed" />
- <item android:drawable="@drawable/ic_lockscreen_forgotpassword_normal" />
-</selector>
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index 313fe9f..8be15cb 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -42,7 +42,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="-10dip"
+ android:layout_marginTop="@dimen/eca_overlap"
style="?android:attr/buttonBarStyle"
android:orientation="horizontal"
android:gravity="center"
@@ -66,12 +66,10 @@
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:drawableLeft="@drawable/lockscreen_forgot_password_button"
style="?android:attr/buttonBarButtonStyle"
android:textSize="@dimen/kg_status_line_font_size"
android:textColor="?android:attr/textColorSecondary"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:drawablePadding="8dip"
android:visibility="gone"
android:textAllCaps="@bool/kg_use_all_caps" />
</LinearLayout>
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index f8a1362..ea5ef27 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -66,4 +66,7 @@
<dimen name="widget_label_font_size">16dp</dimen>
<dimen name="widget_big_font_size">141dp</dimen>
+ <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
+ Should be 0 on devices with plenty of room (e.g. tablets) -->
+ <dimen name="eca_overlap">0dip</dimen>
</resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index a1ad120..71e9924 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -150,6 +150,10 @@
security mode. -->
<dimen name="kg_small_widget_height">160dp</dimen>
+ <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
+ Should be 0 on devices with plenty of room (e.g. tablets) -->
+ <dimen name="eca_overlap">-10dip</dimen>
+
<!-- Default clock parameters -->
<dimen name="bottom_text_spacing_digital">-8dp</dimen>
<dimen name="label_font_size">14dp</dimen>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index abc4483..4738049 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -24,12 +24,12 @@
<!-- Instructions telling the user to enter their SIM PUK to unlock the keyguard.
Displayed in one line in a large font. -->
- <string name="keyguard_password_enter_puk_code">Type PUK and new PIN code</string>
+ <string name="keyguard_password_enter_puk_code">Type SIM PUK and new PIN code</string>
<!-- Prompt to enter SIM PUK in Edit Text Box in unlock screen -->
- <string name="keyguard_password_enter_puk_prompt">PUK code</string>
+ <string name="keyguard_password_enter_puk_prompt">SIM PUK code</string>
<!-- Prompt to enter New SIM PIN in Edit Text Box in unlock screen -->
- <string name="keyguard_password_enter_pin_prompt">New PIN code</string>
+ <string name="keyguard_password_enter_pin_prompt">New SIM PIN code</string>
<!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]-->
<string name="keyguard_password_entry_touch_hint"><font size="17">Touch to type password</font></string>
@@ -249,8 +249,6 @@
<string name="kg_enter_confirm_pin_hint">Confirm desired PIN code</string>
<!-- Message shown in dialog while the device is unlocking the SIM card -->
<string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
- <!-- Message shown when the user enters the wrong PIN code -->
- <string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
<!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
<string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
<!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
@@ -333,6 +331,34 @@
<!-- The delete-widget drop target button text -->
<string name="kg_reordering_delete_drop_target_text">Remove</string>
+ <!-- Instructions telling the user that they entered the wrong SIM PIN for the last time.
+ Displayed in a dialog box. -->
+ <string name="kg_password_wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string>
+ <!-- Instructions telling the user that they entered the wrong SIM PIN while trying
+ to unlock the keyguard. Displayed in a dialog box. -->
+ <plurals name="kg_password_wrong_pin_code">
+ <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
+ </plurals>
+
+ <!-- Instructions telling the user that they have exhausted SIM PUK retries and the SIM is now unusable.
+ Displayed in a dialog box. -->
+ <string name="kg_password_wrong_puk_code_dead">SIM is unusable. Contact your carrier.</string>
+ <!-- Instructions telling the user that they entered the wrong puk while trying
+ to unlock the keyguard. Displayed in a dialog box. -->
+ <plurals name="kg_password_wrong_puk_code">
+ <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable.</item>
+ <item quantity="other">Incorrect SIM PUK code, you have <xliff:g id="number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
+ </plurals>
+ <!-- Instructions telling the user that the operation to unlock the keyguard
+ with SIM PIN failed. Displayed in one line in a large font. -->
+ <string name="kg_password_pin_failed">SIM PIN operation failed!</string>
+ <!-- Instructions telling the user that the operation to unlock the keyguard
+ with PUK failed. Displayed in one line in a large font. -->
+ <string name="kg_password_puk_failed">SIM PUK operation failed!</string>
+ <!-- Notification telling the user that the PIN1 they entered is valid -->
+ <string name="kg_pin_accepted">Code Accepted!</string>
+
<!-- Transport control strings -->
<!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
<string name="keyguard_transport_prev_description">Previous track button</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index 5059407..e39622a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -17,11 +17,16 @@
package com.android.keyguard;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.PhoneConstants;
import android.content.Context;
+import android.content.DialogInterface;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.ProgressDialog;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.Editable;
@@ -30,6 +35,7 @@
import android.text.method.DigitsKeyListener;
import android.util.AttributeSet;
import android.view.View;
+import android.util.Log;
import android.view.WindowManager;
import android.widget.TextView.OnEditorActionListener;
@@ -38,10 +44,14 @@
*/
public class KeyguardSimPinView extends KeyguardAbsKeyInputView
implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+ private static final String LOG_TAG = "KeyguardSimPinView";
+ private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
private ProgressDialog mSimUnlockProgressDialog = null;
private volatile boolean mSimCheckInProgress;
+ private AlertDialog mRemainingAttemptsDialog;
+
public KeyguardSimPinView(Context context) {
this(context, null);
}
@@ -55,6 +65,23 @@
mPasswordEntry.setEnabled(true);
}
+ private String getPinPasswordErrorMessage(int attemptsRemaining) {
+ String displayMessage;
+
+ if (attemptsRemaining == 0) {
+ displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
+ } else if (attemptsRemaining > 0) {
+ displayMessage = getContext().getResources()
+ .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining,
+ attemptsRemaining);
+ } else {
+ displayMessage = getContext().getString(R.string.kg_password_pin_failed);
+ }
+ if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+ + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
+ return displayMessage;
+ }
+
@Override
protected boolean shouldLockout(long deadline) {
// SIM PIN doesn't have a timed lockout
@@ -109,6 +136,8 @@
| InputType.TYPE_NUMBER_VARIATION_PASSWORD);
mPasswordEntry.requestFocus();
+
+ mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
}
@Override
@@ -135,22 +164,22 @@
mPin = pin;
}
- abstract void onSimCheckResponse(boolean success);
+ abstract void onSimCheckResponse(final int result, final int attemptsRemaining);
@Override
public void run() {
try {
- final boolean result = ITelephony.Stub.asInterface(ServiceManager
- .checkService("phone")).supplyPin(mPin);
+ final int[] result = ITelephony.Stub.asInterface(ServiceManager
+ .checkService("phone")).supplyPinReportResult(mPin);
post(new Runnable() {
public void run() {
- onSimCheckResponse(result);
+ onSimCheckResponse(result[0], result[1]);
}
});
} catch (RemoteException e) {
post(new Runnable() {
public void run() {
- onSimCheckResponse(false);
+ onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
}
});
}
@@ -164,14 +193,28 @@
mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
mSimUnlockProgressDialog.setIndeterminate(true);
mSimUnlockProgressDialog.setCancelable(false);
- if (!(mContext instanceof Activity)) {
- mSimUnlockProgressDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- }
+ mSimUnlockProgressDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
}
return mSimUnlockProgressDialog;
}
+ private Dialog getSimRemainingAttemptsDialog(int remaining) {
+ String msg = getPinPasswordErrorMessage(remaining);
+ if (mRemainingAttemptsDialog == null) {
+ Builder builder = new AlertDialog.Builder(mContext);
+ builder.setMessage(msg);
+ builder.setCancelable(false);
+ builder.setNeutralButton(R.string.ok, null);
+ mRemainingAttemptsDialog = builder.create();
+ mRemainingAttemptsDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ } else {
+ mRemainingAttemptsDialog.setMessage(msg);
+ }
+ return mRemainingAttemptsDialog;
+ }
+
@Override
protected void verifyPasswordAndUnlock() {
String entry = mPasswordEntry.getText().toString();
@@ -189,20 +232,34 @@
if (!mSimCheckInProgress) {
mSimCheckInProgress = true; // there should be only one
new CheckSimPin(mPasswordEntry.getText().toString()) {
- void onSimCheckResponse(final boolean success) {
+ void onSimCheckResponse(final int result, final int attemptsRemaining) {
post(new Runnable() {
public void run() {
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.hide();
}
- if (success) {
- // before closing the keyguard, report back that the sim is unlocked
- // so it knows right away.
+ if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
mCallback.dismiss(true);
} else {
- mSecurityMessageDisplay.setMessage
- (R.string.kg_password_wrong_pin_code, true);
+ if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+ if (attemptsRemaining <= 2) {
+ // this is getting critical - show dialog
+ getSimRemainingAttemptsDialog(attemptsRemaining).show();
+ } else {
+ // show message
+ mSecurityMessageDisplay.setMessage(
+ getPinPasswordErrorMessage(attemptsRemaining), true);
+ }
+ } else {
+ // "PIN operation failed!" - no idea what this was and no way to
+ // find out. :/
+ mSecurityMessageDisplay.setMessage(getContext().getString(
+ R.string.kg_password_pin_failed), true);
+ }
+ if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " CheckSimPin.onSimCheckResponse: " + result
+ + " attemptsRemaining=" + attemptsRemaining);
mPasswordEntry.setText("");
}
mCallback.userActivity(0);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index 2ae4cc7..31518a1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -16,10 +16,10 @@
package com.android.keyguard;
-import com.android.internal.telephony.ITelephony;
-
import android.content.Context;
+import android.animation.AnimatorSet.Builder;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.RemoteException;
@@ -29,21 +29,29 @@
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView.OnEditorActionListener;
+import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.PhoneConstants;
+
+
/**
* Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
*/
public class KeyguardSimPukView extends KeyguardAbsKeyInputView
implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+ private static final String LOG_TAG = "KeyguardSimPukView";
+ private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
private ProgressDialog mSimUnlockProgressDialog = null;
private volatile boolean mCheckInProgress;
private String mPukText;
private String mPinText;
private StateMachine mStateMachine = new StateMachine();
+ private AlertDialog mRemainingAttemptsDialog;
private class StateMachine {
final int ENTER_PUK = 0;
@@ -93,6 +101,23 @@
}
}
+ private String getPukPasswordErrorMessage(int attemptsRemaining) {
+ String displayMessage;
+
+ if (attemptsRemaining == 0) {
+ displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
+ } else if (attemptsRemaining > 0) {
+ displayMessage = getContext().getResources()
+ .getQuantityString(R.plurals.kg_password_wrong_puk_code, attemptsRemaining,
+ attemptsRemaining);
+ } else {
+ displayMessage = getContext().getString(R.string.kg_password_puk_failed);
+ }
+ if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
+ + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
+ return displayMessage;
+ }
+
public KeyguardSimPukView(Context context) {
this(context, null);
}
@@ -190,23 +215,23 @@
mPin = pin;
}
- abstract void onSimLockChangedResponse(boolean success);
+ abstract void onSimLockChangedResponse(final int result, final int attemptsRemaining);
@Override
public void run() {
try {
- final boolean result = ITelephony.Stub.asInterface(ServiceManager
- .checkService("phone")).supplyPuk(mPuk, mPin);
+ final int[] result = ITelephony.Stub.asInterface(ServiceManager
+ .checkService("phone")).supplyPukReportResult(mPuk, mPin);
post(new Runnable() {
public void run() {
- onSimLockChangedResponse(result);
+ onSimLockChangedResponse(result[0], result[1]);
}
});
} catch (RemoteException e) {
post(new Runnable() {
public void run() {
- onSimLockChangedResponse(false);
+ onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
}
});
}
@@ -228,6 +253,22 @@
return mSimUnlockProgressDialog;
}
+ private Dialog getPukRemainingAttemptsDialog(int remaining) {
+ String msg = getPukPasswordErrorMessage(remaining);
+ if (mRemainingAttemptsDialog == null) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setMessage(msg);
+ builder.setCancelable(false);
+ builder.setNeutralButton(R.string.ok, null);
+ mRemainingAttemptsDialog = builder.create();
+ mRemainingAttemptsDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ } else {
+ mRemainingAttemptsDialog.setMessage(msg);
+ }
+ return mRemainingAttemptsDialog;
+ }
+
private boolean checkPuk() {
// make sure the puk is at least 8 digits long.
if (mPasswordEntry.getText().length() >= 8) {
@@ -257,17 +298,33 @@
if (!mCheckInProgress) {
mCheckInProgress = true;
new CheckSimPuk(mPukText, mPinText) {
- void onSimLockChangedResponse(final boolean success) {
+ void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
post(new Runnable() {
public void run() {
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.hide();
}
- if (success) {
+ if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
+ KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked();
mCallback.dismiss(true);
} else {
+ if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+ if (attemptsRemaining <= 2) {
+ // this is getting critical - show dialog
+ getPukRemainingAttemptsDialog(attemptsRemaining).show();
+ } else {
+ // show message
+ mSecurityMessageDisplay.setMessage(
+ getPukPasswordErrorMessage(attemptsRemaining), true);
+ }
+ } else {
+ mSecurityMessageDisplay.setMessage(getContext().getString(
+ R.string.kg_password_puk_failed), true);
+ }
+ if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " UpdateSim.onSimCheckResponse: "
+ + " attemptsRemaining=" + attemptsRemaining);
mStateMachine.reset();
- mSecurityMessageDisplay.setMessage(R.string.kg_invalid_puk, true);
}
mCheckInProgress = false;
}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 616090e..8054788 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -58,7 +58,14 @@
// Set this to true to have the watchdog record kernel thread stacks when it fires
static final boolean RECORD_KERNEL_THREADS = true;
- static final int TIME_TO_WAIT = DB ? 5*1000 : 30*1000;
+ static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
+ static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
+
+ // These are temporally ordered: larger values as lateness increases
+ static final int COMPLETED = 0;
+ static final int WAITING = 1;
+ static final int WAITED_HALF = 2;
+ static final int OVERDUE = 3;
static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
"/system/bin/mediaserver",
@@ -87,13 +94,17 @@
public final class HandlerChecker implements Runnable {
private final Handler mHandler;
private final String mName;
+ private final long mWaitMax;
private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
private boolean mCompleted;
private Monitor mCurrentMonitor;
+ private long mStartTime;
- HandlerChecker(Handler handler, String name) {
+ HandlerChecker(Handler handler, String name, long waitMaxMillis) {
mHandler = handler;
mName = name;
+ mWaitMax = waitMaxMillis;
+ mCompleted = true;
}
public void addMonitor(Monitor monitor) {
@@ -111,13 +122,34 @@
mCompleted = true;
return;
}
+
+ if (!mCompleted) {
+ // we already have a check in flight, so no need
+ return;
+ }
+
mCompleted = false;
mCurrentMonitor = null;
+ mStartTime = SystemClock.uptimeMillis();
mHandler.postAtFrontOfQueue(this);
}
- public boolean isCompletedLocked() {
- return mCompleted;
+ public boolean isOverdueLocked() {
+ return (!mCompleted) && (SystemClock.uptimeMillis() > mStartTime + mWaitMax);
+ }
+
+ public int getCompletionStateLocked() {
+ if (mCompleted) {
+ return COMPLETED;
+ } else {
+ long latency = SystemClock.uptimeMillis() - mStartTime;
+ if (latency < mWaitMax/2) {
+ return WAITING;
+ } else if (latency < mWaitMax) {
+ return WAITED_HALF;
+ }
+ }
+ return OVERDUE;
}
public Thread getThread() {
@@ -186,16 +218,19 @@
// The shared foreground thread is the main checker. It is where we
// will also dispatch monitor checks and do other work.
- mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread");
+ mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
+ "foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
// Add checker for main thread. We only do a quick check since there
// can be UI running on the thread.
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
- "main thread"));
+ "main thread", DEFAULT_TIMEOUT));
// Add checker for shared UI thread.
- mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread"));
+ mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
+ "ui thread", DEFAULT_TIMEOUT));
// And also check IO thread.
- mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread"));
+ mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
+ "i/o thread", DEFAULT_TIMEOUT));
}
public void init(Context context, BatteryService battery,
@@ -242,11 +277,15 @@
}
public void addThread(Handler thread, String name) {
+ addThread(thread, name, DEFAULT_TIMEOUT);
+ }
+
+ public void addThread(Handler thread, String name, long timeoutMillis) {
synchronized (this) {
if (isAlive()) {
throw new RuntimeException("Threads can't be added once the Watchdog is running");
}
- mHandlerCheckers.add(new HandlerChecker(thread, name));
+ mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
}
}
@@ -259,21 +298,20 @@
pms.reboot(false, reason, false);
}
- private boolean haveAllCheckersCompletedLocked() {
+ private int evaluateCheckerCompletionLocked() {
+ int state = COMPLETED;
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
- if (!hc.isCompletedLocked()) {
- return false;
- }
+ state = Math.max(state, hc.getCompletionStateLocked());
}
- return true;
+ return state;
}
private ArrayList<HandlerChecker> getBlockedCheckersLocked() {
ArrayList<HandlerChecker> checkers = new ArrayList<HandlerChecker>();
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
- if (!hc.isCompletedLocked()) {
+ if (hc.isOverdueLocked()) {
checkers.add(hc);
}
}
@@ -299,14 +337,12 @@
final String subject;
final boolean allowRestart;
synchronized (this) {
- long timeout = TIME_TO_WAIT;
- if (!waitedHalf) {
- // If we are not at the half-point of waiting, perform a
- // new set of checks. Otherwise we are still waiting for a previous set.
- for (int i=0; i<mHandlerCheckers.size(); i++) {
- HandlerChecker hc = mHandlerCheckers.get(i);
- hc.scheduleCheckLocked();
- }
+ long timeout = CHECK_INTERVAL;
+ // Make sure we (re)spin the checkers that have become idle within
+ // this wait-and-check interval
+ for (int i=0; i<mHandlerCheckers.size(); i++) {
+ HandlerChecker hc = mHandlerCheckers.get(i);
+ hc.scheduleCheckLocked();
}
// NOTE: We use uptimeMillis() here because we do not want to increment the time we
@@ -320,26 +356,31 @@
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
- timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
+ timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
}
- if (haveAllCheckersCompletedLocked()) {
- // The monitors have returned.
+ final int waitState = evaluateCheckerCompletionLocked();
+ if (waitState == COMPLETED) {
+ // The monitors have returned; reset
waitedHalf = false;
continue;
- }
-
- if (!waitedHalf) {
- // We've waited half the deadlock-detection interval. Pull a stack
- // trace and wait another half.
- ArrayList<Integer> pids = new ArrayList<Integer>();
- pids.add(Process.myPid());
- ActivityManagerService.dumpStackTraces(true, pids, null, null,
- NATIVE_STACKS_OF_INTEREST);
- waitedHalf = true;
+ } else if (waitState == WAITING) {
+ // still waiting but within their configured intervals; back off and recheck
+ continue;
+ } else if (waitState == WAITED_HALF) {
+ if (!waitedHalf) {
+ // We've waited half the deadlock-detection interval. Pull a stack
+ // trace and wait another half.
+ ArrayList<Integer> pids = new ArrayList<Integer>();
+ pids.add(Process.myPid());
+ ActivityManagerService.dumpStackTraces(true, pids, null, null,
+ NATIVE_STACKS_OF_INTEREST);
+ waitedHalf = true;
+ }
continue;
}
+ // something is overdue!
blockedCheckers = getBlockedCheckersLocked();
subject = describeCheckersLocked(blockedCheckers);
allowRestart = mAllowRestart;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index e075862..a781d5f 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -221,6 +221,14 @@
static final int REMOVE_CHATTY = 1<<16;
/**
+ * Timeout (in milliseconds) after which the watchdog should declare that
+ * our handler thread is wedged. The usual default for such things is one
+ * minute but we sometimes do very lengthy I/O operations on this thread,
+ * such as installing multi-gigabyte applications, so ours needs to be longer.
+ */
+ private static final long WATCHDOG_TIMEOUT = 1000*60*10; // ten minutes
+
+ /**
* Whether verification is enabled by default.
*/
private static final boolean DEFAULT_VERIFY_ENABLE = true;
@@ -1115,7 +1123,8 @@
synchronized (mPackages) {
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
- Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());
+ Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(),
+ WATCHDOG_TIMEOUT);
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b0cfd7e..d3ccba6 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2070,8 +2070,10 @@
if (intent.getAction() != null) {
filter.addAction(intent.getAction());
}
- for (String cat : intent.getCategories()) {
- filter.addCategory(cat);
+ if (intent.getCategories() != null) {
+ for (String cat : intent.getCategories()) {
+ filter.addCategory(cat);
+ }
}
if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
filter.addCategory(Intent.CATEGORY_DEFAULT);
@@ -2088,6 +2090,13 @@
if (path != null) {
filter.addDataPath(path);
}
+ if (intent.getType() != null) {
+ try {
+ filter.addDataType(intent.getType());
+ } catch (IntentFilter.MalformedMimeTypeException ex) {
+ Slog.w(TAG, "Malformed mimetype " + intent.getType() + " for " + cn);
+ }
+ }
PreferredActivity pa = new PreferredActivity(filter, match, set, cn, true);
editPreferredActivitiesLPw(userId).addFilter(pa);
} else if (!haveNonSys) {
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index afa4f78..52f2325 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -107,7 +107,7 @@
Region mTouchExcludeRegion = new Region();
/** Save allocating when retrieving tasks */
- ArrayList<Task> mTmpTasks = new ArrayList<Task>();
+ ArrayList<Task> mTaskHistory = new ArrayList<Task>();
/** Save allocating when calculating rects */
Rect mTmpRect = new Rect();
@@ -163,7 +163,7 @@
void moveStack(TaskStack stack, boolean toTop) {
mStackHistory.remove(stack);
mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
- mService.moveStackWindowsLocked(stack);
+ mService.moveStackWindowsLocked(this);
}
public boolean isPrivate() {
@@ -175,14 +175,35 @@
* @return All the Tasks, in order, on this display.
*/
ArrayList<Task> getTasks() {
- mTmpTasks.clear();
- final int numStacks = mStackHistory.size();
- for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- mTmpTasks.addAll(mStackHistory.get(stackNdx).getTasks());
+ return mTaskHistory;
+ }
+
+ void addTask(Task task, boolean toTop) {
+ mTaskHistory.remove(task);
+
+ final int userId = task.mUserId;
+ int taskNdx;
+ final int numTasks = mTaskHistory.size();
+ if (toTop) {
+ for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
+ if (mTaskHistory.get(taskNdx).mUserId == userId) {
+ break;
+ }
+ }
+ ++taskNdx;
+ } else {
+ for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+ if (mTaskHistory.get(taskNdx).mUserId == userId) {
+ break;
+ }
+ }
}
- if (WindowManagerService.DEBUG_LAYERS) Slog.i(TAG, "getTasks: mStackHistory=" +
- mStackHistory);
- return mTmpTasks;
+
+ mTaskHistory.add(taskNdx, task);
+ }
+
+ void removeTask(Task task) {
+ mTaskHistory.remove(task);
}
TaskStack getHomeStack() {
@@ -205,10 +226,9 @@
/** @return The number of tokens in all of the Tasks on this display. */
int numTokens() {
- getTasks();
int count = 0;
- for (int taskNdx = mTmpTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- count += mTmpTasks.get(taskNdx).mAppTokens.size();
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ count += mTaskHistory.get(taskNdx).mAppTokens.size();
}
return count;
}
@@ -469,8 +489,8 @@
pw.println();
pw.println(" Application tokens in Z order:");
getTasks();
- for (int taskNdx = mTmpTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- AppTokenList tokens = mTmpTasks.get(taskNdx).mAppTokens;
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
final AppWindowToken wtoken = tokens.get(tokenNdx);
pw.print(" App #"); pw.print(ndx--);
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index 2347a19..34bef68 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -120,6 +120,7 @@
mTasks.add(stackNdx, task);
task.mStack = this;
+ mDisplayContent.addTask(task, toTop);
return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
}
@@ -145,6 +146,7 @@
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
mStackBox.makeDirty();
mTasks.remove(task);
+ mDisplayContent.removeTask(task);
}
int remove() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index abc2b2b..63e09db 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4733,11 +4733,9 @@
return index;
}
- void moveStackWindowsLocked(TaskStack stack) {
- DisplayContent displayContent = stack.getDisplayContent();
-
+ void moveStackWindowsLocked(DisplayContent displayContent) {
// First remove all of the windows from the list.
- final ArrayList<Task> tasks = stack.getTasks();
+ final ArrayList<Task> tasks = displayContent.getTasks();
final int numTasks = tasks.size();
for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
@@ -4813,7 +4811,7 @@
}
final TaskStack stack = task.mStack;
stack.moveTaskToBottom(task);
- moveStackWindowsLocked(stack);
+ moveStackWindowsLocked(stack.getDisplayContent());
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -5724,7 +5722,7 @@
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
- if (true || DEBUG_SCREENSHOT) {
+ if (DEBUG_SCREENSHOT) {
// TEST IF IT's ALL BLACK
int[] buffer = new int[bm.getWidth() * bm.getHeight()];
bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
@@ -8434,20 +8432,6 @@
&& !mWallpaperTarget.mWinAnimator.isDummyAnimation()
? null : mWallpaperTarget;
- // If there is a wallpaper target and the target is neither opening nor closing, then
- // there exists an app on top of the wallpaper target that has a translucent
- // background.
- // If the pending transition is an exit, we should add the wallpaper target to the list
- // of opening apps so that the translucent app on top of it will animate correctly.
- final AppWindowToken wallpaperTargetAppToken =
- mWallpaperTarget != null ? mWallpaperTarget.mAppToken : null;
- if (wallpaperTargetAppToken != null
- && !mClosingApps.contains(wallpaperTargetAppToken)
- && !mOpeningApps.contains(wallpaperTargetAppToken)
- && (transit & AppTransition.TRANSIT_EXIT_MASK) != 0) {
- mOpeningApps.add(wallpaperTargetAppToken);
- NN++;
- }
mInnerFields.mWallpaperMayChange = false;
// The top-most window will supply the layout params,
@@ -8533,7 +8517,8 @@
break;
}
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + transit);
- } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
+ } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
+ && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
// We are transitioning from an activity with
// a wallpaper to one without.
transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
@@ -8602,8 +8587,7 @@
wtoken.mAppAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
wtoken.mAppAnimator.animation = null;
- setTokenVisibilityLocked(wtoken, animLp, false,
- transit, false);
+ setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToHide = false;
// Force the allDrawn flag, because we want to start
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 584411b..7bd2c84 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -155,6 +155,26 @@
boolean supplyPuk(String puk, String pin);
/**
+ * Supply a pin to unlock the SIM. Blocks until a result is determined.
+ * Returns a specific success/error code.
+ * @param pin The pin to check.
+ * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+ * retValue[1] = number of attempts remaining if known otherwise -1
+ */
+ int[] supplyPinReportResult(String pin);
+
+ /**
+ * Supply puk to unlock the SIM and set SIM pin to new pin.
+ * Blocks until a result is determined.
+ * Returns a specific success/error code
+ * @param puk The puk to check
+ * pin The pin to check.
+ * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+ * retValue[1] = number of attempts remaining if known otherwise -1
+ */
+ int[] supplyPukReportResult(String puk, String pin);
+
+ /**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so <code>dial</code> is not appropriate).
*
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 4a4a62b..4163255 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -86,6 +86,14 @@
public static final String REASON_LINK_PROPERTIES_CHANGED = "linkPropertiesChanged";
/**
+ * Return codes for supplyPinReturnResult and
+ * supplyPukReturnResult APIs
+ */
+ public static final int PIN_RESULT_SUCCESS = 0;
+ public static final int PIN_PASSWORD_INCORRECT = 1;
+ public static final int PIN_GENERAL_FAILURE = 2;
+
+ /**
* Return codes for <code>enableApnType()</code>
*/
public static final int APN_ALREADY_ACTIVE = 0;