summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActionBar.java9
-rw-r--r--core/java/android/app/Activity.java36
-rw-r--r--core/java/android/app/ActivityThread.java3
-rw-r--r--core/java/android/app/ContextImpl.java14
-rw-r--r--core/java/android/app/Fragment.java9
-rw-r--r--core/java/android/app/FragmentManager.java6
-rw-r--r--core/java/android/app/FragmentTransaction.java6
-rw-r--r--core/java/android/app/Instrumentation.java3
-rw-r--r--core/java/android/app/IntentService.java6
-rw-r--r--core/java/android/app/LoadedApk.java3
-rw-r--r--core/java/android/app/LoaderManager.java6
-rw-r--r--core/java/android/app/PendingIntent.java4
-rw-r--r--core/java/android/app/Service.java12
-rw-r--r--core/java/android/content/BroadcastReceiver.java13
-rw-r--r--core/java/android/content/Intent.java29
-rw-r--r--core/java/android/content/IntentFilter.java8
-rw-r--r--core/java/android/content/Loader.java8
-rw-r--r--core/java/android/content/SyncManager.java88
-rw-r--r--core/java/android/net/DhcpStateMachine.java8
-rw-r--r--core/java/android/net/DnsPinger.java36
-rw-r--r--core/java/android/net/NetworkStats.java39
-rw-r--r--core/java/android/os/AsyncTask.java7
-rw-r--r--core/java/android/os/Bundle.java51
-rw-r--r--core/java/android/os/Parcel.java6
-rw-r--r--core/java/android/provider/CallLog.java8
-rw-r--r--core/java/android/server/BluetoothAdapterStateMachine.java26
-rwxr-xr-xcore/java/android/server/BluetoothService.java4
-rw-r--r--core/java/android/view/ActionMode.java12
-rw-r--r--core/java/android/view/View.java78
-rw-r--r--core/java/android/view/ViewGroup.java18
-rw-r--r--core/java/android/view/ViewRootImpl.java41
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java167
-rw-r--r--core/java/android/webkit/FindActionModeCallback.java8
-rw-r--r--core/java/android/webkit/SelectActionModeCallback.java25
-rw-r--r--core/java/android/webkit/WebTextView.java7
-rw-r--r--core/java/android/webkit/WebView.java42
-rw-r--r--core/java/android/widget/ActivityChooserView.java46
-rw-r--r--core/java/android/widget/AdapterView.java22
-rw-r--r--core/java/android/widget/AnalogClock.java10
-rw-r--r--core/java/android/widget/Gallery.java10
-rw-r--r--core/java/android/widget/HorizontalScrollView.java10
-rw-r--r--core/java/android/widget/ScrollView.java10
-rw-r--r--core/java/android/widget/ShareActionProvider.java6
-rw-r--r--core/java/android/widget/SpellChecker.java87
-rw-r--r--core/java/android/widget/TextView.java118
-rw-r--r--core/java/android/widget/TimePicker.java4
-rw-r--r--core/java/com/android/internal/view/StandaloneActionMode.java8
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java58
48 files changed, 896 insertions, 339 deletions
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 51c6f3a..24d3a6b 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -43,15 +43,18 @@ import android.widget.SpinnerAdapter;
* modify various characteristics of the action bar or remove it completely.</p>
* <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
* android.app.Activity#getActionBar getActionBar()}.</p>
- * <p>For information about how to use the action bar, including how to add action items, navigation
- * modes and more, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action
- * Bar</a> developer guide.</p>
* <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,
* using an {@link android.view.ActionMode}. For example, when the user selects one or more items in
* your activity, you can enable an action mode that offers actions specific to the selected
* items, with a UI that temporarily replaces the action bar. Although the UI may occupy the
* same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for
* {@link ActionBar}.
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to use the action bar, including how to add action items, navigation
+ * modes and more, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action
+ * Bar</a> developer guide.</p>
+ * </div>
*/
public abstract class ActionBar {
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 034e3c7..8e8d37d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -111,18 +111,6 @@ import java.util.HashMap;
* {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
* declaration in their package's <code>AndroidManifest.xml</code>.</p>
*
- * <p>The Activity class is an important part of an application's overall lifecycle,
- * and the way activities are launched and put together is a fundamental
- * part of the platform's application model. For a detailed perspective on the structure of an
- * Android application and how activities behave, please read the
- * <a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a> and
- * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
- * documents.</p>
- *
- * <p>You can also find a detailed discussion about how to create activities in the
- * <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>
- * document.</p>
- *
* <p>Topics covered here:
* <ol>
* <li><a href="#Fragments">Fragments</a>
@@ -133,7 +121,22 @@ import java.util.HashMap;
* <li><a href="#Permissions">Permissions</a>
* <li><a href="#ProcessLifecycle">Process Lifecycle</a>
* </ol>
- *
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>The Activity class is an important part of an application's overall lifecycle,
+ * and the way activities are launched and put together is a fundamental
+ * part of the platform's application model. For a detailed perspective on the structure of an
+ * Android application and how activities behave, please read the
+ * <a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a> and
+ * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
+ * developer guides.</p>
+ *
+ * <p>You can also find a detailed discussion about how to create activities in the
+ * <a href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a>
+ * developer guide.</p>
+ * </div>
+ *
* <a name="Fragments"></a>
* <h3>Fragments</h3>
*
@@ -3246,6 +3249,7 @@ public class Activity extends ContextThemeWrapper
try {
String resolvedType = null;
if (fillInIntent != null) {
+ fillInIntent.setAllowFds(false);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -3370,6 +3374,7 @@ public class Activity extends ContextThemeWrapper
if (mParent == null) {
int result = IActivityManager.START_RETURN_INTENT_TO_CALLER;
try {
+ intent.setAllowFds(false);
result = ActivityManagerNative.getDefault()
.startActivity(mMainThread.getApplicationThread(),
intent, intent.resolveTypeIfNeeded(
@@ -3419,6 +3424,7 @@ public class Activity extends ContextThemeWrapper
public boolean startNextMatchingActivity(Intent intent) {
if (mParent == null) {
try {
+ intent.setAllowFds(false);
return ActivityManagerNative.getDefault()
.startNextMatchingActivity(mToken, intent);
} catch (RemoteException e) {
@@ -3692,6 +3698,9 @@ public class Activity extends ContextThemeWrapper
}
if (false) Log.v(TAG, "Finishing self: token=" + mToken);
try {
+ if (resultData != null) {
+ resultData.setAllowFds(false);
+ }
if (ActivityManagerNative.getDefault()
.finishActivity(mToken, resultCode, resultData)) {
mFinished = true;
@@ -3812,6 +3821,7 @@ public class Activity extends ContextThemeWrapper
int flags) {
String packageName = getPackageName();
try {
+ data.setAllowFds(false);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
IActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0776e10..99aae37 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2674,6 +2674,7 @@ public final class ActivityThread {
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
state = new Bundle();
+ state.setAllowFds(false);
mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
r.state = state;
}
@@ -2775,6 +2776,7 @@ public final class ActivityThread {
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
state = new Bundle();
+ state.setAllowFds(false);
mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
r.state = state;
} else {
@@ -3306,6 +3308,7 @@ public final class ActivityThread {
}
if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
r.state = new Bundle();
+ r.state.setAllowFds(false);
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2139704..2bf1fb7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -874,6 +874,7 @@ class ContextImpl extends Context {
try {
String resolvedType = null;
if (fillInIntent != null) {
+ fillInIntent.setAllowFds(false);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -892,6 +893,7 @@ class ContextImpl extends Context {
public void sendBroadcast(Intent intent) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, false, false);
@@ -903,6 +905,7 @@ class ContextImpl extends Context {
public void sendBroadcast(Intent intent, String receiverPermission) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, false, false);
@@ -915,6 +918,7 @@ class ContextImpl extends Context {
String receiverPermission) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermission, true, false);
@@ -946,6 +950,7 @@ class ContextImpl extends Context {
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermission,
@@ -958,6 +963,7 @@ class ContextImpl extends Context {
public void sendStickyBroadcast(Intent intent) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, false, true);
@@ -989,6 +995,7 @@ class ContextImpl extends Context {
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, null,
@@ -1005,6 +1012,7 @@ class ContextImpl extends Context {
intent.setDataAndType(intent.getData(), resolvedType);
}
try {
+ intent.setAllowFds(false);
ActivityManagerNative.getDefault().unbroadcastIntent(
mMainThread.getApplicationThread(), intent);
} catch (RemoteException e) {
@@ -1069,6 +1077,7 @@ class ContextImpl extends Context {
@Override
public ComponentName startService(Intent service) {
try {
+ service.setAllowFds(false);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()));
@@ -1086,6 +1095,7 @@ class ContextImpl extends Context {
@Override
public boolean stopService(Intent service) {
try {
+ service.setAllowFds(false);
int res = ActivityManagerNative.getDefault().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()));
@@ -1116,6 +1126,7 @@ class ContextImpl extends Context {
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
+ service.setAllowFds(false);
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
@@ -1148,6 +1159,9 @@ class ContextImpl extends Context {
public boolean startInstrumentation(ComponentName className,
String profileFile, Bundle arguments) {
try {
+ if (arguments != null) {
+ arguments.setAllowFds(false);
+ }
return ActivityManagerNative.getDefault().startInstrumentation(
className, profileFile, 0, arguments, null);
} catch (RemoteException e) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 3a08e6d..d423d98 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -162,9 +162,6 @@ final class FragmentState implements Parcelable {
* constructor to instantiate it. If the empty constructor is not available,
* a runtime exception will occur in some cases during state restore.
*
- * <p>For more documentation, also see the <a
- * href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
- *
* <p>Topics covered here:
* <ol>
* <li><a href="#OlderPlatforms">Older Platforms</a>
@@ -173,6 +170,12 @@ final class FragmentState implements Parcelable {
* <li><a href="#BackStack">Back Stack</a>
* </ol>
*
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using fragments, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * </div>
+ *
* <a name="OlderPlatforms"></a>
* <h3>Older Platforms</h3>
*
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 7a6759f..3da4f29 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -45,6 +45,12 @@ import java.util.Arrays;
/**
* Interface for interacting with {@link Fragment} objects inside of an
* {@link Activity}
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using fragments, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * </div>
*/
public abstract class FragmentManager {
/**
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index c1f3cd6..6e99899 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -2,6 +2,12 @@ package android.app;
/**
* API for performing a set of Fragment operations.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using fragments, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
+ * </div>
*/
public abstract class FragmentTransaction {
/**
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f3bc495..d7f5c55 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1375,6 +1375,7 @@ public class Instrumentation {
}
}
try {
+ intent.setAllowFds(false);
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1415,6 +1416,7 @@ public class Instrumentation {
try {
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
+ intents[i].setAllowFds(false);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
int result = ActivityManagerNative.getDefault()
@@ -1471,6 +1473,7 @@ public class Instrumentation {
}
}
try {
+ intent.setAllowFds(false);
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 57a2695..96767ae 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -41,6 +41,12 @@ import android.os.Message;
* long as necessary (and will not block the application's main loop), but
* only one request will be processed at a time.
*
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For a detailed discussion about how to create services, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
+ * </div>
+ *
* @see android.os.AsyncTask
*/
public abstract class IntentService extends Service {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 2549c84..522f477 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -661,6 +661,9 @@ public final class LoadedApk {
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
+ if (extras != null) {
+ extras.setAllowFds(false);
+ }
mgr.finishReceiver(this, resultCode, data, extras, false);
} catch (RemoteException e) {
Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 46a008d..89e9ddd 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -47,6 +47,12 @@ import java.lang.reflect.Modifier;
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LoaderCursor.java
* fragment_cursor}
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using loaders, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p>
+ * </div>
*/
public abstract class LoaderManager {
/**
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index b4827cb..b0637a7 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -192,6 +192,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
+ intent.setAllowFds(false);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
IActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -249,6 +250,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
+ intents[i].setAllowFds(false);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
try {
@@ -287,6 +289,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
+ intent.setAllowFds(false);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
IActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -324,6 +327,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
+ intent.setAllowFds(false);
IIntentSender target =
ActivityManagerNative.getDefault().getIntentSender(
IActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index ebde6e0..35bd8c0 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -50,10 +50,6 @@ import java.io.PrintWriter;
* Threads</a>. The {@link IntentService} class is available
* as a standard implementation of Service that has its own thread where it
* schedules its work to be done.</p>
- *
- * <p>You can find a detailed discussion about how to create services in the
- * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>
- * document.</p>
*
* <p>Topics covered here:
* <ol>
@@ -64,7 +60,13 @@ import java.io.PrintWriter;
* <li><a href="#LocalServiceSample">Local Service Sample</a>
* <li><a href="#RemoteMessengerServiceSample">Remote Messenger Service Sample</a>
* </ol>
- *
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For a detailed discussion about how to create services, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
+ * </div>
+ *
* <a name="WhatIsAService"></a>
* <h3>What is a Service?</h3>
*
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 028149b..d71a8d6 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -90,7 +90,14 @@ import android.util.Slog;
* <li><a href="#Permissions">Permissions</a>
* <li><a href="#ProcessLifecycle">Process Lifecycle</a>
* </ol>
- *
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to use this class to receive and resolve intents, read the
+ * <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+ * developer guide.</p>
+ * </div>
+ *
* <a name="ReceiverLifecycle"></a>
* <h3>Receiver Lifecycle</h3>
*
@@ -366,6 +373,9 @@ public abstract class BroadcastReceiver {
mFinished = true;
try {
+ if (mResultExtras != null) {
+ mResultExtras.setAllowFds(false);
+ }
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast);
@@ -462,6 +472,7 @@ public abstract class BroadcastReceiver {
IActivityManager am = ActivityManagerNative.getDefault();
IBinder binder = null;
try {
+ service.setAllowFds(false);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()));
} catch (RemoteException e) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index f44d038..2be5153 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -55,13 +55,21 @@ import java.util.Set;
* {@link android.content.Context#bindService} to communicate with a
* background {@link android.app.Service}.
*
- * <p>An Intent provides a facility for performing late runtime binding between
- * the code in different applications. Its most significant use is in the
- * launching of activities, where it can be thought of as the glue between
- * activities. It is
- * basically a passive data structure holding an abstract description of an
- * action to be performed. The primary pieces of information in an intent
- * are:</p>
+ * <p>An Intent provides a facility for performing late runtime binding between the code in
+ * different applications. Its most significant use is in the launching of activities, where it
+ * can be thought of as the glue between activities. It is basically a passive data structure
+ * holding an abstract description of an action to be performed.</p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to create and resolve intents, read the
+ * <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+ * developer guide.</p>
+ * </div>
+ *
+ * <a name="IntentStructure"></a>
+ * <h3>Intent Structure</h3>
+ * <p>The primary pieces of information in an intent are:</p>
*
* <ul>
* <li> <p><b>action</b> -- The general action to be performed, such as
@@ -3568,6 +3576,13 @@ public class Intent implements Parcelable, Cloneable {
return mExtras != null && mExtras.hasFileDescriptors();
}
+ /** @hide */
+ public void setAllowFds(boolean allowFds) {
+ if (mExtras != null) {
+ mExtras.setAllowFds(allowFds);
+ }
+ }
+
/**
* Retrieve extended data from the intent.
*
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index f9b3fd5..3b0d846 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -71,6 +71,14 @@ import java.util.Set;
* To specify a path, you also must specify both one or more authorities and
* one or more schemes it is associated with.
*
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to create and resolve intents, read the
+ * <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+ * developer guide.</p>
+ * </div>
+ *
+ * <h3>Filter Rules</h3>
* <p>A match is based on the following rules. Note that
* for an IntentFilter to match an Intent, three conditions must hold:
* the <strong>action</strong> and <strong>category</strong> must match, and
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 368c33e..b962800 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -40,8 +40,12 @@ import java.io.PrintWriter;
*
* <p>Most implementations should not derive directly from this class, but
* instead inherit from {@link AsyncTaskLoader}.</p>
- * <p>For more information, see the <a
- * href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using loaders, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p>
+ * </div>
*
* @param <D> The result returned when the load is complete
*/
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 127efa2..4225393 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -1301,7 +1301,7 @@ public class SyncManager implements OnAccountsUpdateListener {
elapsedTime = authoritySyncStats.elapsedTime;
times = authoritySyncStats.times;
- timeStr = String.format("%d/%d%%",
+ timeStr = String.format("%ds/%d%%",
elapsedTime / 1000,
elapsedTime * 100 / totalElapsedTime);
timesStr = String.format("%d/%d%%",
@@ -1309,32 +1309,30 @@ public class SyncManager implements OnAccountsUpdateListener {
times * 100 / totalTimes);
pw.printf(authorityFormat, name, timesStr, timeStr);
- if (authoritySyncStats.accountMap.size() > 1) {
- final List<AccountSyncStats> sortedAccounts =
- new ArrayList<AccountSyncStats>(
- authoritySyncStats.accountMap.values());
- Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
- @Override
- public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
- // reverse order
- int compare = Integer.compare(rhs.times, lhs.times);
- if (compare == 0) {
- compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
- }
- return compare;
+ final List<AccountSyncStats> sortedAccounts =
+ new ArrayList<AccountSyncStats>(
+ authoritySyncStats.accountMap.values());
+ Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
+ @Override
+ public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
+ // reverse order
+ int compare = Integer.compare(rhs.times, lhs.times);
+ if (compare == 0) {
+ compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
}
- });
- for (AccountSyncStats stats: sortedAccounts) {
- elapsedTime = stats.elapsedTime;
- times = stats.times;
- timeStr = String.format("%d/%d%%",
- elapsedTime / 1000,
- elapsedTime * 100 / totalElapsedTime);
- timesStr = String.format("%d/%d%%",
- times,
- times * 100 / totalTimes);
- pw.printf(accountFormat, stats.name, timesStr, timeStr);
+ return compare;
}
+ });
+ for (AccountSyncStats stats: sortedAccounts) {
+ elapsedTime = stats.elapsedTime;
+ times = stats.times;
+ timeStr = String.format("%ds/%d%%",
+ elapsedTime / 1000,
+ elapsedTime * 100 / totalElapsedTime);
+ timesStr = String.format("%d/%d%%",
+ times,
+ times * 100 / totalTimes);
+ pw.printf(accountFormat, stats.name, timesStr, timeStr);
}
pw.println(separator);
}
@@ -1342,9 +1340,8 @@ public class SyncManager implements OnAccountsUpdateListener {
pw.println();
pw.println("Recent Sync History");
final String format = " %-" + maxAccount + "s %s\n";
- String lastAuthorityName = null;
- String lastAccountKey = null;
- long lastEventTime = 0;
+ final Map<String, Long> lastTimeMap = Maps.newHashMap();
+
for (int i = 0; i < N; i++) {
SyncStorageEngine.SyncHistoryItem item = items.get(i);
SyncStorageEngine.AuthorityInfo authority
@@ -1363,21 +1360,32 @@ public class SyncManager implements OnAccountsUpdateListener {
final long eventTime = item.eventTime;
time.set(eventTime);
- pw.printf(" #%-3d: %s %8s %5.1fs",
- i + 1,
- formatTime(eventTime),
- SyncStorageEngine.SOURCES[item.source],
- ((float) elapsedTime) / 1000);
- if (authorityName.equals(lastAuthorityName) && accountKey.equals(lastAccountKey)) {
- final long span = (lastEventTime - eventTime) / 1000;
- pw.printf(" %02d:%02d\n", span / 60, span % 60);
+ final String key = authorityName + "/" + accountKey;
+ final Long lastEventTime = lastTimeMap.get(key);
+ final String diffString;
+ if (lastEventTime == null) {
+ diffString = "";
} else {
- pw.printf(format, accountKey, authorityName);
+ final long diff = (lastEventTime - eventTime) / 1000;
+ if (diff < 60) {
+ diffString = String.valueOf(diff);
+ } else if (diff < 3600) {
+ diffString = String.format("%02d:%02d", diff / 60, diff % 60);
+ } else {
+ final long sec = diff % 3600;
+ diffString = String.format("%02d:%02d:%02d",
+ diff / 3600, sec / 60, sec % 60);
+ }
}
+ lastTimeMap.put(key, eventTime);
- lastAuthorityName = authorityName;
- lastAccountKey = accountKey;
- lastEventTime = eventTime;
+ pw.printf(" #%-3d: %s %8s %5.1fs %8s",
+ i + 1,
+ formatTime(eventTime),
+ SyncStorageEngine.SOURCES[item.source],
+ ((float) elapsedTime) / 1000,
+ diffString);
+ pw.printf(format, accountKey, authorityName);
if (item.event != SyncStorageEngine.EVENT_STOP
|| item.upstreamActivity != 0
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index 79c9395..fc6a44a 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -336,17 +336,17 @@ public class DhcpStateMachine extends StateMachine {
DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
if (dhcpAction == DhcpAction.START) {
- Log.d(TAG, "DHCP request on " + mInterfaceName);
+ if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
mDhcpInfo = dhcpInfoInternal;
} else if (dhcpAction == DhcpAction.RENEW) {
- Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+ if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
dhcpInfoInternal.updateFromDhcpRequest(mDhcpInfo);
}
if (success) {
- Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
+ if (DBG) Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
long leaseDuration = dhcpInfoInternal.leaseDuration; //int to long conversion
//Sanity check for renewal
@@ -366,7 +366,7 @@ public class DhcpStateMachine extends StateMachine {
mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
.sendToTarget();
} else {
- Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " +
+ Log.e(TAG, "DHCP failed on " + mInterfaceName + ": " +
NetworkUtils.getDhcpError());
NetworkUtils.stopDhcp(mInterfaceName);
mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
index 3291e6b..11acabe 100644
--- a/core/java/android/net/DnsPinger.java
+++ b/core/java/android/net/DnsPinger.java
@@ -22,7 +22,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.util.Protocol;
@@ -51,7 +51,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* @hide
*/
public final class DnsPinger extends Handler {
- private static final boolean V = true;
+ private static final boolean DBG = false;
private static final int RECEIVE_POLL_INTERVAL_MS = 200;
private static final int DNS_PORT = 53;
@@ -154,7 +154,7 @@ public final class DnsPinger extends Handler {
newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
getCurrentLinkProperties().getInterfaceName()));
} catch (Exception e) {
- Slog.w(TAG,"sendDnsPing::Error binding to socket", e);
+ loge("sendDnsPing::Error binding to socket " + e);
}
newActivePing.packetId = (short) sRandom.nextInt();
@@ -165,8 +165,8 @@ public final class DnsPinger extends Handler {
// Send the DNS query
DatagramPacket packet = new DatagramPacket(buf,
buf.length, dnsAddress, DNS_PORT);
- if (V) {
- Slog.v(TAG, "Sending a ping " + newActivePing.internalId +
+ if (DBG) {
+ log("Sending a ping " + newActivePing.internalId +
" to " + dnsAddress.getHostAddress()
+ " with packetId " + newActivePing.packetId + ".");
}
@@ -196,15 +196,15 @@ public final class DnsPinger extends Handler {
curPing.result =
(int) (SystemClock.elapsedRealtime() - curPing.start);
} else {
- if (V) {
- Slog.v(TAG, "response ID didn't match, ignoring packet");
+ if (DBG) {
+ log("response ID didn't match, ignoring packet");
}
}
} catch (SocketTimeoutException e) {
// A timeout here doesn't mean anything - squelsh this exception
} catch (Exception e) {
- if (V) {
- Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e);
+ if (DBG) {
+ log("DnsPinger.pingDns got socket exception: " + e);
}
curPing.result = SOCKET_EXCEPTION;
}
@@ -244,13 +244,13 @@ public final class DnsPinger extends Handler {
public List<InetAddress> getDnsList() {
LinkProperties curLinkProps = getCurrentLinkProperties();
if (curLinkProps == null) {
- Slog.e(TAG, "getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
+ loge("getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
return mDefaultDns;
}
Collection<InetAddress> dnses = curLinkProps.getDnses();
if (dnses == null || dnses.size() == 0) {
- Slog.v(TAG, "getDns::LinkProps has null dns - returning default");
+ loge("getDns::LinkProps has null dns - returning default");
return mDefaultDns;
}
@@ -277,8 +277,8 @@ public final class DnsPinger extends Handler {
}
private void sendResponse(int internalId, int externalId, int responseVal) {
- if(V) {
- Slog.d(TAG, "Responding to packet " + internalId +
+ if(DBG) {
+ log("Responding to packet " + internalId +
" externalId " + externalId +
" and val " + responseVal);
}
@@ -304,7 +304,7 @@ public final class DnsPinger extends Handler {
try {
return NetworkUtils.numericToInetAddress(dns);
} catch (IllegalArgumentException e) {
- Slog.w(TAG, "getDefaultDns::malformed default dns address");
+ loge("getDefaultDns::malformed default dns address");
return null;
}
}
@@ -323,4 +323,12 @@ public final class DnsPinger extends Handler {
0, 1, // QTYPE, set to 1 = A (host address)
0, 1 // QCLASS, set to 1 = IN (internet)
};
+
+ private void log(String s) {
+ Log.d(TAG, s);
+ }
+
+ private void loge(String s) {
+ Log.e(TAG, s);
+ }
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index f3be39c..e554975 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -272,6 +272,17 @@ public class NetworkStats implements Parcelable {
}
/**
+ * Combine all values from another {@link NetworkStats} into this object.
+ */
+ public void combineAllValues(NetworkStats another) {
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < another.size; i++) {
+ entry = another.getValues(i, entry);
+ combineValues(entry);
+ }
+ }
+
+ /**
* Find first stats index that matches the requested parameters.
*/
public int findIndex(String iface, int uid, int set, int tag) {
@@ -456,6 +467,34 @@ public class NetworkStats implements Parcelable {
return result;
}
+ /**
+ * Return total statistics grouped by {@link #iface}; doesn't mutate the
+ * original structure.
+ */
+ public NetworkStats groupedByIface() {
+ final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
+
+ final Entry entry = new Entry();
+ entry.uid = UID_ALL;
+ entry.set = SET_ALL;
+ entry.tag = TAG_NONE;
+ entry.operations = 0L;
+
+ for (int i = 0; i < size; i++) {
+ // skip specific tags, since already counted in TAG_NONE
+ if (tag[i] != TAG_NONE) continue;
+
+ entry.iface = iface[i];
+ entry.rxBytes = rxBytes[i];
+ entry.rxPackets = rxPackets[i];
+ entry.txBytes = txBytes[i];
+ entry.txPackets = txPackets[i];
+ stats.combineValues(entry);
+ }
+
+ return stats;
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 64bba54..9dea4c4 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -42,6 +42,13 @@ import java.util.concurrent.atomic.AtomicInteger;
* and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
* <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
*
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using tasks and threads, read the
+ * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
+ * Threads</a> developer guide.</p>
+ * </div>
+ *
* <h2>Usage</h2>
* <p>AsyncTask must be subclassed to be used. The subclass will override at least
* one method ({@link #doInBackground}), and most often will override a
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c288f8a..28206b7 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -54,6 +54,7 @@ public final class Bundle implements Parcelable, Cloneable {
private boolean mHasFds = false;
private boolean mFdsKnown = true;
+ private boolean mAllowFds = true;
/**
* The ClassLoader used when unparcelling data from mParcelledData.
@@ -186,7 +187,14 @@ public final class Bundle implements Parcelable, Cloneable {
public ClassLoader getClassLoader() {
return mClassLoader;
}
-
+
+ /** @hide */
+ public boolean setAllowFds(boolean allowFds) {
+ boolean orig = mAllowFds;
+ mAllowFds = allowFds;
+ return orig;
+ }
+
/**
* Clones the current Bundle. The internal map is cloned, but the keys and
* values to which it refers are copied by reference.
@@ -1589,24 +1597,29 @@ public final class Bundle implements Parcelable, Cloneable {
* @param parcel The parcel to copy this bundle to.
*/
public void writeToParcel(Parcel parcel, int flags) {
- if (mParcelledData != null) {
- int length = mParcelledData.dataSize();
- parcel.writeInt(length);
- parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
- parcel.appendFrom(mParcelledData, 0, length);
- } else {
- parcel.writeInt(-1); // dummy, will hold length
- parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
-
- int oldPos = parcel.dataPosition();
- parcel.writeMapInternal(mMap);
- int newPos = parcel.dataPosition();
-
- // Backpatch length
- parcel.setDataPosition(oldPos - 8);
- int length = newPos - oldPos;
- parcel.writeInt(length);
- parcel.setDataPosition(newPos);
+ final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
+ try {
+ if (mParcelledData != null) {
+ int length = mParcelledData.dataSize();
+ parcel.writeInt(length);
+ parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+ parcel.appendFrom(mParcelledData, 0, length);
+ } else {
+ parcel.writeInt(-1); // dummy, will hold length
+ parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+
+ int oldPos = parcel.dataPosition();
+ parcel.writeMapInternal(mMap);
+ int newPos = parcel.dataPosition();
+
+ // Backpatch length
+ parcel.setDataPosition(oldPos - 8);
+ int length = newPos - oldPos;
+ parcel.writeInt(length);
+ parcel.setDataPosition(newPos);
+ }
+ } finally {
+ parcel.restoreAllowFds(oldAllowFds);
}
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e9ed676..15e3af4 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -323,6 +323,12 @@ public final class Parcel {
*/
public final native void setDataCapacity(int size);
+ /** @hide */
+ public final native boolean pushAllowFds(boolean allowFds);
+
+ /** @hide */
+ public final native void restoreAllowFds(boolean lastValue);
+
/**
* Returns the raw bytes of the parcel.
*
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 886edaf..6d14dfc 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -238,6 +238,14 @@ public class CallLog {
public static final String CACHED_PHOTO_ID = "photo_id";
/**
+ * The cached formatted phone number.
+ * This value is not guaranteed to be present.
+ * <P>Type: TEXT</P>
+ * @hide
+ */
+ public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
+
+ /**
* Adds a call to the call log.
*
* @param ci the CallerInfo object to get the target contact from. Can be null
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index d26364e..da7c489 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -77,6 +77,12 @@ final class BluetoothAdapterStateMachine extends StateMachine {
static final int PER_PROCESS_TURN_ON = 3;
static final int PER_PROCESS_TURN_OFF = 4;
+ // Turn on Bluetooth Module, Load firmware, and do all the preparation
+ // needed to get the Bluetooth Module ready but keep it not discoverable
+ // and not connectable. This way the Bluetooth Module can be quickly
+ // switched on if needed
+ static final int TURN_HOT = 5;
+
// Message(what) to report a event that the state machine need to respond to
//
// Event indicates sevice records have been loaded
@@ -94,23 +100,18 @@ final class BluetoothAdapterStateMachine extends StateMachine {
// private internal messages
//
- // Turn on Bluetooth Module, Load firmware, and do all the preparation
- // needed to get the Bluetooth Module ready but keep it not discoverable
- // and not connectable. This way the Bluetooth Module can be quickly
- // switched on if needed
- private static final int TURN_HOT = 101;
// USER_TURN_ON is changed to TURN_ON_CONTINUE after we broadcast the
// state change intent so that we will not broadcast the intent again in
// other state
- private static final int TURN_ON_CONTINUE = 102;
+ private static final int TURN_ON_CONTINUE = 101;
// Unload firmware, turning off Bluetooth module power
- private static final int TURN_COLD = 103;
+ private static final int TURN_COLD = 102;
// Device disconnecting timeout happens
- private static final int DEVICES_DISCONNECT_TIMEOUT = 104;
+ private static final int DEVICES_DISCONNECT_TIMEOUT = 103;
// Prepare Bluetooth timeout happens
- private static final int PREPARE_BLUETOOTH_TIMEOUT = 105;
+ private static final int PREPARE_BLUETOOTH_TIMEOUT = 104;
// Bluetooth Powerdown timeout happens
- private static final int POWER_DOWN_TIMEOUT = 106;
+ private static final int POWER_DOWN_TIMEOUT = 105;
private Context mContext;
private BluetoothService mBluetoothService;
@@ -156,11 +157,6 @@ final class BluetoothAdapterStateMachine extends StateMachine {
setInitialState(mPowerOff);
mPublicState = BluetoothAdapter.STATE_OFF;
-
- if (mContext.getResources().getBoolean
- (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
- sendMessage(TURN_HOT);
- }
}
/**
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 63da926..9ca5847 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -313,6 +313,10 @@ public class BluetoothService extends IBluetooth.Stub {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter);
mBluetoothState.start();
+ if (mContext.getResources().getBoolean
+ (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
+ mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT);
+ }
mEventLoop = mBluetoothState.getBluetoothEventLoop();
}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index e954983..34e7d4d 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -153,6 +153,18 @@ public abstract class ActionMode {
public abstract MenuInflater getMenuInflater();
/**
+ * Returns whether the UI presenting this action mode can take focus or not.
+ * This is used by internal components within the framework that would otherwise
+ * present an action mode UI that requires focus, such as an EditText as a custom view.
+ *
+ * @return true if the UI used to show this action mode can take focus
+ * @hide Internal use only
+ */
+ public boolean isUiFocusable() {
+ return true;
+ }
+
+ /**
* Callback interface for action modes. Supplied to
* {@link View#startActionMode(Callback)}, a Callback
* configures and handles events raised by a user's interaction with an action mode.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d193d6e..8e5aefd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -94,20 +94,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
* their layout properties.
* </p>
*
- * <div class="special">
- * <p>For an introduction to using this class to develop your
- * application's user interface, read the Developer Guide documentation on
- * <strong><a href="{@docRoot}guide/topics/ui/index.html">User Interface</a></strong>. Special topics
- * include:
- * <br/><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>
- * <br/><a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>
- * <br/><a href="{@docRoot}guide/topics/ui/layout-objects.html">Common Layout Objects</a>
- * <br/><a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a>
- * <br/><a href="{@docRoot}guide/topics/ui/ui-events.html">Handling UI Events</a>
- * <br/><a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a>
- * <br/><a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>
- * <br/><a href="{@docRoot}guide/topics/ui/how-android-draws.html">How Android Draws Views</a>.
- * </p>
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about using this class to develop your application's user interface,
+ * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide.
* </div>
*
* <a name="Using"></a>
@@ -1487,6 +1477,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * Accessibility event types that are dispatched for text population.
+ */
+ private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES =
+ AccessibilityEvent.TYPE_VIEW_CLICKED
+ | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
+ | AccessibilityEvent.TYPE_VIEW_SELECTED
+ | AccessibilityEvent.TYPE_VIEW_FOCUSED
+ | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+ | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
+ | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT;
+
+ /**
* Temporary Rect currently for use in setBackground(). This will probably
* be extended in the future to hold our own class with more than just
* a Rect. :)
@@ -3855,7 +3857,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
return;
}
onInitializeAccessibilityEvent(event);
- dispatchPopulateAccessibilityEvent(event);
+ // Only a subset of accessibility events populates text content.
+ if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) {
+ dispatchPopulateAccessibilityEvent(event);
+ }
// In the beginning we called #isShown(), so we know that getParent() is not null.
getParent().requestSendAccessibilityEvent(this, event);
}
@@ -3876,6 +3881,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)}
* is responsible for handling this call.
* </p>
+ * <p>
+ * <em>Note:</em> Accessibility events of certain types are not dispatched for
+ * populating the event text via this method. For details refer to {@link AccessibilityEvent}.
+ * </p>
*
* @param event The event.
*
@@ -3895,12 +3904,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Note: Called from the default {@link AccessibilityDelegate}.
*/
boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
- // Do not populate text to scroll events. They describe position change
- // and usually come from container with a lot of text which is not very
- // informative for accessibility purposes. Also they are fired frequently.
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- return true;
- }
onPopulateAccessibilityEvent(event);
return false;
}
@@ -12093,6 +12096,39 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * Finds a view by its unuque and stable accessibility id.
+ *
+ * @param accessibilityId The searched accessibility id.
+ * @return The found view.
+ */
+ final View findViewByAccessibilityId(int accessibilityId) {
+ if (accessibilityId < 0) {
+ return null;
+ }
+ return findViewByAccessibilityIdTraversal(accessibilityId);
+ }
+
+ /**
+ * Performs the traversal to find a view by its unuque and stable accessibility id.
+ *
+ * <strong>Note:</strong>This method does not stop at the root namespace
+ * boundary since the user can touch the screen at an arbitrary location
+ * potentially crossing the root namespace bounday which will send an
+ * accessibility event to accessibility services and they should be able
+ * to obtain the event source. Also accessibility ids are guaranteed to be
+ * unique in the window.
+ *
+ * @param accessibilityId The accessibility id.
+ * @return The found view.
+ */
+ View findViewByAccessibilityIdTraversal(int accessibilityId) {
+ if (getAccessibilityViewId() == accessibilityId) {
+ return this;
+ }
+ return null;
+ }
+
+ /**
* Look for a child view with the given tag. If this view has the given
* tag, return this view.
*
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index fb0d80a..5b4a6f8 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -821,6 +821,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
+ @Override
+ View findViewByAccessibilityIdTraversal(int accessibilityId) {
+ View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
+ if (foundView != null) {
+ return foundView;
+ }
+ final int childrenCount = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < childrenCount; i++) {
+ View child = children[i];
+ foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
+ if (foundView != null) {
+ return foundView;
+ }
+ }
+ return null;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9cb4e5e..e7c91f9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -74,7 +74,6 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
import com.android.internal.policy.PolicyManager;
-import com.android.internal.util.Predicate;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.IInputMethodCallback;
import com.android.internal.view.IInputMethodSession;
@@ -4462,9 +4461,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
final class AccessibilityInteractionController {
private static final int POOL_SIZE = 5;
- private FindByAccessibilitytIdPredicate mFindByAccessibilityIdPredicate =
- new FindByAccessibilitytIdPredicate();
-
private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
new ArrayList<AccessibilityNodeInfo>();
@@ -4551,11 +4547,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
AccessibilityNodeInfo info = null;
try {
- FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate;
- predicate.init(accessibilityId);
- View root = ViewRootImpl.this.mView;
- View target = root.findViewByPredicate(predicate);
- if (target != null && target.getVisibility() == View.VISIBLE) {
+ View target = findViewByAccessibilityId(accessibilityId);
+ if (target != null) {
info = target.createAccessibilityNodeInfo();
}
} finally {
@@ -4794,25 +4787,12 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (root == null) {
return null;
}
- mFindByAccessibilityIdPredicate.init(accessibilityId);
- View foundView = root.findViewByPredicate(mFindByAccessibilityIdPredicate);
- if (foundView == null || foundView.getVisibility() != View.VISIBLE) {
+ View foundView = root.findViewByAccessibilityId(accessibilityId);
+ if (foundView != null && foundView.getVisibility() != View.VISIBLE) {
return null;
}
return foundView;
}
-
- private final class FindByAccessibilitytIdPredicate implements Predicate<View> {
- public int mSearchedId;
-
- public void init(int searchedId) {
- mSearchedId = searchedId;
- }
-
- public boolean apply(View view) {
- return (view.getAccessibilityViewId() == mSearchedId);
- }
- }
}
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
@@ -4820,18 +4800,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
public void run() {
if (mView != null) {
- // Check again for accessibility state since this is executed delayed.
- AccessibilityManager accessibilityManager =
- AccessibilityManager.getInstance(mView.mContext);
- if (accessibilityManager.isEnabled()) {
- // Send the event directly since we do not want to append the
- // source text because this is the text for the entire window
- // and we just want to notify that the content has changed.
- AccessibilityEvent event = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- mView.onInitializeAccessibilityEvent(event);
- accessibilityManager.sendAccessibilityEvent(event);
- }
+ mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
mIsPending = false;
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index c93b564..91fbb0e 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -69,14 +69,16 @@ import java.util.List;
* <em>Type:</em>{@link #TYPE_VIEW_CLICKED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
* </p>
* <p>
@@ -85,14 +87,16 @@ import java.util.List;
* <em>Type:</em>{@link #TYPE_VIEW_LONG_CLICKED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
* </p>
* <p>
@@ -101,16 +105,18 @@ import java.util.List;
* <em>Type:</em> {@link #TYPE_VIEW_SELECTED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
* <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
* <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
* </p>
* <p>
@@ -119,16 +125,18 @@ import java.util.List;
* <em>Type:</em> {@link #TYPE_VIEW_FOCUSED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
* <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
* <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
* </p>
* <p>
@@ -137,6 +145,7 @@ import java.util.List;
* <em>Type:</em> {@link #TYPE_VIEW_TEXT_CHANGED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
@@ -149,7 +158,17 @@ import java.util.List;
* <li>{@link #getAddedCount()} - The number of added characters.</li>
* <li>{@link #getRemovedCount()} - The number of removed characters.</li>
* <li>{@link #getBeforeText()} - The text of the source before the change.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
* </p>
* <p>
* <b>View text selection changed</b> - represents the event of changing the text
@@ -157,35 +176,47 @@ import java.util.List;
* <em>Type:</em> {@link #TYPE_VIEW_TEXT_SELECTION_CHANGED} </br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
* <li>{@link #getText()} - The text of the source.</li>
- * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #getFromIndex()} - The selection start index.</li>
* <li>{@link #getToIndex()} - The selection end index.</li>
* <li>{@link #getItemCount()} - The length of the source text.</li>
+ * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
* </p>
* <p>
* <b>View scrolled</b> - represents the event of scrolling a view. If
* the source is a descendant of {@link android.widget.AdapterView} the
* scroll is reported in terms of visible items - the first visible item,
* the last visible item, and the total items - because the the source
- * is unaware if its pixel size since its adapter is responsible for
+ * is unaware of its pixel size since its adapter is responsible for
* creating views. In all other cases the scroll is reported as the current
* scroll on the X and Y axis respectively plus the height of the source in
* pixels.</br>
* <em>Type:</em> {@link #TYPE_VIEW_SCROLLED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #getScrollX()} - The horizontal offset of the source
* (without descendants of AdapterView)).</li>
@@ -197,56 +228,165 @@ import java.util.List;
* (for descendants of AdapterView).</li>
* <li>{@link #getItemCount()} - The total items of the source (for descendants of AdapterView)
* or the height of the source in pixels (all other cases).</li>
+ * <li>{@link #getText()} - Text for providing more context.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
* </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
* </p>
* <p>
* <b>TRANSITION TYPES</b></br>
* </p>
+ * <p>
* <b>Window state changed</b> - represents the event of opening a
* {@link android.widget.PopupWindow}, {@link android.view.Menu},
* {@link android.app.Dialog}, etc.</br>
* <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
+ * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* </ul>
* </p>
* <p>
* <b>Window content changed</b> - represents the event of change in the
* content of a window. This change can be adding/removing view, changing
* a view size, etc.</br>
+ * </p>
* <p>
* <strong>Note:</strong> This event is fired only for the window source of the
- * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED})
+ * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED}
* and its purpose is to notify clients that the content of the user interaction
- * window has changed.
- * </p>
+ * window has changed.</br>
* <em>Type:</em> {@link #TYPE_WINDOW_CONTENT_CHANGED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
* </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
+ * </p>
* <p>
* <b>NOTIFICATION TYPES</b></br>
+ * </p>
* <p>
* <b>Notification state changed</b> - represents the event showing
- * {@link android.app.Notification}.
+ * {@link android.app.Notification}.</br>
* <em>Type:</em> {@link #TYPE_NOTIFICATION_STATE_CHANGED}</br>
* <em>Properties:</em></br>
* <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <li>{@link #getText()} - The text of the source.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
* <li>{@link #getParcelableData()} - The posted {@link android.app.Notification}.</li>
+ * <li>{@link #getText()} - Text for providing more context.</li>
* </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
+ * </p>
+ * <p>
+ * <b>EXPLORATION TYPES</b></br>
+ * </p>
+ * <p>
+ * <b>View hover enter</b> - represents the event of beginning to hover
+ * over a {@link android.view.View}. The hover may be generated via
+ * exploring the screen by touch or via a pointing device.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_HOVER_ENTER}</br>
+ * <em>Properties:</em></br>
+ * <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
+ * <li>{@link #getClassName()} - The class name of the source.</li>
+ * <li>{@link #getPackageName()} - The package name of the source.</li>
+ * <li>{@link #getEventTime()} - The event time.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
+ * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
+ * </ul>
+ * </p>
+ * <b>View hover exit</b> - represents the event of stopping to hover
+ * over a {@link android.view.View}. The hover may be generated via
+ * exploring the screen by touch or via a pointing device.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_HOVER_EXIT}</br>
+ * <em>Properties:</em></br>
+ * <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
+ * <li>{@link #getClassName()} - The class name of the source.</li>
+ * <li>{@link #getPackageName()} - The package name of the source.</li>
+ * <li>{@link #getEventTime()} - The event time.</li>
+ * <li>{@link #getText()} - The text of the source's sub-tree.</li>
+ * <li>{@link #isEnabled()} - Whether the source is enabled.</li>
+ * <li>{@link #getContentDescription()} - The content description of the source.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * <b>Touch exploration gesture start</b> - represents the event of starting a touch
+ * exploring gesture.</br>
+ * <em>Type:</em> {@link #TYPE_TOUCH_EXPLORATION_GESTURE_START}</br>
+ * <em>Properties:</em></br>
+ * <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
+ * </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
+ * </p>
+ * <p>
+ * <b>Touch exploration gesture end</b> - represents the event of ending a touch
+ * exploring gesture.</br>
+ * <em>Type:</em> {@link #TYPE_TOUCH_EXPLORATION_GESTURE_END}</br>
+ * <em>Properties:</em></br>
+ * <ul>
+ * <li>{@link #getEventType()} - The type of the event.</li>
+ * </ul>
+ * <em>Note:</em> This event type is not dispatched to descendants though
+ * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
+ * source {@link android.view.View} and the sub-tree rooted at it will not receive
+ * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
+ * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
+ * text content to such events is by setting the
+ * {@link android.R.styleable#View_contentDescription contentDescription} of the source
+ * view.</br>
* </p>
* <p>
* <b>Security note</b>
@@ -254,6 +394,7 @@ import java.util.List;
* Since an event contains the text of its source privacy can be compromised by leaking
* sensitive information such as passwords. To address this issue any event fired in response
* to manipulation of a PASSWORD field does NOT CONTAIN the text of the password.
+ * </p>
*
* @see android.view.accessibility.AccessibilityManager
* @see android.accessibilityservice.AccessibilityService
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index a322fa3..7398262 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -180,6 +180,14 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ if (!mode.isUiFocusable()) {
+ // If the action mode we're running in is not focusable the user
+ // will not be able to type into the find on page field. This
+ // should only come up when we're running in a dialog which is
+ // already less than ideal; disable the option for now.
+ return false;
+ }
+
mode.setCustomView(mCustomView);
mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_find,
menu);
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index 104deb1..8c174aa 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -17,13 +17,12 @@
package android.webkit;
import android.app.SearchManager;
+import android.content.Context;
import android.content.Intent;
import android.provider.Browser;
-import android.webkit.WebView;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
class SelectActionModeCallback implements ActionMode.Callback {
private WebView mWebView;
@@ -45,9 +44,25 @@ class SelectActionModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy,
- menu);
- mode.setTitle(com.android.internal.R.string.textSelectionCABTitle);
+ mode.getMenuInflater().inflate(com.android.internal.R.menu.webview_copy, menu);
+
+ final Context context = mWebView.getContext();
+ boolean allowText = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
+ mode.setTitle(allowText ?
+ context.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
+
+ if (!mode.isUiFocusable()) {
+ // If the action mode UI we're running in isn't capable of taking window focus
+ // the user won't be able to type into the find on page UI. Disable this functionality.
+ // (Note that this should only happen in floating dialog windows.)
+ // This can be removed once we can handle multiple focusable windows at a time
+ // in a better way.
+ final MenuItem findOnPageItem = menu.findItem(com.android.internal.R.id.find);
+ if (findOnPageItem != null) {
+ findOnPageItem.setVisible(false);
+ }
+ }
mActionMode = mode;
return true;
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 217ad7c..092e2b5 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -1092,4 +1092,11 @@ import junit.framework.Assert;
return url != null ? url.getProtocol() + "://" + url.getHost() + url.getPath() : null;
}
+
+ public void setGravityForRtl(boolean rtl) {
+ int gravity = rtl ? Gravity.RIGHT : Gravity.LEFT;
+ gravity |= mSingle ? Gravity.CENTER_VERTICAL : Gravity.TOP;
+ setGravity(gravity);
+ }
+
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 370cce4..eaed9fe 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4078,8 +4078,8 @@ public class WebView extends AbsoluteLayout
boolean pressed = (mTouchMode == TOUCH_SHORTPRESS_START_MODE
|| mTouchMode == TOUCH_INIT_MODE
|| mTouchMode == TOUCH_SHORTPRESS_MODE);
- nativeRecordButtons(hasFocus() && hasWindowFocus(),
- (pressed && !USE_WEBKIT_RINGS)
+ recordButtons(canvas,
+ hasFocus() && hasWindowFocus(), (pressed && !USE_WEBKIT_RINGS)
|| mTrackballDown || mGotCenterDown, false);
drawCoreAndCursorRing(canvas, mBackgroundColor,
mDrawCursorRing && drawRings);
@@ -4760,12 +4760,12 @@ public class WebView extends AbsoluteLayout
}
String text = nativeFocusCandidateText();
int nodePointer = nativeFocusCandidatePointer();
- mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
- Gravity.RIGHT : Gravity.NO_GRAVITY);
// This needs to be called before setType, which may call
// requestFormData, and it needs to have the correct nodePointer.
mWebTextView.setNodePointer(nodePointer);
mWebTextView.setType(nativeFocusCandidateType());
+ // Gravity needs to be set after setType
+ mWebTextView.setGravityForRtl(nativeFocusCandidateIsRtlText());
updateWebTextViewPadding();
if (null == text) {
if (DebugFlags.WEB_VIEW) {
@@ -5133,7 +5133,7 @@ public class WebView extends AbsoluteLayout
.obtainMessage(LONG_PRESS_CENTER), LONG_PRESS_TIMEOUT);
// Already checked mNativeClass, so we do not need to check it
// again.
- nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+ recordButtons(null, hasFocus() && hasWindowFocus(), true, true);
if (!wantsKeyEvents) return true;
}
// Bubble up the key event as WebView doesn't handle it
@@ -5561,7 +5561,7 @@ public class WebView extends AbsoluteLayout
mDrawCursorRing = true;
setFocusControllerActive(true);
if (mNativeClass != 0) {
- nativeRecordButtons(true, false, true);
+ recordButtons(null, true, false, true);
}
} else {
if (!inEditingMode()) {
@@ -5570,7 +5570,7 @@ public class WebView extends AbsoluteLayout
mDrawCursorRing = false;
setFocusControllerActive(false);
}
- // We do not call nativeRecordButtons here because we assume
+ // We do not call recordButtons here because we assume
// that when we lost focus, or window focus, it got called with
// false for the first parameter
}
@@ -5589,7 +5589,7 @@ public class WebView extends AbsoluteLayout
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mTouchMode = TOUCH_DONE_MODE;
if (mNativeClass != 0) {
- nativeRecordButtons(false, false, true);
+ recordButtons(null, false, false, true);
}
setFocusControllerActive(false);
}
@@ -5647,13 +5647,13 @@ public class WebView extends AbsoluteLayout
if (hasWindowFocus()) {
mDrawCursorRing = true;
if (mNativeClass != 0) {
- nativeRecordButtons(true, false, true);
+ recordButtons(null, true, false, true);
}
setFocusControllerActive(true);
//} else {
// The WebView has gained focus while we do not have
// windowfocus. When our window lost focus, we should have
- // called nativeRecordButtons(false...)
+ // called recordButtons(false...)
}
} else {
// When we lost focus, unless focus went to the TextView (which is
@@ -5661,7 +5661,7 @@ public class WebView extends AbsoluteLayout
if (!inEditingMode()) {
mDrawCursorRing = false;
if (mNativeClass != 0) {
- nativeRecordButtons(false, false, true);
+ recordButtons(null, false, false, true);
}
setFocusControllerActive(false);
}
@@ -6762,7 +6762,7 @@ public class WebView extends AbsoluteLayout
if (mNativeClass == 0) {
return false;
}
- nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+ recordButtons(null, hasFocus() && hasWindowFocus(), true, true);
if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
&& !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
nativeSelectBestAt(mLastCursorBounds);
@@ -9349,6 +9349,24 @@ public class WebView extends AbsoluteLayout
return nativeTileProfilingGetFloat(frame, tile, key);
}
+ /**
+ * Helper method to deal with differences between hardware and software rendering
+ */
+ private void recordButtons(Canvas canvas, boolean focus, boolean pressed,
+ boolean inval) {
+ boolean isHardwareAccel = canvas != null
+ ? canvas.isHardwareAccelerated()
+ : isHardwareAccelerated();
+ if (isHardwareAccel) {
+ // We never want to change button state if we are hardware accelerated,
+ // but we DO want to invalidate as necessary so that the GL ring
+ // can be drawn
+ nativeRecordButtons(false, false, inval);
+ } else {
+ nativeRecordButtons(focus, pressed, inval);
+ }
+ }
+
private native int nativeCacheHitFramePointer();
private native boolean nativeCacheHitIsPlugin();
private native Rect nativeCacheHitNodeBounds();
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index c37cc52..60b24bc 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -33,6 +33,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
/**
@@ -169,6 +171,11 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
private boolean mIsAttachedToWindow;
/**
+ * String resource for formatting content description of the default target.
+ */
+ private int mDefaultActionButtonContentDescription;
+
+ /**
* Create a new instance.
*
* @param context The application environment.
@@ -259,7 +266,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
*
* <strong>Note:</strong> Clients would like to set this drawable
* as a clue about the action the chosen activity will perform. For
- * example, if share activity is to be chosen the drawable should
+ * example, if a share activity is to be chosen the drawable should
* give a clue that sharing is to be performed.
*
* @param drawable The drawable.
@@ -269,6 +276,21 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
/**
+ * Sets the content description for the button that expands the activity
+ * overflow list.
+ *
+ * description as a clue about the action performed by the button.
+ * For example, if a share activity is to be chosen the content
+ * description should be something like "Share with".
+ *
+ * @param resourceId The content description resource id.
+ */
+ public void setExpandActivityOverflowButtonContentDescription(int resourceId) {
+ CharSequence contentDescription = mContext.getString(resourceId);
+ mExpandActivityOverflowButtonImage.setContentDescription(contentDescription);
+ }
+
+ /**
* Set the provider hosting this view, if applicable.
* @hide Internal use only
*/
@@ -329,6 +351,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
if (mProvider != null) {
mProvider.subUiVisibilityChanged(true);
}
+ popupWindow.getListView().setContentDescription(mContext.getString(
+ R.string.activitychooserview_choose_application));
}
}
@@ -431,6 +455,20 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
/**
+ * Sets a content description of the default action button. This
+ * resource should be a string taking one formatting argument and
+ * will be used for formatting the content description of the button
+ * dynamically as the default target changes. For example, a resource
+ * pointing to the string "share with %1$s" will result in a content
+ * description "share with Bluetooth" for the Bluetooth activity.
+ *
+ * @param resourceId The resource id.
+ */
+ public void setDefaultActionButtonContentDescription(int resourceId) {
+ mDefaultActionButtonContentDescription = resourceId;
+ }
+
+ /**
* Gets the list popup window which is lazily initialized.
*
* @return The popup.
@@ -465,6 +503,12 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
ResolveInfo activity = mAdapter.getDefaultActivity();
PackageManager packageManager = mContext.getPackageManager();
mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
+ if (mDefaultActionButtonContentDescription != 0) {
+ CharSequence label = activity.loadLabel(packageManager);
+ String contentDescription = mContext.getString(
+ mDefaultActionButtonContentDescription, label);
+ mDefaultActivityButton.setContentDescription(contentDescription);
+ }
} else {
mDefaultActivityButton.setVisibility(View.GONE);
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index a4b4e78..61c5dd4 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -881,20 +881,14 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- final int eventType = event.getEventType();
- switch (eventType) {
- case AccessibilityEvent.TYPE_VIEW_SCROLLED:
- // Do not populate the text of scroll events.
- return true;
- case AccessibilityEvent.TYPE_VIEW_FOCUSED:
- // This is an exceptional case which occurs when a window gets the
- // focus and sends a focus event via its focused child to announce
- // current focus/selection. AdapterView fires selection but not focus
- // events so we change the event type here.
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
- event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
- break;
+ if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
+ // This is an exceptional case which occurs when a window gets the
+ // focus and sends a focus event via its focused child to announce
+ // current focus/selection. AdapterView fires selection but not focus
+ // events so we change the event type here.
+ if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
+ event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ }
}
View selectedView = getSelectedView();
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 84ebec3..63a0870 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -25,6 +25,7 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
import android.view.View;
@@ -228,6 +229,8 @@ public class AnalogClock extends View {
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
+
+ updateContentDescription(mCalendar);
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -243,4 +246,11 @@ public class AnalogClock extends View {
invalidate();
}
};
+
+ private void updateContentDescription(Time time) {
+ final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
+ String contentDescription = DateUtils.formatDateTime(mContext,
+ time.toMillis(false), flags);
+ setContentDescription(contentDescription);
+ }
}
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 3f5b571..a0eba9a 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -371,16 +371,6 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
}
}
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // Do not append text content to scroll events they are fired frequently
- // and the client has already received another event type with the text.
- if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- super.dispatchPopulateAccessibilityEvent(event);
- }
- return false;
- }
-
/**
* Tracks a motion scroll. In reality, this is used to do just about any
* movement to items (touch scroll, arrow-key scroll, set an item as selected).
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 1bbc501..324dfd7 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -725,16 +725,6 @@ public class HorizontalScrollView extends FrameLayout {
event.setScrollable(true);
}
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // Do not append text content to scroll events they are fired frequently
- // and the client has already received another event type with the text.
- if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- super.dispatchPopulateAccessibilityEvent(event);
- }
- return false;
- }
-
private int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 61ea5c9..3ac4e80 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -730,16 +730,6 @@ public class ScrollView extends FrameLayout {
event.setScrollable(true);
}
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // Do not append text content to scroll events they are fired frequently
- // and the client has already received another event type with the text.
- if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- super.dispatchPopulateAccessibilityEvent(event);
- }
- return false;
- }
-
private int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 3627890..bb27b73 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -171,6 +171,12 @@ public class ShareActionProvider extends ActionProvider {
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
activityChooserView.setProvider(this);
+ // Set content description.
+ activityChooserView.setDefaultActionButtonContentDescription(
+ R.string.shareactionprovider_share_with_application);
+ activityChooserView.setExpandActivityOverflowButtonContentDescription(
+ R.string.shareactionprovider_share_with);
+
return activityChooserView;
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index ac9535a..ce17184 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -30,8 +30,6 @@ import android.view.textservice.TextServicesManager;
import com.android.internal.util.ArrayUtils;
-import java.util.Locale;
-
/**
* Helper class for TextView. Bridge between the TextView and the Dictionnary service.
@@ -174,8 +172,6 @@ public class SpellChecker implements SpellCheckerSessionListener {
final int sequenceNumber = suggestionsInfo.getSequence();
for (int j = 0; j < mLength; j++) {
- final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
-
if (sequenceNumber == mIds[j]) {
final int attributes = suggestionsInfo.getSuggestionsAttributes();
boolean isInDictionary =
@@ -183,32 +179,79 @@ public class SpellChecker implements SpellCheckerSessionListener {
boolean looksLikeTypo =
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
+ SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
if (!isInDictionary && looksLikeTypo) {
- String[] suggestions = getSuggestions(suggestionsInfo);
- SuggestionSpan suggestionSpan = new SuggestionSpan(
- mTextView.getContext(), suggestions,
- SuggestionSpan.FLAG_EASY_CORRECT |
- SuggestionSpan.FLAG_MISSPELLED);
- final int start = editable.getSpanStart(spellCheckSpan);
- final int end = editable.getSpanEnd(spellCheckSpan);
- editable.setSpan(suggestionSpan, start, end,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- // TODO limit to the word rectangle region
- mTextView.invalidate();
+ createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan);
}
editable.removeSpan(spellCheckSpan);
+ break;
}
}
}
}
- private static String[] getSuggestions(SuggestionsInfo suggestionsInfo) {
- // A negative suggestion count is possible
- final int len = Math.max(0, suggestionsInfo.getSuggestionsCount());
- String[] suggestions = new String[len];
- for (int j = 0; j < len; j++) {
- suggestions[j] = suggestionsInfo.getSuggestionAt(j);
+ private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
+ SpellCheckSpan spellCheckSpan) {
+ final int start = editable.getSpanStart(spellCheckSpan);
+ final int end = editable.getSpanEnd(spellCheckSpan);
+
+ // Other suggestion spans may exist on that region, with identical suggestions, filter
+ // them out to avoid duplicates. First, filter suggestion spans on that exact region.
+ SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
+ final int length = suggestionSpans.length;
+ for (int i = 0; i < length; i++) {
+ final int spanStart = editable.getSpanStart(suggestionSpans[i]);
+ final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
+ if (spanStart != start || spanEnd != end) {
+ suggestionSpans[i] = null;
+ break;
+ }
+ }
+
+ final int suggestionsCount = suggestionsInfo.getSuggestionsCount();
+ String[] suggestions;
+ if (suggestionsCount <= 0) {
+ // A negative suggestion count is possible
+ suggestions = ArrayUtils.emptyArray(String.class);
+ } else {
+ int numberOfSuggestions = 0;
+ suggestions = new String[suggestionsCount];
+
+ for (int i = 0; i < suggestionsCount; i++) {
+ final String spellSuggestion = suggestionsInfo.getSuggestionAt(i);
+ if (spellSuggestion == null) break;
+ boolean suggestionFound = false;
+
+ for (int j = 0; j < length && !suggestionFound; j++) {
+ if (suggestionSpans[j] == null) break;
+
+ String[] suggests = suggestionSpans[j].getSuggestions();
+ for (int k = 0; k < suggests.length; k++) {
+ if (spellSuggestion.equals(suggests[k])) {
+ // The suggestion is already provided by an other SuggestionSpan
+ suggestionFound = true;
+ break;
+ }
+ }
+ }
+
+ if (!suggestionFound) {
+ suggestions[numberOfSuggestions++] = spellSuggestion;
+ }
+ }
+
+ if (numberOfSuggestions != suggestionsCount) {
+ String[] newSuggestions = new String[numberOfSuggestions];
+ System.arraycopy(suggestions, 0, newSuggestions, 0, numberOfSuggestions);
+ suggestions = newSuggestions;
+ }
}
- return suggestions;
+
+ SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
+ SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
+ editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ // TODO limit to the word rectangle region
+ mTextView.invalidate();
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5cd7902..17f0e05 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -353,6 +353,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Set when this TextView gained focus with some text selected. Will start selection mode.
private boolean mCreatedWithASelection = false;
+ // Size of the window for the word iterator, should be greater than the longest word's length
+ private static final int WORD_ITERATOR_WINDOW_WIDTH = 50;
private WordIterator mWordIterator;
private SpellChecker mSpellChecker;
@@ -2937,11 +2939,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Spannable sp = new SpannableString(mText);
- for (ChangeWatcher cw :
- sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
+ for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
sp.removeSpan(cw);
}
+ SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);
+ for (int i = 0; i < suggestionSpans.length; i++) {
+ int flags = suggestionSpans[i].getFlags();
+ if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
+ && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+ sp.removeSpan(suggestionSpans[i]);
+ }
+ }
+
sp.removeSpan(mSuggestionRangeSpan);
ss.text = sp;
@@ -4449,7 +4459,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mSpellChecker != null) {
mSpellChecker.closeSession();
- removeMisspelledSpans();
// Forces the creation of a new SpellChecker next time this window is created.
// Will handle the cases where the settings has been changed in the meantime.
mSpellChecker = null;
@@ -7771,7 +7780,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Iterate over the newly added text and schedule new SpellCheckSpans
while (wordStart <= shiftedEnd) {
- if (wordEnd >= shiftedStart) {
+ if (wordEnd >= shiftedStart && wordEnd > wordStart) {
// A new word has been created across the interval boundaries. Remove previous spans
if (wordStart < shiftedStart && wordEnd > shiftedStart) {
removeSpansAt(start, spellCheckSpans, text);
@@ -8461,24 +8470,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- /**
- * Removes the suggestion spans for misspelled words.
- */
- private void removeMisspelledSpans() {
- if (mText instanceof Spannable) {
- Spannable spannable = (Spannable) mText;
- SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
- spannable.length(), SuggestionSpan.class);
- for (int i = 0; i < suggestionSpans.length; i++) {
- int flags = suggestionSpans[i].getFlags();
- if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
- && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
- spannable.removeSpan(suggestionSpans[i]);
- }
- }
- }
- }
-
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mMovement != null && mText instanceof Spannable && mLayout != null) {
@@ -8934,10 +8925,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// If a URLSpan (web address, email, phone...) is found at that position, select it.
URLSpan[] urlSpans = ((Spanned) mText).getSpans(minOffset, maxOffset, URLSpan.class);
- if (urlSpans.length == 1) {
- URLSpan url = urlSpans[0];
- selectionStart = ((Spanned) mText).getSpanStart(url);
- selectionEnd = ((Spanned) mText).getSpanEnd(url);
+ if (urlSpans.length >= 1) {
+ URLSpan urlSpan = urlSpans[0];
+ selectionStart = ((Spanned) mText).getSpanStart(urlSpan);
+ selectionEnd = ((Spanned) mText).getSpanEnd(urlSpan);
} else {
final int shift = prepareWordIterator(minOffset, maxOffset);
@@ -8948,10 +8939,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
selectionEnd = mWordIterator.getEnd(maxOffset - shift);
if (selectionEnd == BreakIterator.DONE) return false;
selectionEnd += shift;
+
+ if (selectionStart == selectionEnd) {
+ // Possible when the word iterator does not properly handle the text's language
+ long range = getCharRange(selectionStart);
+ selectionStart = extractRangeStartFromLong(range);
+ selectionEnd = extractRangeEndFromLong(range);
+ }
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
- return true;
+ return selectionEnd > selectionStart;
+ }
+
+ private long getCharRange(int offset) {
+ final int textLength = mText.length();
+ if (offset + 1 < textLength) {
+ final char currentChar = mText.charAt(offset);
+ final char nextChar = mText.charAt(offset + 1);
+ if (Character.isSurrogatePair(currentChar, nextChar)) {
+ return packRangeInLong(offset, offset + 2);
+ }
+ }
+ if (offset < textLength) {
+ return packRangeInLong(offset, offset + 1);
+ }
+ if (offset - 2 >= 0) {
+ final char previousChar = mText.charAt(offset - 1);
+ final char previousPreviousChar = mText.charAt(offset - 2);
+ if (Character.isSurrogatePair(previousPreviousChar, previousChar)) {
+ return packRangeInLong(offset - 2, offset);
+ }
+ }
+ if (offset - 1 >= 0) {
+ return packRangeInLong(offset - 1, offset);
+ }
+ return packRangeInLong(offset, offset);
}
int prepareWordIterator(int start, int end) {
@@ -8959,9 +8982,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mWordIterator = new WordIterator();
}
- final int TEXT_WINDOW_WIDTH = 50; // Should be larger than the longest word's length
- final int windowStart = Math.max(0, start - TEXT_WINDOW_WIDTH);
- final int windowEnd = Math.min(mText.length(), end + TEXT_WINDOW_WIDTH);
+ final int windowStart = Math.max(0, start - WORD_ITERATOR_WINDOW_WIDTH);
+ final int windowEnd = Math.min(mText.length(), end + WORD_ITERATOR_WINDOW_WIDTH);
mWordIterator.setCharSequence(mText.subSequence(windowStart, windowEnd));
return windowStart;
@@ -9340,7 +9362,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Start a new selection
if (!handled) {
- handled = startSelectionActionMode();
+ vibrate = handled = startSelectionActionMode();
}
if (vibrate) {
@@ -9930,7 +9952,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Fallback on the default highlight color when the first span does not provide one
mSuggestionRangeSpan.setBackgroundColor(mHighlightColor);
} else {
- final float BACKGROUND_TRANSPARENCY = 0.3f;
+ final float BACKGROUND_TRANSPARENCY = 0.4f;
final int newAlpha = (int) (Color.alpha(underlineColor) * BACKGROUND_TRANSPARENCY);
mSuggestionRangeSpan.setBackgroundColor(
(underlineColor & 0x00FFFFFF) + (newAlpha << 24));
@@ -9956,8 +9978,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Add the text before and after the span.
- suggestionInfo.text.insert(0, mText.subSequence(unionStart, spanStart).toString());
- suggestionInfo.text.append(mText.subSequence(spanEnd, unionEnd).toString());
+ suggestionInfo.text.insert(0, mText.toString().substring(unionStart, spanStart));
+ suggestionInfo.text.append(mText.toString().substring(spanEnd, unionEnd));
}
@Override
@@ -9989,14 +10011,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
hide();
return;
}
- final String originalText = mText.subSequence(spanStart, spanEnd).toString();
+ final String originalText = mText.toString().substring(spanStart, spanEnd);
if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
intent.putExtra("word", originalText);
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
- suggestionInfo.removeMisspelledFlag();
+ // There is no way to know if the word was indeed added. Re-check.
+ editable.removeSpan(suggestionInfo.suggestionSpan);
+ updateSpellCheckSpans(spanStart, spanEnd);
} else {
// SuggestionSpans are removed by replace: save them before
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
@@ -10024,8 +10048,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!TextUtils.isEmpty(
suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
InputMethodManager imm = InputMethodManager.peekInstance();
- imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText,
- suggestionInfo.suggestionIndex);
+ if (imm != null) {
+ imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText,
+ suggestionInfo.suggestionIndex);
+ }
}
// Swap text content between actual text and Suggestion span
@@ -10045,7 +10071,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- // Move cursor at the end of the replacement word
+ // Move cursor at the end of the replaced word
Selection.setSelection(editable, spanEnd + lengthDifference);
}
@@ -10174,8 +10200,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!hasSelection()) {
// There may already be a selection on device rotation
- boolean currentWordSelected = selectCurrentWord();
- if (!currentWordSelected) {
+ if (!selectCurrentWord()) {
// No word found under cursor or text selection not permitted.
return false;
}
@@ -10256,7 +10281,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- TypedArray styledAttributes = mContext.obtainStyledAttributes(R.styleable.Theme);
+ TypedArray styledAttributes = mContext.obtainStyledAttributes(
+ com.android.internal.R.styleable.SelectionModeDrawables);
boolean allowText = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
@@ -10269,7 +10295,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!allowText) {
// Provide an icon, text will not be displayed on smaller screens.
selectAllIconId = styledAttributes.getResourceId(
- R.styleable.Theme_actionModeSelectAllDrawable, 0);
+ R.styleable.SelectionModeDrawables_actionModeSelectAllDrawable, 0);
}
menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
@@ -10281,7 +10307,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (canCut()) {
menu.add(0, ID_CUT, 0, com.android.internal.R.string.cut).
setIcon(styledAttributes.getResourceId(
- R.styleable.Theme_actionModeCutDrawable, 0)).
+ R.styleable.SelectionModeDrawables_actionModeCutDrawable, 0)).
setAlphabeticShortcut('x').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
@@ -10290,7 +10316,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (canCopy()) {
menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
setIcon(styledAttributes.getResourceId(
- R.styleable.Theme_actionModeCopyDrawable, 0)).
+ R.styleable.SelectionModeDrawables_actionModeCopyDrawable, 0)).
setAlphabeticShortcut('c').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
@@ -10299,7 +10325,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (canPaste()) {
menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
setIcon(styledAttributes.getResourceId(
- R.styleable.Theme_actionModePasteDrawable, 0)).
+ R.styleable.SelectionModeDrawables_actionModePasteDrawable, 0)).
setAlphabeticShortcut('v').
setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 7444d46..f52e773 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -237,9 +237,7 @@ public class TimePicker extends FrameLayout {
}
// set the content descriptions
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- setContentDescriptions();
- }
+ setContentDescriptions();
}
@Override
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index ecda47e..edf4443 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -36,17 +36,19 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call
private ActionMode.Callback mCallback;
private WeakReference<View> mCustomView;
private boolean mFinished;
+ private boolean mFocusable;
private MenuBuilder mMenu;
public StandaloneActionMode(Context context, ActionBarContextView view,
- ActionMode.Callback callback) {
+ ActionMode.Callback callback, boolean isFocusable) {
mContext = context;
mContextView = view;
mCallback = callback;
mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
mMenu.setCallback(this);
+ mFocusable = isFocusable;
}
@Override
@@ -139,4 +141,8 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call
invalidate();
mContextView.showOverflowMenu();
}
+
+ public boolean isUiFocusable() {
+ return mFocusable;
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 4a38775..2694aa2 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -24,11 +24,15 @@ import android.app.admin.DevicePolicyManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
import android.os.FileObserver;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.storage.IMountService;
import android.provider.Settings;
import android.security.KeyStore;
@@ -55,6 +59,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public class LockPatternUtils {
+ private static final String OPTION_ENABLE_FACELOCK = "enable_facelock";
+
private static final String TAG = "LockPatternUtils";
private static final String SYSTEM_DIRECTORY = "/system/";
@@ -110,6 +116,7 @@ public class LockPatternUtils {
public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
+ private final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
= "lockscreen.biometric_weak_fallback";
@@ -339,12 +346,21 @@ public class LockPatternUtils {
*/
public int getActivePasswordQuality() {
int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
- switch (getKeyguardStoredPasswordQuality()) {
+ // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
+ // return biometric_weak if that is being used instead of the backup
+ int quality =
+ (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ switch (quality) {
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
if (isLockPatternEnabled()) {
activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
}
break;
+ case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
+ if (isBiometricWeakInstalled()) {
+ activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+ }
+ break;
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
if (isLockPasswordEnabled()) {
activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
@@ -366,6 +382,7 @@ public class LockPatternUtils {
}
break;
}
+
return activePasswordQuality;
}
@@ -434,7 +451,7 @@ public class LockPatternUtils {
* Calls back SetupFaceLock to delete the gallery file when the lock type is changed
*/
void deleteGallery() {
- if(isBiometricEnabled()) {
+ if(usingBiometricWeak()) {
Intent intent = new Intent().setClassName("com.android.facelock",
"com.android.facelock.SetupFaceLock");
intent.putExtra("deleteGallery", true);
@@ -677,6 +694,9 @@ public class LockPatternUtils {
return quality;
}
+ /**
+ * @return true if the lockscreen method is set to biometric weak
+ */
public boolean usingBiometricWeak() {
int quality =
(int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
@@ -810,7 +830,7 @@ public class LockPatternUtils {
|| backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
return savedPasswordExists() && (passwordEnabled ||
- (isBiometricEnabled() && backupEnabled));
+ (usingBiometricWeak() && backupEnabled));
}
/**
@@ -824,16 +844,36 @@ public class LockPatternUtils {
return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED)
&& (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
- (isBiometricEnabled() && backupEnabled));
+ (usingBiometricWeak() && backupEnabled));
}
/**
- * @return Whether biometric weak lock is enabled.
+ * @return Whether biometric weak lock is installed and that the front facing camera exists
*/
- public boolean isBiometricEnabled() {
- // TODO: check if it's installed
- return getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
- == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
+ public boolean isBiometricWeakInstalled() {
+ // Check that the system flag was set
+ if (!OPTION_ENABLE_FACELOCK.equals(getString(LOCKSCREEN_OPTIONS))) {
+ return false;
+ }
+
+ // Check that it's installed
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+
+ // Check that the camera is enabled
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
+ return false;
+ }
+ if (getDevicePolicyManager().getCameraDisabled(null)) {
+ return false;
+ }
+
+
+ return true;
}
/**