getInstalledProviders() {
try {
return sService.getInstalledProviders();
}
@@ -175,12 +268,12 @@ public class GadgetManager {
}
/**
- * Get the available info about the gadget. If the gadgetId has not been bound yet,
- * this method will return null.
+ * Get the available info about the gadget.
*
- * TODO: throws GadgetNotFoundException ??? if not valid
+ * @return A gadgetId. If the gadgetId has not been bound to a provider yet, or
+ * you don't have access to that gadgetId, null is returned.
*/
- public GadgetInfo getGadgetInfo(int gadgetId) {
+ public GadgetProviderInfo getGadgetInfo(int gadgetId) {
try {
return sService.getGadgetInfo(gadgetId);
}
@@ -190,7 +283,14 @@ public class GadgetManager {
}
/**
- * Set the component for a given gadgetId. You need the GADGET_LIST permission.
+ * Set the component for a given gadgetId.
+ *
+ * You need the GADGET_LIST permission. This method is to be used by the
+ * gadget picker.
+ *
+ * @param gadgetId The gadget instance for which to set the RemoteViews.
+ * @param provider The {@link android.content.BroadcastReceiver} that will be the gadget
+ * provider for this gadget.
*/
public void bindGadgetId(int gadgetId, ComponentName provider) {
try {
diff --git a/core/java/android/gadget/GadgetProvider.java b/core/java/android/gadget/GadgetProvider.java
index 1ddfe3f0babf3..7e10e7817a2b6 100755
--- a/core/java/android/gadget/GadgetProvider.java
+++ b/core/java/android/gadget/GadgetProvider.java
@@ -55,7 +55,7 @@ public class GadgetProvider extends BroadcastReceiver {
// Protect against rogue update broadcasts (not really a security issue,
// just filter bad broacasts out so subclasses are less likely to crash).
String action = intent.getAction();
- if (GadgetManager.GADGET_UPDATE_ACTION.equals(action)) {
+ if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
Bundle extras = intent.getExtras();
if (extras != null) {
int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
@@ -64,7 +64,7 @@ public class GadgetProvider extends BroadcastReceiver {
}
}
}
- else if (GadgetManager.GADGET_DELETED_ACTION.equals(action)) {
+ else if (GadgetManager.ACTION_GADGET_DELETED.equals(action)) {
Bundle extras = intent.getExtras();
if (extras != null) {
int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
@@ -73,102 +73,81 @@ public class GadgetProvider extends BroadcastReceiver {
}
}
}
- else if (GadgetManager.GADGET_ENABLED_ACTION.equals(action)) {
+ else if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
this.onEnabled(context);
}
- else if (GadgetManager.GADGET_DISABLED_ACTION.equals(action)) {
+ else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
this.onDisabled(context);
}
}
// END_INCLUDE(onReceive)
/**
- * Called in response to the {@link GadgetManager#GADGET_UPDATE_ACTION} broadcast when
+ * Called in response to the {@link GadgetManager#ACTION_GADGET_UPDATE} broadcast when
* this gadget provider is being asked to provide {@link android.widget.RemoteViews RemoteViews}
* for a set of gadgets. Override this method to implement your own gadget functionality.
*
* {@more}
- *
If you want this method called, you must declare in an intent-filter in
- * your AndroidManifest.xml file that you accept the GADGET_UPDATE_ACTION intent action.
- * For example:
- * TODO: SAMPLE CODE GOES HERE
- *
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
* @param gadgetManager A {@link GadgetManager} object you can call {@link
- * GadgetManager#updateGadgets} on.
+ * GadgetManager#updateGadget} on.
* @param gadgetIds The gadgetsIds for which an update is needed. Note that this
* may be all of the gadget instances for this provider, or just
* a subset of them.
*
- * @see GadgetManager#GADGET_UPDATE_ACTION
+ * @see GadgetManager#ACTION_GADGET_UPDATE
*/
public void onUpdate(Context context, GadgetManager gadgetManager, int[] gadgetIds) {
}
/**
- * Called in response to the {@link GadgetManager#GADGET_DELETED_ACTION} broadcast when
+ * Called in response to the {@link GadgetManager#ACTION_GADGET_DELETED} broadcast when
* one or more gadget instances have been deleted. Override this method to implement
* your own gadget functionality.
*
* {@more}
- * If you want this method called, you must declare in an intent-filter in
- * your AndroidManifest.xml file that you accept the GADGET_DELETED_ACTION intent action.
- * For example:
- * TODO: SAMPLE CODE GOES HERE
- *
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
* @param gadgetIds The gadgetsIds that have been deleted from their host.
*
- * @see GadgetManager#GADGET_DELETED_ACTION
+ * @see GadgetManager#ACTION_GADGET_DELETED
*/
public void onDeleted(Context context, int[] gadgetIds) {
}
/**
- * Called in response to the {@link GadgetManager#GADGET_ENABLED_ACTION} broadcast when
+ * Called in response to the {@link GadgetManager#ACTION_GADGET_ENABLED} broadcast when
* the a gadget for this provider is instantiated. Override this method to implement your
* own gadget functionality.
*
* {@more}
* When the last gadget for this provider is deleted,
- * {@link GadgetManager#GADGET_DISABLED_ACTION} is sent and {@link #onDisabled}
- * is called. If after that, a gadget for this provider is created again, onEnabled() will
- * be called again.
+ * {@link GadgetManager#ACTION_GADGET_DISABLED} is sent by the gadget manager, and
+ * {@link #onDisabled} is called. If after that, a gadget for this provider is created
+ * again, onEnabled() will be called again.
*
- * If you want this method called, you must declare in an intent-filter in
- * your AndroidManifest.xml file that you accept the GADGET_ENABLED_ACTION intent action.
- * For example:
- * TODO: SAMPLE CODE GOES HERE
- *
- *
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
*
- * @see GadgetManager#GADGET_ENABLED_ACTION
+ * @see GadgetManager#ACTION_GADGET_ENABLED
*/
public void onEnabled(Context context) {
}
/**
- * Called in response to the {@link GadgetManager#GADGET_DISABLED_ACTION} broadcast, which
+ * Called in response to the {@link GadgetManager#ACTION_GADGET_DISABLED} broadcast, which
* is sent when the last gadget instance for this provider is deleted. Override this method
* to implement your own gadget functionality.
*
* {@more}
- * If you want this method called, you must declare in an intent-filter in
- * your AndroidManifest.xml file that you accept the GADGET_DISABLED_ACTION intent action.
- * For example:
- * TODO: SAMPLE CODE GOES HERE
- *
*
* @param context The {@link android.content.Context Context} in which this receiver is
* running.
*
- * @see GadgetManager#GADGET_DISABLED_ACTION
+ * @see GadgetManager#ACTION_GADGET_DISABLED
*/
public void onDisabled(Context context) {
}
diff --git a/core/java/android/gadget/GadgetInfo.aidl b/core/java/android/gadget/GadgetProviderInfo.aidl
similarity index 95%
rename from core/java/android/gadget/GadgetInfo.aidl
rename to core/java/android/gadget/GadgetProviderInfo.aidl
index 72315454b6dd8..589f886776f4e 100644
--- a/core/java/android/gadget/GadgetInfo.aidl
+++ b/core/java/android/gadget/GadgetProviderInfo.aidl
@@ -16,4 +16,4 @@
package android.gadget;
-parcelable GadgetInfo;
+parcelable GadgetProviderInfo;
diff --git a/core/java/android/gadget/GadgetInfo.java b/core/java/android/gadget/GadgetProviderInfo.java
similarity index 56%
rename from core/java/android/gadget/GadgetInfo.java
rename to core/java/android/gadget/GadgetProviderInfo.java
index 5ac3da9cf2d11..95c043230ec30 100644
--- a/core/java/android/gadget/GadgetInfo.java
+++ b/core/java/android/gadget/GadgetProviderInfo.java
@@ -21,60 +21,88 @@ import android.os.Parcelable;
import android.content.ComponentName;
/**
- * Describes the meta data for an installed gadget.
+ * Describes the meta data for an installed gadget provider. The fields in this class
+ * correspond to the fields in the <gadget-provider> xml tag.
*/
-public class GadgetInfo implements Parcelable {
+public class GadgetProviderInfo implements Parcelable {
/**
* Identity of this gadget component. This component should be a {@link
* android.content.BroadcastReceiver}, and it will be sent the Gadget intents
* {@link android.gadget as described in the gadget package documentation}.
+ *
+ * This field corresponds to the android:name attribute in
+ * the <receiver> element in the AndroidManifest.xml file.
*/
public ComponentName provider;
/**
* Minimum width of the gadget, in dp.
+ *
+ *
This field corresponds to the android:minWidth attribute in
+ * the gadget meta-data file.
*/
public int minWidth;
/**
* Minimum height of the gadget, in dp.
+ *
+ *
This field corresponds to the android:minHeight attribute in
+ * the gadget meta-data file.
*/
public int minHeight;
/**
* How often, in milliseconds, that this gadget wants to be updated.
* The gadget manager may place a limit on how often a gadget is updated.
+ *
+ *
This field corresponds to the android:updatePeriodMillis attribute in
+ * the gadget meta-data file.
*/
public int updatePeriodMillis;
/**
* The resource id of the initial layout for this gadget. This should be
* displayed until the RemoteViews for the gadget is available.
+ *
+ *
This field corresponds to the android:initialLayout attribute in
+ * the gadget meta-data file.
*/
public int initialLayout;
/**
* The activity to launch that will configure the gadget.
+ *
+ *
This class name of field corresponds to the android:configure attribute in
+ * the gadget meta-data file. The package name always corresponds to the package containing
+ * the gadget provider.
*/
public ComponentName configure;
/**
- * The label to display to the user.
+ * The label to display to the user in the gadget picker. If not supplied in the
+ * xml, the application label will be used.
+ *
+ *
This field corresponds to the android:label attribute in
+ * the <receiver> element in the AndroidManifest.xml file.
*/
public String label;
/**
- * The icon to display for this gadget in the picker list.
+ * The icon to display for this gadget in the gadget picker. If not supplied in the
+ * xml, the application icon will be used.
+ *
+ *
This field corresponds to the android:icon attribute in
+ * the <receiver> element in the AndroidManifest.xml file.
*/
public int icon;
- public GadgetInfo() {
+ public GadgetProviderInfo() {
}
/**
- * Unflatten the GadgetInfo from a parcel.
+ * Unflatten the GadgetProviderInfo from a parcel.
*/
- public GadgetInfo(Parcel in) {
+ public GadgetProviderInfo(Parcel in) {
if (0 != in.readInt()) {
this.provider = new ComponentName(in);
}
@@ -116,24 +144,24 @@ public class GadgetInfo implements Parcelable {
}
/**
- * Parcelable.Creator that instantiates GadgetInfo objects
+ * Parcelable.Creator that instantiates GadgetProviderInfo objects
*/
- public static final Parcelable.Creator CREATOR
- = new Parcelable.Creator()
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator()
{
- public GadgetInfo createFromParcel(Parcel parcel)
+ public GadgetProviderInfo createFromParcel(Parcel parcel)
{
- return new GadgetInfo(parcel);
+ return new GadgetProviderInfo(parcel);
}
- public GadgetInfo[] newArray(int size)
+ public GadgetProviderInfo[] newArray(int size)
{
- return new GadgetInfo[size];
+ return new GadgetProviderInfo[size];
}
};
public String toString() {
- return "GadgetInfo(provider=" + this.provider + ")";
+ return "GadgetProviderInfo(provider=" + this.provider + ")";
}
}
diff --git a/core/java/android/gadget/package.html b/core/java/android/gadget/package.html
index 4b8b9d9c3d6b2..4c04396e8b7e6 100644
--- a/core/java/android/gadget/package.html
+++ b/core/java/android/gadget/package.html
@@ -1,41 +1,126 @@
-{@hide}
Android allows applications to publish views to be embedded in other applications. These
views are called gadgets, and are published by "gadget providers." The component that can
-contain gadgets is called a "gadget host." See the links below for more information.
+contain gadgets is called a "gadget host."
-
+
-
-
+
+
+
{@more}
+
+
Gadget Providers
-Any application can publish gadgets. All an application needs to do to publish a gadget is
+
+Any application can publish gadgets. All an application needs to do to publish a gadget is
to have a {@link android.content.BroadcastReceiver} that receives the {@link
-android.gadget.GadgetManager#GADGET_UPDATE_ACTION GadgetManager.GADGET_UPDATE_ACTION} intent,
-and provide some meta-data about the gadget.
+android.gadget.GadgetManager#ACTION_GADGET_UPDATE GadgetManager.ACTION_GADGET_UPDATE} intent,
+and provide some meta-data about the gadget. Android provides the
+{@link android.gadget.GadgetProvider} class, which extends BroadcastReceiver, as a convenience
+class to aid in handling the broadcasts.
Declaring a gadget in the AndroidManifest
-Adding the {@link android.gadget.GadgetInfo GadgetInfo} meta-data
+
+First, declare the {@link android.content.BroadcastReceiver} in your application's
+AndroidManifest.xml file.
+
+{@sample frameworks/base/tests/gadgets/GadgetHostTest/AndroidManifest.xml GadgetProvider}
+
+
+The <receiver> element has the following attributes:
+
+ android:name - which specifies the
+ {@link android.content.BroadcastReceiver} or {@link android.gadget.GadgetProvider}
+ class.
+ android:label - which specifies the string resource that
+ will be shown by the gadget picker as the label.
+ android:icon - which specifies the drawable resource that
+ will be shown by the gadget picker as the icon.
+
+
+
+The <intent-filter> element tells the {@link android.content.pm.PackageManager}
+that this {@link android.content.BroadcastReceiver} receives the {@link
+android.gadget.GadgetManager#ACTION_GADGET_UPDATE GadgetManager.ACTION_GADGET_UPDATE} broadcast.
+The gadget manager will send other broadcasts directly to your gadget provider as required.
+It is only necessary to explicitly declare that you accept the {@link
+android.gadget.GadgetManager#ACTION_GADGET_UPDATE GadgetManager.ACTION_GADGET_UPDATE} broadcast.
+
+
+The <meta-data> element tells the gadget manager which xml resource to
+read to find the {@link android.gadget.GadgetProviderInfo} for your gadget provider. It has the following
+attributes:
+
+ android:name="android.gadget.provider" - identifies this meta-data
+ as the {@link android.gadget.GadgetProviderInfo} descriptor.
+ android:resource - is the xml resource to use as that descriptor.
+
+
+
+Adding the {@link android.gadget.GadgetProviderInfo GadgetProviderInfo} meta-data
+
+
+For a gadget, the values in the {@link android.gadget.GadgetProviderInfo} structure are supplied
+in an XML resource. In the example above, the xml resource is referenced with
+android:resource="@xml/gadget_info". That XML file would go in your application's
+directory at res/xml/gadget_info.xml. Here is a simple example.
+
+{@sample frameworks/base/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml GadgetProviderInfo}
+
+
+The attributes are as documented in the {@link android.gadget.GadgetProviderInfo GagetInfo} class. (86400000 milliseconds means once per day)
+
Using the {@link android.gadget.GadgetProvider GadgetProvider} class
+The GadgetProvider class is the easiest way to handle the gadget provider intent broadcasts.
+See the src/com/example/android/apis/gadget/ExampleGadgetProvider.java
+sample class in ApiDemos for an example.
+
+
Keep in mind that since the the GadgetProvider is a BroadcastReceiver,
+your process is not guaranteed to keep running after the callback methods return. See
+Application Fundamentals >
+Broadcast Receiver Lifecycle for more information.
+
+
+
Gadget Configuration UI
+
+Gadget hosts have the ability to start a configuration activity when a gadget is instantiated.
+The activity should be declared as normal in AndroidManifest.xml, and it should be listed in
+the GadgetProviderInfo XML file in the android:configure attribute.
+
+
The activity you specified will be launched with the {@link
+android.gadget.GadgetManager#ACTION_GADGET_CONFIGURE} action. See the documentation for that
+action for more info.
+
+
See the src/com/example/android/apis/gadget/ExampleGadgetConfigure.java
+sample class in ApiDemos for an example.
+
+
+
Gadget Broadcast Intents
-{@link GadgetProvider} is just a convenience class. If you would like to receive the
-gadget broadcasts directly, you can. By way of example, the implementation of
-{@link GadgetProvider.onReceive} is quite simple:
+{@link android.gadget.GadgetProvider} is just a convenience class. If you would like
+to receive the gadget broadcasts directly, you can. The four intents you need to care about are:
+
+ - {@link android.gadget.GadgetManager#ACTION_GADGET_UPDATE}
+ - {@link android.gadget.GadgetManager#ACTION_GADGET_DELETED}
+ - {@link android.gadget.GadgetManager#ACTION_GADGET_ENABLED}
+ - {@link android.gadget.GadgetManager#ACTION_GADGET_DISABLED}
+
+
+By way of example, the implementation of
+{@link android.gadget.GadgetProvider#onReceive} is quite simple:
{@sample frameworks/base/core/java/android/gadget/GadgetProvider.java onReceive}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c09567c7f0a6d..40a5b478e5f0a 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,6 +18,7 @@ package android.hardware;
import java.lang.ref.WeakReference;
import java.util.HashMap;
+import java.util.StringTokenizer;
import java.io.IOException;
import android.util.Log;
@@ -494,11 +495,17 @@ public class Camera {
*/
public void unflatten(String flattened) {
mMap.clear();
- String[] pairs = flattened.split(";");
- for (String p : pairs) {
- String[] kv = p.split("=");
- if (kv.length == 2)
- mMap.put(kv[0], kv[1]);
+
+ StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
+ while (tokenizer.hasMoreElements()) {
+ String kv = tokenizer.nextToken();
+ int pos = kv.indexOf('=');
+ if (pos == -1) {
+ continue;
+ }
+ String k = kv.substring(0, pos);
+ String v = kv.substring(pos + 1);
+ mMap.put(k, v);
}
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ea5f7414d63de..c8841201f11b6 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -206,6 +206,8 @@ public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
static final boolean DEBUG = false;
+ InputMethodManager mImm;
+
LayoutInflater mInflater;
View mRootView;
SoftInputWindow mWindow;
@@ -293,6 +295,8 @@ public class InputMethodService extends AbstractInputMethodService {
mInputConnection = binding.getConnection();
if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
+ " ic=" + mInputConnection);
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
initialize();
onBindInput();
}
@@ -423,7 +427,7 @@ public class InputMethodService extends AbstractInputMethodService {
* of the application behind. This value is relative to the top edge
* of the input method window.
*/
- int contentTopInsets;
+ public int contentTopInsets;
/**
* This is the top part of the UI that is visibly covering the
@@ -436,7 +440,7 @@ public class InputMethodService extends AbstractInputMethodService {
* needed to make the focus visible. This value is relative to the top edge
* of the input method window.
*/
- int visibleTopInsets;
+ public int visibleTopInsets;
/**
* Option for {@link #touchableInsets}: the entire window frame
@@ -469,6 +473,7 @@ public class InputMethodService extends AbstractInputMethodService {
@Override public void onCreate() {
super.onCreate();
+ mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this);
@@ -554,7 +559,6 @@ public class InputMethodService extends AbstractInputMethodService {
boolean visible = mWindowVisible;
boolean showingInput = mShowInputRequested;
boolean showingForced = mShowInputForced;
- boolean showingCandidates = mCandidatesVisibility == View.VISIBLE;
initViews();
mInputViewStarted = false;
mCandidatesViewStarted = false;
@@ -577,9 +581,6 @@ public class InputMethodService extends AbstractInputMethodService {
// Otherwise just put it back for its candidates.
showWindow(false);
}
- if (showingCandidates) {
- setCandidatesViewShown(true);
- }
}
}
@@ -670,6 +671,8 @@ public class InputMethodService extends AbstractInputMethodService {
if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
changed = true;
mIsFullscreen = isFullscreen;
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) ic.reportFullscreenMode(isFullscreen);
mFullscreenApplied = true;
initialize();
Drawable bg = onCreateBackgroundDrawable();
@@ -860,12 +863,14 @@ public class InputMethodService extends AbstractInputMethodService {
return isFullscreenMode() ? View.GONE : View.INVISIBLE;
}
- public void setStatusIcon(int iconResId) {
+ public void showStatusIcon(int iconResId) {
mStatusIcon = iconResId;
- InputConnection ic = getCurrentInputConnection();
- if (ic != null && mWindowVisible) {
- ic.showStatusIcon(getPackageName(), iconResId);
- }
+ mImm.showStatusIcon(mToken, getPackageName(), iconResId);
+ }
+
+ public void hideStatusIcon() {
+ mStatusIcon = 0;
+ mImm.hideStatusIcon(mToken);
}
/**
@@ -876,8 +881,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @param id Unique identifier of the new input method ot start.
*/
public void switchInputMethod(String id) {
- ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
- .setInputMethod(mToken, id);
+ mImm.setInputMethod(mToken, id);
}
public void setExtractView(View view) {
@@ -1149,15 +1153,9 @@ public class InputMethodService extends AbstractInputMethodService {
if (!wasVisible) {
if (DEBUG) Log.v(TAG, "showWindow: showing!");
+ onWindowShown();
mWindow.show();
}
-
- if (!wasVisible || !wasCreated) {
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.showStatusIcon(getPackageName(), mStatusIcon);
- }
- }
}
public void hideWindow() {
@@ -1173,13 +1171,25 @@ public class InputMethodService extends AbstractInputMethodService {
if (mWindowVisible) {
mWindow.hide();
mWindowVisible = false;
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.hideStatusIcon();
- }
+ onWindowHidden();
}
}
+ /**
+ * Called when the input method window has been shown to the user, after
+ * previously not being visible. This is done after all of the UI setup
+ * for the window has occurred (creating its views etc).
+ */
+ public void onWindowShown() {
+ }
+
+ /**
+ * Called when the input method window has been hidden from the user,
+ * after previously being visible.
+ */
+ public void onWindowHidden() {
+ }
+
/**
* Called when a new client has bound to the input method. This
* may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
@@ -1341,8 +1351,7 @@ public class InputMethodService extends AbstractInputMethodService {
* InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
*/
public void dismissSoftInput(int flags) {
- ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
- .hideSoftInputFromInputMethod(mToken, flags);
+ mImm.hideSoftInputFromInputMethod(mToken, flags);
}
/**
@@ -1447,17 +1456,19 @@ public class InputMethodService extends AbstractInputMethodService {
return true;
}
} else {
- KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
- if (movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, down)) {
- KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
- movement.onKeyUp(eet,
- (Spannable)eet.getText(), keyCode, up);
- while (--count > 0) {
- movement.onKeyDown(eet,
- (Spannable)eet.getText(), keyCode, down);
+ if (!movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+ KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
+ if (movement.onKeyDown(eet,
+ (Spannable)eet.getText(), keyCode, down)) {
+ KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
movement.onKeyUp(eet,
(Spannable)eet.getText(), keyCode, up);
+ while (--count > 0) {
+ movement.onKeyDown(eet,
+ (Spannable)eet.getText(), keyCode, down);
+ movement.onKeyUp(eet,
+ (Spannable)eet.getText(), keyCode, up);
+ }
}
}
}
@@ -1593,5 +1604,9 @@ public class InputMethodService extends AbstractInputMethodService {
p.println(" mExtractedToken=" + mExtractedToken);
p.println(" mIsInputViewShown=" + mIsInputViewShown
+ " mStatusIcon=" + mStatusIcon);
+ p.println("Last computed insets:");
+ p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
+ + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
+ + " touchableInsets=" + mTmpInsets.touchableInsets);
}
}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index b2c74f24bf00e..b8bd10dc44de2 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -1084,6 +1084,10 @@ public class KeyboardView extends View implements View.OnClickListener {
if (mPreviewPopup.isShowing()) {
mPreviewPopup.dismiss();
}
+ mHandler.removeMessages(MSG_REPEAT);
+ mHandler.removeMessages(MSG_LONGPRESS);
+ mHandler.removeMessages(MSG_SHOW_PREVIEW);
+
dismissPopupKeyboard();
}
diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java
index 70e50b7c26357..a6efcdd3da517 100644
--- a/core/java/android/net/UrlQuerySanitizer.java
+++ b/core/java/android/net/UrlQuerySanitizer.java
@@ -23,7 +23,7 @@ import java.util.Set;
import java.util.StringTokenizer;
/**
- *
+ *
* Sanitizes the Query portion of a URL. Simple example:
*
* UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
@@ -32,7 +32,7 @@ import java.util.StringTokenizer;
* String name = sanitizer.getValue("name"));
* // name now contains "Joe_User"
*
- *
+ *
* Register ValueSanitizers to customize the way individual
* parameters are sanitized:
*
@@ -46,7 +46,7 @@ import java.util.StringTokenizer;
* unregistered parameter sanitizer does not allow any special characters,
* and ' ' is a special character.)
*
- *
+ *
* There are several ways to create ValueSanitizers. In order of increasing
* sophistication:
*
@@ -56,7 +56,7 @@ import java.util.StringTokenizer;
* - Subclass UrlQuerySanitizer.ValueSanitizer to define your own value
* sanitizer.
*
- *
+ *
*/
public class UrlQuerySanitizer {
@@ -84,7 +84,7 @@ public class UrlQuerySanitizer {
*/
public String mValue;
}
-
+
final private HashMap mSanitizers =
new HashMap();
final private HashMap mEntries =
@@ -95,9 +95,9 @@ public class UrlQuerySanitizer {
private boolean mPreferFirstRepeatedParameter;
private ValueSanitizer mUnregisteredParameterValueSanitizer =
getAllIllegal();
-
+
/**
- * A functor used to sanitize a single query value.
+ * A functor used to sanitize a single query value.
*
*/
public static interface ValueSanitizer {
@@ -108,7 +108,7 @@ public class UrlQuerySanitizer {
*/
public String sanitize(String value);
}
-
+
/**
* Sanitize values based on which characters they contain. Illegal
* characters are replaced with either space or '_', depending upon
@@ -117,7 +117,7 @@ public class UrlQuerySanitizer {
public static class IllegalCharacterValueSanitizer implements
ValueSanitizer {
private int mFlags;
-
+
/**
* Allow space (' ') characters.
*/
@@ -165,21 +165,21 @@ public class UrlQuerySanitizer {
* such as "javascript:" or "vbscript:"
*/
public final static int SCRIPT_URL_OK = 1 << 10;
-
+
/**
* Mask with all fields set to OK
*/
public final static int ALL_OK = 0x7ff;
-
+
/**
* Mask with both regular space and other whitespace OK
*/
public final static int ALL_WHITESPACE_OK =
SPACE_OK | OTHER_WHITESPACE_OK;
-
+
// Common flag combinations:
-
+
/**
*
* - Deny all special characters.
@@ -262,18 +262,18 @@ public class UrlQuerySanitizer {
*/
public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL =
ALL_OK & ~(NUL_OK | LT_OK | GT_OK);
-
+
/**
* Script URL definitions
*/
-
+
private final static String JAVASCRIPT_PREFIX = "javascript:";
-
+
private final static String VBSCRIPT_PREFIX = "vbscript:";
-
+
private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min(
JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length());
-
+
/**
* Construct a sanitizer. The parameters set the behavior of the
* sanitizer.
@@ -312,7 +312,7 @@ public class UrlQuerySanitizer {
}
}
}
-
+
// If whitespace isn't OK, get rid of whitespace at beginning
// and end of value.
if ( (mFlags & ALL_WHITESPACE_OK) == 0) {
@@ -337,7 +337,7 @@ public class UrlQuerySanitizer {
}
return stringBuilder.toString();
}
-
+
/**
* Trim whitespace from the beginning and end of a string.
*
@@ -361,7 +361,7 @@ public class UrlQuerySanitizer {
}
return value.substring(start, end + 1);
}
-
+
/**
* Check if c is whitespace.
* @param c character to test
@@ -380,7 +380,7 @@ public class UrlQuerySanitizer {
return false;
}
}
-
+
/**
* Check whether an individual character is legal. Uses the
* flag bit-set passed into the constructor.
@@ -400,11 +400,11 @@ public class UrlQuerySanitizer {
case '%' : return (mFlags & PCT_OK) != 0;
case '\0': return (mFlags & NUL_OK) != 0;
default : return (c >= 32 && c < 127) ||
- (c >= 128 && c <= 255 && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
- }
+ ((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
+ }
}
}
-
+
/**
* Get the current value sanitizer used when processing
* unregistered parameter values.
@@ -412,14 +412,14 @@ public class UrlQuerySanitizer {
* Note: The default unregistered parameter value sanitizer is
* one that doesn't allow any special characters, similar to what
* is returned by calling createAllIllegal.
- *
+ *
* @return the current ValueSanitizer used to sanitize unregistered
* parameter values.
*/
public ValueSanitizer getUnregisteredParameterValueSanitizer() {
return mUnregisteredParameterValueSanitizer;
}
-
+
/**
* Set the value sanitizer used when processing unregistered
* parameter values.
@@ -430,46 +430,46 @@ public class UrlQuerySanitizer {
ValueSanitizer sanitizer) {
mUnregisteredParameterValueSanitizer = sanitizer;
}
-
-
+
+
// Private fields for singleton sanitizers:
-
+
private static final ValueSanitizer sAllIllegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_ILLEGAL);
-
+
private static final ValueSanitizer sAllButNulLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL);
-
+
private static final ValueSanitizer sAllButWhitespaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL);
-
+
private static final ValueSanitizer sURLLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.URL_LEGAL);
-
+
private static final ValueSanitizer sUrlAndSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL);
-
+
private static final ValueSanitizer sAmpLegal =
new IllegalCharacterValueSanitizer(
- IllegalCharacterValueSanitizer.AMP_LEGAL);
-
+ IllegalCharacterValueSanitizer.AMP_LEGAL);
+
private static final ValueSanitizer sAmpAndSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL);
-
+
private static final ValueSanitizer sSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.SPACE_LEGAL);
-
+
private static final ValueSanitizer sAllButNulAndAngleBracketsLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL);
-
+
/**
* Return a value sanitizer that does not allow any special characters,
* and also does not allow script URLs.
@@ -478,7 +478,7 @@ public class UrlQuerySanitizer {
public static final ValueSanitizer getAllIllegal() {
return sAllIllegal;
}
-
+
/**
* Return a value sanitizer that allows everything except Nul ('\0')
* characters. Script URLs are allowed.
@@ -547,7 +547,7 @@ public class UrlQuerySanitizer {
public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() {
return sAllButNulAndAngleBracketsLegal;
}
-
+
/**
* Constructs a UrlQuerySanitizer.
*
@@ -560,7 +560,7 @@ public class UrlQuerySanitizer {
*/
public UrlQuerySanitizer() {
}
-
+
/**
* Constructs a UrlQuerySanitizer and parse a URL.
* This constructor is provided for convenience when the
@@ -585,7 +585,7 @@ public class UrlQuerySanitizer {
setAllowUnregisteredParamaters(true);
parseUrl(url);
}
-
+
/**
* Parse the query parameters out of an encoded URL.
* Works by extracting the query portion from the URL and then
@@ -604,7 +604,7 @@ public class UrlQuerySanitizer {
}
parseQuery(query);
}
-
+
/**
* Parse a query. A query string is any number of parameter-value clauses
* separated by any non-zero number of ampersands. A parameter-value clause
@@ -631,7 +631,7 @@ public class UrlQuerySanitizer {
}
}
}
-
+
/**
* Get a set of all of the parameters found in the sanitized query.
*
@@ -641,7 +641,7 @@ public class UrlQuerySanitizer {
public Set getParameterSet() {
return mEntries.keySet();
}
-
+
/**
* An array list of all of the parameter value pairs in the sanitized
* query, in the order they appeared in the query. May contain duplicate
@@ -691,7 +691,7 @@ public class UrlQuerySanitizer {
}
mSanitizers.put(parameter, valueSanitizer);
}
-
+
/**
* Register a value sanitizer for an array of parameters.
* @param parameters An array of unencoded parameter names.
@@ -705,7 +705,7 @@ public class UrlQuerySanitizer {
mSanitizers.put(parameters[i], valueSanitizer);
}
}
-
+
/**
* Set whether or not unregistered parameters are allowed. If they
* are not allowed, then they will be dropped when a query is sanitized.
@@ -718,7 +718,7 @@ public class UrlQuerySanitizer {
boolean allowUnregisteredParamaters) {
mAllowUnregisteredParamaters = allowUnregisteredParamaters;
}
-
+
/**
* Get whether or not unregistered parameters are allowed. If not
* allowed, they will be dropped when a query is parsed.
@@ -728,10 +728,10 @@ public class UrlQuerySanitizer {
public boolean getAllowUnregisteredParamaters() {
return mAllowUnregisteredParamaters;
}
-
+
/**
* Set whether or not the first occurrence of a repeated parameter is
- * preferred. True means the first repeated parameter is preferred.
+ * preferred. True means the first repeated parameter is preferred.
* False means that the last repeated parameter is preferred.
*
* The preferred parameter is the one that is returned when getParameter
@@ -746,7 +746,7 @@ public class UrlQuerySanitizer {
boolean preferFirstRepeatedParameter) {
mPreferFirstRepeatedParameter = preferFirstRepeatedParameter;
}
-
+
/**
* Get whether or not the first occurrence of a repeated parameter is
* preferred.
@@ -757,10 +757,10 @@ public class UrlQuerySanitizer {
public boolean getPreferFirstRepeatedParameter() {
return mPreferFirstRepeatedParameter;
}
-
+
/**
* Parse an escaped parameter-value pair. The default implementation
- * unescapes both the parameter and the value, then looks up the
+ * unescapes both the parameter and the value, then looks up the
* effective value sanitizer for the parameter and uses it to sanitize
* the value. If all goes well then addSanitizedValue is called with
* the unescaped parameter and the sanitized unescaped value.
@@ -779,7 +779,7 @@ public class UrlQuerySanitizer {
String sanitizedValue = valueSanitizer.sanitize(unescapedValue);
addSanitizedEntry(unescapedParameter, sanitizedValue);
}
-
+
/**
* Record a sanitized parameter-value pair. Override if you want to
* do additional filtering or validation.
@@ -796,7 +796,7 @@ public class UrlQuerySanitizer {
}
mEntries.put(parameter, value);
}
-
+
/**
* Get the value sanitizer for a parameter. Returns null if there
* is no value sanitizer registered for the parameter.
@@ -807,7 +807,7 @@ public class UrlQuerySanitizer {
public ValueSanitizer getValueSanitizer(String parameter) {
return mSanitizers.get(parameter);
}
-
+
/**
* Get the effective value sanitizer for a parameter. Like getValueSanitizer,
* except if there is no value sanitizer registered for a parameter, and
@@ -823,7 +823,7 @@ public class UrlQuerySanitizer {
}
return sanitizer;
}
-
+
/**
* Unescape an escaped string.
*
@@ -867,7 +867,7 @@ public class UrlQuerySanitizer {
}
return stringBuilder.toString();
}
-
+
/**
* Test if a character is a hexidecimal digit. Both upper case and lower
* case hex digits are allowed.
@@ -877,7 +877,7 @@ public class UrlQuerySanitizer {
protected boolean isHexDigit(char c) {
return decodeHexDigit(c) >= 0;
}
-
+
/**
* Convert a character that represents a hexidecimal digit into an integer.
* If the character is not a hexidecimal digit, then -1 is returned.
@@ -885,7 +885,7 @@ public class UrlQuerySanitizer {
* @param c the hexidecimal digit.
* @return the integer value of the hexidecimal digit.
*/
-
+
protected int decodeHexDigit(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
@@ -900,7 +900,7 @@ public class UrlQuerySanitizer {
return -1;
}
}
-
+
/**
* Clear the existing entries. Called to get ready to parse a new
* query string.
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index c6615da03eef8..1a287c814dcac 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -140,7 +140,6 @@ public class RecurrenceSet {
recurrence = recurrence.substring(tzidx + 1);
}
Time time = new Time(tz);
- boolean rdateNotInUtc = !tz.equals(Time.TIMEZONE_UTC);
String[] rawDates = recurrence.split(",");
int n = rawDates.length;
long[] dates = new long[n];
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index 05c2952243746..02ab1da35fda1 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -88,6 +88,9 @@ class PreferenceGroupAdapter extends BaseAdapter implements OnPreferenceChangeIn
public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
mPreferenceGroup = preferenceGroup;
+ // If this group gets or loses any children, let us know
+ mPreferenceGroup.setOnPreferenceChangeInternalListener(this);
+
mPreferenceList = new ArrayList();
mPreferenceClassNames = new ArrayList();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 054da1de5f48e..c6a7b407101ce 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -878,15 +878,6 @@ public final class Settings {
*/
public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
- /**
- * The interval in milliseconds after which Wi-Fi is considered idle.
- * When idle, it is possible for the device to be switched from Wi-Fi to
- * the mobile data network.
- *
- * @hide pending API Council approval
- */
- public static final String WIFI_IDLE_MS = "wifi_idle_ms";
-
/**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
@@ -1288,6 +1279,12 @@ public final class Settings {
*/
public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
+ /**
+ * Whether the haptic feedback (long presses, ...) are enabled. The value is
+ * boolean (1 or 0).
+ */
+ public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
+
// Settings moved to Settings.Secure
/**
@@ -2731,6 +2728,13 @@ public final class Settings {
public static final String GPRS_REGISTER_CHECK_PERIOD_MS =
"gprs_register_check_period_ms";
+ /**
+ * The interval in milliseconds after which Wi-Fi is considered idle.
+ * When idle, it is possible for the device to be switched from Wi-Fi to
+ * the mobile data network.
+ */
+ public static final String WIFI_IDLE_MS = "wifi_idle_ms";
+
/**
* Screen timeout in milliseconds corresponding to the
* PowerManager's POKE_LOCK_SHORT_TIMEOUT flag (i.e. the fastest
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index d1497619a92e2..7c15045dbfb4a 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -25,8 +25,8 @@
package android.server;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset; // just for dump()
import android.bluetooth.BluetoothError;
+import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDevice;
import android.bluetooth.IBluetoothDeviceCallback;
@@ -35,23 +35,20 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemService;
+import android.provider.Settings;
+import android.util.Log;
-import java.io.IOException;
import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
public class BluetoothDeviceService extends IBluetoothDevice.Stub {
@@ -119,7 +116,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public synchronized boolean disable() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
-
+
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
@@ -229,9 +226,9 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
long origCallerIdentityToken = Binder.clearCallingIdentity();
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
bluetoothOn ? 1 : 0);
- Binder.restoreCallingIdentity(origCallerIdentityToken);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
}
-
+
private native int enableNative();
private native int disableNative();
@@ -247,6 +244,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public class BondState {
private final HashMap mState = new HashMap();
private final HashMap mPinAttempt = new HashMap();
+ private final ArrayList mAutoPairingFailures = new ArrayList();
public synchronized void loadBondState() {
if (!mIsEnabled) {
@@ -281,8 +279,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
if (state == BluetoothDevice.BOND_NOT_BONDED) {
if (reason <= 0) {
- Log.w(TAG, "setBondState() called to unbond device with invalid reason code " +
- "Setting reason = BOND_RESULT_REMOVED");
+ Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
+ "invalid. Overriding reason code with BOND_RESULT_REMOVED");
reason = BluetoothDevice.UNBOND_REASON_REMOVED;
}
intent.putExtra(BluetoothIntent.REASON, reason);
@@ -290,11 +288,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
} else {
mState.put(address, state);
}
- if (state == BluetoothDevice.BOND_BONDING) {
- mPinAttempt.put(address, Integer.valueOf(0));
- } else {
- mPinAttempt.remove(address);
- }
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
@@ -316,6 +310,24 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
return result.toArray(new String[result.size()]);
}
+ public synchronized void addAutoPairingFailure(String address) {
+ if (!mAutoPairingFailures.contains(address)) {
+ mAutoPairingFailures.add(address);
+ }
+ }
+
+ public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
+ return getAttempt(address) != 0;
+ }
+
+ public synchronized void clearPinAttempts(String address) {
+ mPinAttempt.remove(address);
+ }
+
+ public synchronized boolean hasAutoPairingFailed(String address) {
+ return mAutoPairingFailures.contains(address);
+ }
+
public synchronized int getAttempt(String address) {
Integer attempt = mPinAttempt.get(address);
if (attempt == null) {
@@ -326,10 +338,13 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public synchronized void attempt(String address) {
Integer attempt = mPinAttempt.get(address);
+ int newAttempt;
if (attempt == null) {
- return;
+ newAttempt = 1;
+ } else {
+ newAttempt = attempt.intValue() + 1;
}
- mPinAttempt.put(address, new Integer(attempt.intValue() + 1));
+ mPinAttempt.put(address, new Integer(newAttempt));
}
}
@@ -508,7 +523,11 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
return false;
}
address = address.toUpperCase();
- if (mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+
+ // Check for bond state only if we are not performing auto
+ // pairing exponential back-off attempts.
+ if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
+ mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
return false;
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 0f60fae346205..b5e409027ce99 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -24,6 +24,8 @@ import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDeviceCallback;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -48,9 +50,33 @@ class BluetoothEventLoop {
private BluetoothDeviceService mBluetoothService;
private Context mContext;
+ private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
+
+ // The time (in millisecs) to delay the pairing attempt after the first
+ // auto pairing attempt fails. We use an exponential delay with
+ // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
+ // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
+ private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
+ private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
+
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
+ String address = (String)msg.obj;
+ if (address != null) {
+ mBluetoothService.createBond(address);
+ return;
+ }
+ break;
+ }
+ }
+ };
+
static { classInitNative(); }
private static native void classInitNative();
@@ -149,16 +175,6 @@ class BluetoothEventLoop {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- private void onPairingRequest() {
- Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- }
-
- private void onPairingCancel() {
- Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- }
-
private void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
@@ -214,12 +230,55 @@ class BluetoothEventLoop {
address = address.toUpperCase();
if (result == BluetoothError.SUCCESS) {
mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
+ if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ }
+ } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
+ mBluetoothService.getBondState().getAttempt(address) == 1) {
+ mBluetoothService.getBondState().addAutoPairingFailure(address);
+ pairingAttempt(address, result);
+ } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
+ mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+ pairingAttempt(address, result);
} else {
mBluetoothService.getBondState().setBondState(address,
BluetoothDevice.BOND_NOT_BONDED, result);
+ if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ }
}
}
+ private void pairingAttempt(String address, int result) {
+ // This happens when our initial guess of "0000" as the pass key
+ // fails. Try to create the bond again and display the pin dialog
+ // to the user. Use back-off while posting the delayed
+ // message. The initial value is
+ // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
+ // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
+ // reached, display an error to the user.
+ int attempt = mBluetoothService.getBondState().getAttempt(address);
+ if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
+ MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NOT_BONDED, result);
+ return;
+ }
+
+ Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+ message.obj = address;
+ boolean postResult = mHandler.sendMessageDelayed(message,
+ attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+ if (!postResult) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NOT_BONDED, result);
+ return;
+ }
+ mBluetoothService.getBondState().attempt(address);
+ }
+
private void onBondingCreated(String address) {
mBluetoothService.getBondState().setBondState(address.toUpperCase(),
BluetoothDevice.BOND_BONDED);
@@ -253,12 +312,12 @@ class BluetoothEventLoop {
case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
- if (mBluetoothService.getBondState().getAttempt(address) < 1) {
+ if (!mBluetoothService.getBondState().hasAutoPairingFailed(address)) {
mBluetoothService.getBondState().attempt(address);
mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
return;
}
- }
+ }
}
Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index a559b9d6f43d3..6df0b35cb497a 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -16,6 +16,7 @@
package android.text.method;
+import android.util.Log;
import android.view.KeyEvent;
import android.text.*;
import android.widget.TextView;
@@ -185,15 +186,9 @@ implements MovementMethod
if (code != KeyEvent.KEYCODE_UNKNOWN
&& event.getAction() == KeyEvent.ACTION_MULTIPLE) {
int repeat = event.getRepeatCount();
- boolean first = true;
boolean handled = false;
while ((--repeat) > 0) {
- if (first && executeDown(view, text, code)) {
- handled = true;
- MetaKeyKeyListener.adjustMetaAfterKeypress(text);
- MetaKeyKeyListener.resetLockedMeta(text);
- }
- first = false;
+ handled |= executeDown(view, text, code);
}
return handled;
}
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index d89fbec557ae6..39ad97689a5dc 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -287,10 +287,10 @@ public abstract class MetaKeyKeyListener {
}
public static void clearMetaKeyState(Editable content, int states) {
- if ((states&META_SHIFT_ON) != 0) resetLock(content, CAP);
- if ((states&META_ALT_ON) != 0) resetLock(content, ALT);
- if ((states&META_SYM_ON) != 0) resetLock(content, SYM);
- if ((states&META_SELECTING) != 0) resetLock(content, SELECTING);
+ if ((states&META_SHIFT_ON) != 0) content.removeSpan(CAP);
+ if ((states&META_ALT_ON) != 0) content.removeSpan(ALT);
+ if ((states&META_SYM_ON) != 0) content.removeSpan(SYM);
+ if ((states&META_SELECTING) != 0) content.removeSpan(SELECTING);
}
/**
diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java
index 85adabd72abb0..fad4f64ffe1ea 100644
--- a/core/java/android/text/method/PasswordTransformationMethod.java
+++ b/core/java/android/text/method/PasswordTransformationMethod.java
@@ -105,8 +105,10 @@ implements TransformationMethod, TextWatcher
sp.removeSpan(old[i]);
}
- sp.setSpan(new Visible(sp, this), start, start + count,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ if (count == 1) {
+ sp.setSpan(new Visible(sp, this), start, start + count,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
}
}
}
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
new file mode 100644
index 0000000000000..cc3563c40f8da
--- /dev/null
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Constants to be used to perform haptic feedback effects via
+ * {@link View#performHapticFeedback(int)}
+ */
+public class HapticFeedbackConstants {
+
+ private HapticFeedbackConstants() {}
+
+ public static final int LONG_PRESS = 0;
+
+ /** @hide pending API council */
+ public static final int ZOOM_RING_TICK = 1;
+
+ /**
+ * Flag for {@link View#performHapticFeedback(int, int)
+ * View.performHapticFeedback(int, int)}: Ignore the setting in the
+ * view for whether to perform haptic feedback, do it always.
+ */
+ public static final int FLAG_IGNORE_VIEW_SETTING = 0x0001;
+
+ /**
+ * Flag for {@link View#performHapticFeedback(int, int)
+ * View.performHapticFeedback(int, int)}: Ignore the global setting
+ * for whether to perform haptic feedback, do it always.
+ */
+ public static final int FLAG_IGNORE_GLOBAL_SETTING = 0x0002;
+}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7276f173cf3f5..1156856694062 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -106,5 +106,6 @@ interface IWindowSession {
void setInTouchMode(boolean showFocus);
boolean getInTouchMode();
+
+ boolean performHapticFeedback(IWindow window, int effectId, boolean always);
}
-
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a51b5646c1576..1d5e7cd49ca53 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -835,6 +835,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
public static final int SOUND_EFFECTS_ENABLED = 0x08000000;
+ /**
+ * View flag indicating whether this view should have haptic feedback
+ * enabled for events such as long presses.
+ */
+ public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;
+
/**
* Use with {@link #focusSearch}. Move focus to the previous selectable
* item.
@@ -1637,6 +1643,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
+ mViewFlags = SOUND_EFFECTS_ENABLED|HAPTIC_FEEDBACK_ENABLED;
++sInstanceCount;
}
@@ -1703,9 +1710,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
- viewFlagValues |= SOUND_EFFECTS_ENABLED;
- viewFlagMasks |= SOUND_EFFECTS_ENABLED;
-
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
@@ -1801,6 +1805,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
viewFlagValues &= ~SOUND_EFFECTS_ENABLED;
viewFlagMasks |= SOUND_EFFECTS_ENABLED;
}
+ case com.android.internal.R.styleable.View_hapticFeedbackEnabled:
+ if (!a.getBoolean(attr, true)) {
+ viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED;
+ viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED;
+ }
case R.styleable.View_scrollbars:
final int scrollbars = a.getInt(attr, SCROLLBARS_NONE);
if (scrollbars != SCROLLBARS_NONE) {
@@ -2182,6 +2191,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (!handled) {
handled = showContextMenu();
}
+ if (handled) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
return handled;
}
@@ -2742,7 +2754,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* Set whether this view should have sound effects enabled for events such as
* clicking and touching.
*
- * You may wish to disable sound effects for a view if you already play sounds,
+ * You may wish to disable sound effects for a view if you already play sounds,
* for instance, a dial key that plays dtmf tones.
*
* @param soundEffectsEnabled whether sound effects are enabled for this view.
@@ -2767,6 +2779,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED);
}
+ /**
+ * Set whether this view should have haptic feedback for events such as
+ * long presses.
+ *
+ *
You may wish to disable haptic feedback if your view already controls
+ * its own haptic feedback.
+ *
+ * @param hapticFeedbackEnabled whether haptic feedback enabled for this view.
+ * @see #isHapticFeedbackEnabled()
+ * @see #performHapticFeedback(int)
+ * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+ */
+ public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) {
+ setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED);
+ }
+
+ /**
+ * @return whether this view should have haptic feedback enabled for events
+ * long presses.
+ *
+ * @see #setHapticFeedbackEnabled(boolean)
+ * @see #performHapticFeedback(int)
+ * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+ */
+ @ViewDebug.ExportedProperty
+ public boolean isHapticFeedbackEnabled() {
+ return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED);
+ }
+
/**
* If this view doesn't do any drawing on its own, set this flag to
* allow further optimizations. By default, this flag is not set on
@@ -7312,20 +7353,57 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
/**
* Play a sound effect for this view.
*
- * The framework will play sound effects for some built in actions, such as
+ *
The framework will play sound effects for some built in actions, such as
* clicking, but you may wish to play these effects in your widget,
* for instance, for internal navigation.
*
- * The sound effect will only be played if sound effects are enabled by the user, and
+ *
The sound effect will only be played if sound effects are enabled by the user, and
* {@link #isSoundEffectsEnabled()} is true.
*
* @param soundConstant One of the constants defined in {@link SoundEffectConstants}
*/
- protected void playSoundEffect(int soundConstant) {
- if (mAttachInfo == null || mAttachInfo.mSoundEffectPlayer == null || !isSoundEffectsEnabled()) {
+ public void playSoundEffect(int soundConstant) {
+ if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) {
return;
}
- mAttachInfo.mSoundEffectPlayer.playSoundEffect(soundConstant);
+ mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant);
+ }
+
+ /**
+ * Provide haptic feedback to the user for this view.
+ *
+ *
The framework will provide haptic feedback for some built in actions,
+ * such as long presses, but you may wish to provide feedback for your
+ * own widget.
+ *
+ *
The feedback will only be performed if
+ * {@link #isHapticFeedbackEnabled()} is true.
+ *
+ * @param feedbackConstant One of the constants defined in
+ * {@link HapticFeedbackConstants}
+ */
+ public boolean performHapticFeedback(int feedbackConstant) {
+ return performHapticFeedback(feedbackConstant, 0);
+ }
+
+ /**
+ * Like {@link #performHapticFeedback(int)}, with additional options.
+ *
+ * @param feedbackConstant One of the constants defined in
+ * {@link HapticFeedbackConstants}
+ * @param flags Additional flags as per {@link HapticFeedbackConstants}.
+ */
+ public boolean performHapticFeedback(int feedbackConstant, int flags) {
+ if (mAttachInfo == null) {
+ return false;
+ }
+ if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
+ && !isHapticFeedbackEnabled()) {
+ return false;
+ }
+ return mAttachInfo.mRootCallbacks.performHapticFeedback(
+ feedbackConstant,
+ (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
}
/**
@@ -7704,8 +7782,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
static class AttachInfo {
- interface SoundEffectPlayer {
+ interface Callbacks {
void playSoundEffect(int effectId);
+ boolean performHapticFeedback(int effectId, boolean always);
}
/**
@@ -7775,7 +7854,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final IBinder mWindowToken;
- final SoundEffectPlayer mSoundEffectPlayer;
+ final Callbacks mRootCallbacks;
/**
* The top view of the hierarchy.
@@ -7922,12 +8001,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @param handler the events handler the view must use
*/
AttachInfo(IWindowSession session, IWindow window,
- Handler handler, SoundEffectPlayer effectPlayer) {
+ Handler handler, Callbacks effectPlayer) {
mSession = session;
mWindow = window;
mWindowToken = window.asBinder();
mHandler = handler;
- mSoundEffectPlayer = effectPlayer;
+ mRootCallbacks = effectPlayer;
}
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 4e46397bae38b..ccfa6bf97fcf7 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -61,7 +61,7 @@ import static javax.microedition.khronos.opengles.GL10.*;
*/
@SuppressWarnings({"EmptyCatchBlock"})
public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.SoundEffectPlayer {
+ View.AttachInfo.Callbacks {
private static final String TAG = "ViewRoot";
private static final boolean DBG = false;
@SuppressWarnings({"ConstantConditionalExpression"})
@@ -1637,7 +1637,7 @@ public final class ViewRoot extends Handler implements ViewParent,
dispatchDetachedFromWindow();
break;
case DISPATCH_KEY_FROM_IME:
- if (true) Log.v(
+ if (LOCAL_LOGV) Log.v(
"ViewRoot", "Dispatching key "
+ msg.obj + " from IME to " + mView);
deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
@@ -2235,6 +2235,17 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
+ /**
+ * {@inheritDoc}
+ */
+ public boolean performHapticFeedback(int effectId, boolean always) {
+ try {
+ return sWindowSession.performHapticFeedback(mWindow, effectId, always);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d08a6fa675586..406af3e3d3846 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -925,7 +925,7 @@ public interface WindowManager extends ViewManager {
sb.append(Integer.toHexString(windowAnimations));
}
if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
- sb.append("or=");
+ sb.append(" or=");
sb.append(screenOrientation);
}
sb.append('}');
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 542b35fc6b8da..051f823fdfdea 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -771,4 +771,15 @@ public interface WindowManagerPolicy {
public boolean isCheekPressedAgainstScreen(MotionEvent ev);
public void setCurrentOrientation(int newOrientation);
+
+ /**
+ * Call from application to perform haptic feedback on its window.
+ */
+ public boolean performHapticFeedback(WindowState win, int effectId, boolean always);
+
+ /**
+ * Called when we have stopped keeping the screen on because a window
+ * requesting this is no longer visible.
+ */
+ public void screenOnStopped();
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 56c6c924fbf32..9509b15317ebe 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -371,6 +371,14 @@ public class BaseInputConnection implements InputConnection {
if (DEBUG) Log.v(TAG, "setSelection " + start + ", " + end);
final Editable content = getEditable();
if (content == null) return false;
+ int len = content.length();
+ if (start > len || end > len) {
+ // If the given selection is out of bounds, just ignore it.
+ // Most likely the text was changed out from under the IME,
+ // the the IME is going to have to update all of its state
+ // anyway.
+ return true;
+ }
Selection.setSelection(content, start, end);
return true;
}
@@ -396,20 +404,10 @@ public class BaseInputConnection implements InputConnection {
}
/**
- * Provides standard implementation for hiding the status icon associated
- * with the current input method.
+ * Updates InputMethodManager with the current fullscreen mode.
*/
- public boolean hideStatusIcon() {
- mIMM.updateStatusIcon(0, null);
- return true;
- }
-
- /**
- * Provides standard implementation for showing the status icon associated
- * with the current input method.
- */
- public boolean showStatusIcon(String packageName, int resId) {
- mIMM.updateStatusIcon(resId, packageName);
+ public boolean reportFullscreenMode(boolean enabled) {
+ mIMM.setFullscreenMode(enabled);
return true;
}
@@ -420,7 +418,11 @@ public class BaseInputConnection implements InputConnection {
Editable content = getEditable();
if (content != null) {
- if (content.length() == 1) {
+ final int N = content.length();
+ if (N == 0) {
+ return;
+ }
+ if (N == 1) {
// If it's 1 character, we have a chance of being
// able to generate normal key events...
if (mKeyCharacterMap == null) {
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 8c30d3fd41280..13173f656397f 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -266,6 +266,13 @@ public interface InputConnection {
*/
public boolean clearMetaKeyStates(int states);
+ /**
+ * Called by the IME to tell the client when it switches between fullscreen
+ * and normal modes. This will normally be called for you by the standard
+ * implementation of {@link android.inputmethodservice.InputMethodService}.
+ */
+ public boolean reportFullscreenMode(boolean enabled);
+
/**
* API to send private commands from an input method to its connected
* editor. This can be used to provide domain-specific features that are
@@ -284,23 +291,4 @@ public interface InputConnection {
* valid.
*/
public boolean performPrivateCommand(String action, Bundle data);
-
- /**
- * Show an icon in the status bar.
- *
- * @param packageName The package holding the icon resource to be shown.
- * @param resId The resource id of the icon to show.
- *
- * @return Returns true on success, false if the input connection is no longer
- * valid.
- */
- public boolean showStatusIcon(String packageName, int resId);
-
- /**
- * Hide the icon shown in the status bar.
- *
- * @return Returns true on success, false if the input connection is no longer
- * valid.
- */
- public boolean hideStatusIcon();
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 99d5aa511df95..fe1416680620d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -214,6 +214,11 @@ public final class InputMethodManager {
*/
boolean mActive = false;
+ /**
+ * As reported by IME through InputConnection.
+ */
+ boolean mFullscreenMode;
+
// -----------------------------------------------------------
/**
@@ -374,6 +379,7 @@ public final class InputMethodManager {
public void setActive(boolean active) {
mActive = active;
+ mFullscreenMode = false;
}
};
@@ -443,14 +449,36 @@ public final class InputMethodManager {
}
}
- public void updateStatusIcon(int iconId, String iconPackage) {
+ public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
try {
- mService.updateStatusIcon(iconId, iconPackage);
+ mService.updateStatusIcon(imeToken, packageName, iconId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
+ public void hideStatusIcon(IBinder imeToken) {
+ try {
+ mService.updateStatusIcon(imeToken, null, 0);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** @hide */
+ public void setFullscreenMode(boolean enabled) {
+ mFullscreenMode = true;
+ }
+
+ /**
+ * Allows you to discover whether the attached input method is running
+ * in fullscreen mode. Return true if it is fullscreen, entirely covering
+ * your UI, else returns false.
+ */
+ public boolean isFullscreenMode() {
+ return mFullscreenMode;
+ }
+
/**
* Return true if the given view is the currently active view for the
* input method.
@@ -503,7 +531,6 @@ public final class InputMethodManager {
void finishInputLocked() {
if (mServedView != null) {
if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
- updateStatusIcon(0, null);
if (mCurrentTextBoxAttribute != null) {
try {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 5a37f040d5ff7..07c1a5d1c0256 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -171,6 +171,10 @@ public final class CookieManager {
boolean pathMatch(String urlPath) {
if (urlPath.startsWith(path)) {
int len = path.length();
+ if (len == 0) {
+ Log.w(LOGTAG, "Empty cookie path");
+ return false;
+ }
int urlLen = urlPath.length();
if (path.charAt(len-1) != PATH_DELIM && urlLen > len) {
// make sure /wee doesn't match /we
@@ -864,7 +868,10 @@ public final class CookieManager {
"illegal format for max-age: " + value);
}
} else if (name.equals(PATH)) {
- cookie.path = value;
+ // only allow non-empty path value
+ if (value.length() > 0) {
+ cookie.path = value;
+ }
} else if (name.equals(DOMAIN)) {
int lastPeriod = value.lastIndexOf(PERIOD);
if (lastPeriod == 0) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3306700424680..bdbf38a703693 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -260,19 +260,8 @@ public class WebView extends AbsoluteLayout
// Whether we are in the drag tap mode, which exists starting at the second
// tap's down, through its move, and includes its up. These events should be
// given to the method on the zoom controller.
- private boolean mInZoomTapDragMode;
-
- // The event time of the previous touch up.
- private long mPreviousUpTime;
-
- private Runnable mRemoveReleaseSingleTap = new Runnable() {
- public void run() {
- mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- }
- };
-
+ private boolean mInZoomTapDragMode = false;
+
// Whether to prevent drag during touch. The initial value depends on
// mForwardTouchEvents. If WebCore wants touch events, we assume it will
// take control of touch events unless it says no for touch down event.
@@ -517,6 +506,11 @@ public class WebView extends AbsoluteLayout
private ZoomRingController mZoomRingController;
+ // These keep track of the center point of the zoom ring. They are used to
+ // determine the point around which we should zoom.
+ private float mZoomCenterX;
+ private float mZoomCenterY;
+
private ZoomRingController.OnZoomListener mZoomListener =
new ZoomRingController.OnZoomListener() {
@@ -554,12 +548,9 @@ public class WebView extends AbsoluteLayout
deltaZoomLevel == 0) {
return false;
}
-
- int deltaX = centerX - getViewWidth() / 2;
- int deltaY = centerY - getViewHeight() / 2;
+ mZoomCenterX = (float) centerX;
+ mZoomCenterY = (float) centerY;
- pinScrollBy(deltaX, deltaY, false, 0);
-
while (deltaZoomLevel != 0) {
if (deltaZoomLevel > 0) {
if (!zoomIn()) return false;
@@ -569,15 +560,16 @@ public class WebView extends AbsoluteLayout
deltaZoomLevel++;
}
}
-
- pinScrollBy(-deltaX, -deltaY, false, 0);
-
+
return true;
}
public void onSimpleZoom(boolean zoomIn) {
- if (zoomIn) zoomIn();
- else zoomOut();
+ if (zoomIn) {
+ zoomIn();
+ } else {
+ zoomOut();
+ }
}
};
@@ -1586,8 +1578,8 @@ public class WebView extends AbsoluteLayout
int oldX = mScrollX;
int oldY = mScrollY;
float ratio = scale * mInvActualScale; // old inverse
- float sx = ratio * oldX + (ratio - 1) * getViewWidth() * 0.5f;
- float sy = ratio * oldY + (ratio - 1) * getViewHeight() * 0.5f;
+ float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
+ float sy = ratio * oldY + (ratio - 1) * mZoomCenterY;
// now update our new scale and inverse
if (scale != mActualScale && !mPreviewZoomOnly) {
@@ -2264,8 +2256,8 @@ public class WebView extends AbsoluteLayout
zoomScale = mZoomScale;
}
float scale = (mActualScale - zoomScale) * mInvActualScale;
- float tx = scale * ((getLeft() + getRight()) * 0.5f + mScrollX);
- float ty = scale * ((getTop() + getBottom()) * 0.5f + mScrollY);
+ float tx = scale * (mZoomCenterX + mScrollX);
+ float ty = scale * (mZoomCenterY + mScrollY);
// this block pins the translate to "legal" bounds. This makes the
// animation a bit non-obvious, but it means we won't pop when the
@@ -3025,8 +3017,8 @@ public class WebView extends AbsoluteLayout
(keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
break;
case KeyEvent.KEYCODE_9:
- debugDump();
- break;
+ nativeInstrumentReport();
+ return true;
}
}
@@ -3161,6 +3153,7 @@ public class WebView extends AbsoluteLayout
* @hide
*/
public void emulateShiftHeld() {
+ mExtendSelection = false;
mShiftIsPressed = true;
}
@@ -3176,6 +3169,7 @@ public class WebView extends AbsoluteLayout
mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
copiedSomething = true;
}
+ mExtendSelection = false;
}
mShiftIsPressed = false;
if (mTouchMode == TOUCH_SELECT_MODE) {
@@ -3218,6 +3212,11 @@ public class WebView extends AbsoluteLayout
}
}
+ /**
+ * @deprecated WebView should not have implemented
+ * ViewTreeObserver.OnGlobalFocusChangeListener. This method
+ * does nothing now.
+ */
@Deprecated
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
}
@@ -3281,7 +3280,11 @@ public class WebView extends AbsoluteLayout
@Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
-
+ // Center zooming to the center of the screen. This is appropriate for
+ // this case of zooming, and it also sets us up properly if we remove
+ // the new zoom ring controller
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
// we always force, in case our height changed, in which case we still
// want to send the notification over to webkit
setNewZoomScale(mActualScale, true);
@@ -3342,25 +3345,12 @@ public class WebView extends AbsoluteLayout
+ mTouchMode);
}
- if (mZoomRingController.isVisible()) {
- if (mInZoomTapDragMode) {
- mZoomRingController.handleDoubleTapEvent(ev);
- if (ev.getAction() == MotionEvent.ACTION_UP) {
- // Just released the second tap, no longer in tap-drag mode
- mInZoomTapDragMode = false;
- }
- return true;
- } else {
- // TODO: properly do this.
- /*
- * When the zoom widget is showing, the user can tap outside of
- * it to dismiss it. Furthermore, he can drag outside of it to
- * pan the browser. However, we do not want a tap on a link to
- * open the link.
- */
- post(mRemoveReleaseSingleTap);
- // Continue through to normal processing
+ if (mZoomRingController.isVisible() && mInZoomTapDragMode) {
+ if (ev.getAction() == MotionEvent.ACTION_UP) {
+ // Just released the second tap, no longer in tap-drag mode
+ mInZoomTapDragMode = false;
}
+ return mZoomRingController.handleDoubleTapEvent(ev);
}
int action = ev.getAction();
@@ -3418,21 +3408,19 @@ public class WebView extends AbsoluteLayout
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
} else if (!ZoomRingController.useOldZoom(mContext) &&
- eventTime - mPreviousUpTime < DOUBLE_TAP_TIMEOUT &&
- getSettings().supportZoom() &&
- mMinZoomScale < mMaxZoomScale) {
+ mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
// Found doubletap, invoke the zoom controller
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
mZoomRingController.setVisible(true);
mInZoomTapDragMode = true;
- mZoomRingController.handleDoubleTapEvent(ev);
+ return mZoomRingController.handleDoubleTapEvent(ev);
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
}
- if (mTouchMode == TOUCH_INIT_MODE) {
+ // don't trigger the link if zoom ring is visible
+ if (mTouchMode == TOUCH_INIT_MODE
+ && !mZoomRingController.isVisible()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
@@ -3485,9 +3473,6 @@ public class WebView extends AbsoluteLayout
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
- // Prevent double-tap from being invoked
- mPreviousUpTime = 0;
-
// if it starts nearly horizontal or vertical, enforce it
int ax = Math.abs(deltaX);
int ay = Math.abs(deltaY);
@@ -3597,6 +3582,10 @@ public class WebView extends AbsoluteLayout
case MotionEvent.ACTION_UP: {
switch (mTouchMode) {
case TOUCH_INIT_MODE: // tap
+ if (mZoomRingController.isVisible()) {
+ // don't trigger the link if zoom ring is visible
+ break;
+ }
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
if (getSettings().supportZoom()
&& (mMinZoomScale < mMaxZoomScale)) {
@@ -3611,7 +3600,7 @@ public class WebView extends AbsoluteLayout
break;
case TOUCH_SELECT_MODE:
commitCopy();
- mTouchSelection = mExtendSelection = false;
+ mTouchSelection = false;
break;
case SCROLL_ZOOM_ANIMATION_IN:
case SCROLL_ZOOM_ANIMATION_OUT:
@@ -3679,7 +3668,6 @@ public class WebView extends AbsoluteLayout
mVelocityTracker.recycle();
mVelocityTracker = null;
}
- mPreviousUpTime = eventTime;
break;
}
case MotionEvent.ACTION_CANCEL: {
@@ -4109,6 +4097,14 @@ public class WebView extends AbsoluteLayout
return mZoomControls;
}
+ /**
+ * @hide pending API council? Assuming we make ZoomRingController itself
+ * public, which I think we will.
+ */
+ public ZoomRingController getZoomRingController() {
+ return mZoomRingController;
+ }
+
/**
* Perform zoom in in the webview
* @return TRUE if zoom in succeeds. FALSE if no zoom changes.
@@ -4193,16 +4189,15 @@ public class WebView extends AbsoluteLayout
return;
}
switchOutDrawHistory();
- // FIXME: we don't know if the current (x,y) is on a focus node or
- // not -- so playing the sound effect here is premature
- if (nativeUpdateFocusNode()) {
- playSoundEffect(SoundEffectConstants.CLICK);
- }
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
int contentSize = ViewConfiguration.get(getContext()).getScaledTouchSlop();
nativeMotionUp(contentX, contentY, contentSize, true);
+ if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
+ && !mFocusNode.mIsTextArea) {
+ playSoundEffect(SoundEffectConstants.CLICK);
+ }
}
@Override
@@ -5013,6 +5008,7 @@ public class WebView extends AbsoluteLayout
private native boolean nativeUpdateFocusNode();
private native Rect nativeGetFocusRingBounds();
private native Rect nativeGetNavBounds();
+ private native void nativeInstrumentReport();
private native void nativeMarkNodeInvalid(int node);
private native void nativeMotionUp(int x, int y, int slop, boolean isClick);
// returns false if it handled the key
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8f788872bfe1b..b979032f55dea 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -330,8 +330,7 @@ final class WebViewCore {
String currentText, int keyCode, int keyValue, boolean down,
boolean cap, boolean fn, boolean sym);
- private native void nativeSaveDocumentState(int frame, int node, int x,
- int y);
+ private native void nativeSaveDocumentState(int frame);
private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
int y, boolean block);
@@ -777,8 +776,7 @@ final class WebViewCore {
case SAVE_DOCUMENT_STATE: {
FocusData fDat = (FocusData) msg.obj;
- nativeSaveDocumentState(fDat.mFrame, fDat.mNode,
- fDat.mX, fDat.mY);
+ nativeSaveDocumentState(fDat.mFrame);
break;
}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 96f36983343a5..1004e30ef5e62 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -531,33 +531,34 @@ public class WebViewDatabase {
* @param url The url
* @return CacheResult The CacheManager.CacheResult
*/
- @SuppressWarnings("deprecation")
CacheResult getCache(String url) {
if (url == null || mCacheDatabase == null) {
return null;
}
- CacheResult ret = null;
- final String s = "SELECT filepath, lastmodify, etag, expires, mimetype, encoding, httpstatus, location, contentlength FROM cache WHERE url = ";
- StringBuilder sb = new StringBuilder(256);
- sb.append(s);
- DatabaseUtils.appendEscapedSQLString(sb, url);
- Cursor cursor = mCacheDatabase.rawQuery(sb.toString(), null);
+ Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
+ + "mimetype, encoding, httpstatus, location, contentlength "
+ + "FROM cache WHERE url = ?",
+ new String[] { url });
- if (cursor.moveToFirst()) {
- ret = new CacheResult();
- ret.localPath = cursor.getString(0);
- ret.lastModified = cursor.getString(1);
- ret.etag = cursor.getString(2);
- ret.expires = cursor.getLong(3);
- ret.mimeType = cursor.getString(4);
- ret.encoding = cursor.getString(5);
- ret.httpStatusCode = cursor.getInt(6);
- ret.location = cursor.getString(7);
- ret.contentLength = cursor.getLong(8);
+ try {
+ if (cursor.moveToFirst()) {
+ CacheResult ret = new CacheResult();
+ ret.localPath = cursor.getString(0);
+ ret.lastModified = cursor.getString(1);
+ ret.etag = cursor.getString(2);
+ ret.expires = cursor.getLong(3);
+ ret.mimeType = cursor.getString(4);
+ ret.encoding = cursor.getString(5);
+ ret.httpStatusCode = cursor.getInt(6);
+ ret.location = cursor.getString(7);
+ ret.contentLength = cursor.getLong(8);
+ return ret;
+ }
+ } finally {
+ if (cursor != null) cursor.close();
}
- cursor.close();
- return ret;
+ return null;
}
/**
@@ -565,16 +566,12 @@ public class WebViewDatabase {
*
* @param url The url
*/
- @SuppressWarnings("deprecation")
void removeCache(String url) {
if (url == null || mCacheDatabase == null) {
return;
}
- StringBuilder sb = new StringBuilder(256);
- sb.append("DELETE FROM cache WHERE url = ");
- DatabaseUtils.appendEscapedSQLString(sb, url);
- mCacheDatabase.execSQL(sb.toString());
+ mCacheDatabase.execSQL("DELETE FROM cache WHERE url = ?", new String[] { url });
}
/**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 378d2183a7db8..c012e25cf0c55 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -31,6 +31,7 @@ import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -1622,6 +1623,9 @@ public abstract class AbsListView extends AdapterView implements Te
mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
handled = super.showContextMenuForChild(AbsListView.this);
}
+ if (handled) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
return handled;
}
diff --git a/core/java/android/widget/CursorFilter.java b/core/java/android/widget/CursorFilter.java
index afd5b10e0dd31..dbded69364f3f 100644
--- a/core/java/android/widget/CursorFilter.java
+++ b/core/java/android/widget/CursorFilter.java
@@ -60,11 +60,10 @@ class CursorFilter extends Filter {
}
@Override
- protected void publishResults(CharSequence constraint,
- FilterResults results) {
+ protected void publishResults(CharSequence constraint, FilterResults results) {
Cursor oldCursor = mClient.getCursor();
- if (results.values != oldCursor) {
+ if (results.values != null && results.values != oldCursor) {
mClient.changeCursor((Cursor) results.values);
}
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 67010b2dcece8..54f27072b4f93 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -47,11 +47,8 @@ public class DatePicker extends FrameLayout {
/* UI Components */
private final NumberPicker mDayPicker;
private final NumberPicker mMonthPicker;
- private final NumberPicker mYearPicker;
-
- private final int mStartYear;
- private final int mEndYear;
-
+ private final NumberPicker mYearPicker;
+
/**
* How we notify users the date has changed.
*/
@@ -87,12 +84,9 @@ public class DatePicker extends FrameLayout {
public DatePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.date_picker,
- this, // we are the parent
- true);
-
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.date_picker, this, true);
+
mDayPicker = (NumberPicker) findViewById(R.id.day);
mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
mDayPicker.setSpeed(100);
@@ -134,20 +128,17 @@ public class DatePicker extends FrameLayout {
});
// attributes
- TypedArray a = context
- .obtainStyledAttributes(attrs, R.styleable.DatePicker);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
- mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
- mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
+ int mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
+ int mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
mYearPicker.setRange(mStartYear, mEndYear);
a.recycle();
// initialize to current date
Calendar cal = Calendar.getInstance();
- init(cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH), null);
+ init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null);
// re-order the number pickers to match the current date format
reorderPickers();
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 7f1601e581c8d..a2316cf6c7bf7 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -20,6 +20,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
/**
* A filter constrains data with a filtering pattern.
@@ -36,6 +37,8 @@ import android.os.Message;
* @see android.widget.Filterable
*/
public abstract class Filter {
+ private static final String LOG_TAG = "Filter";
+
private static final String THREAD_NAME = "Filter";
private static final int FILTER_TOKEN = 0xD0D0F00D;
private static final int FINISH_TOKEN = 0xDEADBEEF;
@@ -221,6 +224,9 @@ public abstract class Filter {
RequestArguments args = (RequestArguments) msg.obj;
try {
args.results = performFiltering(args.constraint);
+ } catch (Exception e) {
+ args.results = new FilterResults();
+ Log.w(LOG_TAG, "An exception occured during performFiltering()!", e);
} finally {
message = mResultHandler.obtainMessage(what);
message.obj = args;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index ffabb02270601..e7b303ada4d06 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -27,6 +27,7 @@ import android.util.Config;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -994,6 +995,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
return;
}
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
long id = getItemIdAtPosition(mDownTouchPosition);
dispatchLongPress(mDownTouchView, mDownTouchPosition, id);
}
@@ -1086,6 +1088,10 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
handled = super.showContextMenuForChild(this);
}
+ if (handled) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
+
return handled;
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b5d4e2d5a6d49..4ae322e1fb012 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -48,6 +48,7 @@ import android.widget.RemoteViews.RemoteView;
* @attr ref android.R.styleable#ImageView_maxHeight
* @attr ref android.R.styleable#ImageView_tint
* @attr ref android.R.styleable#ImageView_scaleType
+ * @attr ref android.R.styleable#ImageView_cropToPadding
*/
@RemoteView
public class ImageView extends View {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index a1023bdc5d7df..25afee83a548c 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -35,6 +35,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater.Filter;
import android.view.View.OnClickListener;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -547,6 +549,54 @@ public class RemoteViews implements Parcelable, Filter {
public final static int TAG = 9;
}
+ /**
+ * Equivalent to calling {@link android.widget.ViewFlipper#startFlipping()}
+ * or {@link android.widget.ViewFlipper#stopFlipping()} along with
+ * {@link android.widget.ViewFlipper#setFlipInterval(int)}.
+ */
+ private class SetFlipping extends Action {
+ public SetFlipping(int id, boolean flipping, int milliseconds) {
+ this.viewId = id;
+ this.flipping = flipping;
+ this.milliseconds = milliseconds;
+ }
+
+ public SetFlipping(Parcel parcel) {
+ viewId = parcel.readInt();
+ flipping = parcel.readInt() != 0;
+ milliseconds = parcel.readInt();
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(TAG);
+ dest.writeInt(viewId);
+ dest.writeInt(flipping ? 1 : 0);
+ dest.writeInt(milliseconds);
+ }
+
+ @Override
+ public void apply(View root) {
+ final View target = root.findViewById(viewId);
+ if (target instanceof ViewFlipper) {
+ final ViewFlipper flipper = (ViewFlipper) target;
+ if (milliseconds != -1) {
+ flipper.setFlipInterval(milliseconds);
+ }
+ if (flipping) {
+ flipper.startFlipping();
+ } else {
+ flipper.stopFlipping();
+ }
+ }
+ }
+
+ int viewId;
+ boolean flipping;
+ int milliseconds;
+
+ public final static int TAG = 10;
+ }
+
/**
* Create a new RemoteViews object that will display the views contained
* in the specified layout file.
@@ -603,6 +653,9 @@ public class RemoteViews implements Parcelable, Filter {
case SetTextColor.TAG:
mActions.add(new SetTextColor(parcel));
break;
+ case SetFlipping.TAG:
+ mActions.add(new SetFlipping(parcel));
+ break;
default:
throw new ActionException("Tag " + tag + "not found");
}
@@ -768,6 +821,22 @@ public class RemoteViews implements Parcelable, Filter {
addAction(new SetTextColor(viewId, color));
}
+ /**
+ * Equivalent to calling {@link android.widget.ViewFlipper#startFlipping()}
+ * or {@link android.widget.ViewFlipper#stopFlipping()} along with
+ * {@link android.widget.ViewFlipper#setFlipInterval(int)}.
+ *
+ * @param viewId The id of the view to apply changes to
+ * @param flipping True means we should
+ * {@link android.widget.ViewFlipper#startFlipping()}, otherwise
+ * {@link android.widget.ViewFlipper#stopFlipping()}.
+ * @param milliseconds How long to wait before flipping to the next view, or
+ * -1 to leave unchanged.
+ */
+ public void setFlipping(int viewId, boolean flipping, int milliseconds) {
+ addAction(new SetFlipping(viewId, flipping, milliseconds));
+ }
+
/**
* Inflates the view hierarchy represented by this object and applies
* all of the actions.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d21c01722d967..2ae5d4ee53645 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3844,7 +3844,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boolean doDown = true;
if (otherEvent != null) {
try {
- boolean handled = mMovement.onKeyOther(this, (Editable) mText,
+ boolean handled = mMovement.onKeyOther(this, (Spannable) mText,
otherEvent);
doDown = false;
if (handled) {
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index 8c652e5ead345..fa8935e3bc552 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -28,6 +28,9 @@ import android.view.animation.AnimationUtils;
/**
* Base class for a {@link FrameLayout} container that will perform animations
* when switching between its views.
+ *
+ * @attr ref android.R.styleable#ViewAnimator_inAnimation
+ * @attr ref android.R.styleable#ViewAnimator_outAnimation
*/
public class ViewAnimator extends FrameLayout {
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index a3c15d945b3b2..e20bfdf0f52fc 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -22,12 +22,16 @@ import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
+import android.widget.RemoteViews.RemoteView;
/**
* Simple {@link ViewAnimator} that will animate between two or more views
* that have been added to it. Only one child is shown at a time. If
* requested, can automatically flip between each child at a regular interval.
+ *
+ * @attr ref android.R.styleable#ViewFlipper_flipInterval
*/
+@RemoteView
public class ViewFlipper extends ViewAnimator {
private int mFlipInterval = 3000;
private boolean mKeepFlipping = false;
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index df3f307a3cbcf..0df919d02a5f3 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -57,6 +58,7 @@ public class ZoomButton extends ImageButton implements OnLongClickListener {
mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
onLongClick(ZoomButton.this);
}
});
diff --git a/core/java/android/widget/ZoomRing.java b/core/java/android/widget/ZoomRing.java
index 20d605617075f..be3b1fbd527fb 100644
--- a/core/java/android/widget/ZoomRing.java
+++ b/core/java/android/widget/ZoomRing.java
@@ -6,10 +6,9 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
+import android.graphics.drawable.RotateDrawable;
import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -18,17 +17,20 @@ import android.view.ViewConfiguration;
* @hide
*/
public class ZoomRing extends View {
-
+
// TODO: move to ViewConfiguration?
- private static final int DOUBLE_TAP_DISMISS_TIMEOUT = ViewConfiguration.getJumpTapTimeout();
+ static final int DOUBLE_TAP_DISMISS_TIMEOUT = ViewConfiguration.getJumpTapTimeout();
// TODO: get from theme
private static final int DISABLED_ALPHA = 160;
-
+
private static final String TAG = "ZoomRing";
+ // TODO: Temporary until the trail is done
+ private static final boolean DRAW_TRAIL = false;
+
// TODO: xml
- private static final int THUMB_DISTANCE = 63;
-
+ private static final int THUMB_DISTANCE = 63;
+
/** To avoid floating point calculations, we multiply radians by this value. */
public static final int RADIAN_INT_MULTIPLIER = 100000000;
/** PI using our multiplier. */
@@ -36,68 +38,81 @@ public class ZoomRing extends View {
/** PI/2 using our multiplier. */
private static final int HALF_PI_INT_MULTIPLIED = PI_INT_MULTIPLIED / 2;
+ private int mZeroAngle = HALF_PI_INT_MULTIPLIED * 3;
+
private static final int THUMB_GRAB_SLOP = PI_INT_MULTIPLIED / 4;
-
+
/** The cached X of our center. */
private int mCenterX;
- /** The cached Y of our center. */
+ /** The cached Y of our center. */
private int mCenterY;
/** The angle of the thumb (in int radians) */
private int mThumbAngle;
private boolean mIsThumbAngleValid;
- private int mThumbCenterX;
- private int mThumbCenterY;
private int mThumbHalfWidth;
private int mThumbHalfHeight;
-
- private int mCallbackThreshold = Integer.MAX_VALUE;
-
- /** The accumulated amount of drag for the thumb (in int radians). */
- private int mAcculumalatedThumbDrag = 0;
-
+
/** The inner radius of the track. */
private int mBoundInnerRadiusSquared = 0;
/** The outer radius of the track. */
private int mBoundOuterRadiusSquared = Integer.MAX_VALUE;
-
+
private int mPreviousWidgetDragX;
private int mPreviousWidgetDragY;
-
+
private boolean mDrawThumb = true;
private Drawable mThumbDrawable;
-
+
private static final int MODE_IDLE = 0;
private static final int MODE_DRAG_THUMB = 1;
+ /**
+ * User has his finger down, but we are waiting for him to pass the touch
+ * slop before going into the #MODE_MOVE_ZOOM_RING. This is a good time to
+ * show the movable hint.
+ */
+ private static final int MODE_WAITING_FOR_MOVE_ZOOM_RING = 4;
private static final int MODE_MOVE_ZOOM_RING = 2;
private static final int MODE_TAP_DRAG = 3;
private int mMode;
- private long mPreviousTapTime;
-
- private Handler mHandler = new Handler();
-
+ private long mPreviousDownTime;
+ private int mPreviousDownX;
+ private int mPreviousDownY;
+
private Disabler mDisabler = new Disabler();
-
+
private OnZoomRingCallback mCallback;
-
+ private int mPreviousCallbackAngle;
+ private int mCallbackThreshold = Integer.MAX_VALUE;
+
private boolean mResetThumbAutomatically = true;
private int mThumbDragStartAngle;
-
+ private final int mTouchSlop;
+ private Drawable mTrail;
+ private double mAcculumalatedTrailAngle;
+
public ZoomRing(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- // TODO get drawable from style instead
+
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
+ mTouchSlop = viewConfiguration.getScaledTouchSlop();
+
+ // TODO get drawables from style instead
Resources res = context.getResources();
mThumbDrawable = res.getDrawable(R.drawable.zoom_ring_thumb);
-
+ if (DRAW_TRAIL) {
+ mTrail = res.getDrawable(R.drawable.zoom_ring_trail).mutate();
+ }
+
// TODO: add padding to drawable
setBackgroundResource(R.drawable.zoom_ring_track);
// TODO get from style
setBounds(30, Integer.MAX_VALUE);
-
+
mThumbHalfHeight = mThumbDrawable.getIntrinsicHeight() / 2;
mThumbHalfWidth = mThumbDrawable.getIntrinsicWidth() / 2;
-
+
mCallbackThreshold = PI_INT_MULTIPLIED / 6;
}
@@ -108,7 +123,7 @@ public class ZoomRing extends View {
public ZoomRing(Context context) {
this(context, null);
}
-
+
public void setCallback(OnZoomRingCallback callback) {
mCallback = callback;
}
@@ -132,26 +147,49 @@ public class ZoomRing extends View {
mBoundOuterRadiusSquared = Integer.MAX_VALUE;
}
}
-
+
public void setThumbAngle(int angle) {
mThumbAngle = angle;
- mThumbCenterX = (int) (Math.cos(1f * angle / RADIAN_INT_MULTIPLIER) * THUMB_DISTANCE)
- + mCenterX;
- mThumbCenterY = (int) (Math.sin(1f * angle / RADIAN_INT_MULTIPLIER) * THUMB_DISTANCE)
- * -1 + mCenterY;
+ int unoffsetAngle = angle + mZeroAngle;
+ int thumbCenterX = (int) (Math.cos(1f * unoffsetAngle / RADIAN_INT_MULTIPLIER) *
+ THUMB_DISTANCE) + mCenterX;
+ int thumbCenterY = (int) (Math.sin(1f * unoffsetAngle / RADIAN_INT_MULTIPLIER) *
+ THUMB_DISTANCE) * -1 + mCenterY;
+
+ mThumbDrawable.setBounds(thumbCenterX - mThumbHalfWidth,
+ thumbCenterY - mThumbHalfHeight,
+ thumbCenterX + mThumbHalfWidth,
+ thumbCenterY + mThumbHalfHeight);
+
+ if (DRAW_TRAIL) {
+ double degrees;
+ degrees = Math.min(359.0, Math.abs(mAcculumalatedTrailAngle));
+ int level = (int) (10000.0 * degrees / 360.0);
+
+ mTrail.setLevel((int) (10000.0 *
+ (-Math.toDegrees(angle / (double) RADIAN_INT_MULTIPLIER) -
+ degrees + 90) / 360.0));
+ ((RotateDrawable) mTrail).getDrawable().setLevel(level);
+ }
+
invalidate();
}
-
+
+ public void resetThumbAngle(int angle) {
+ mPreviousCallbackAngle = angle;
+ setThumbAngle(angle);
+ }
+
public void resetThumbAngle() {
if (mResetThumbAutomatically) {
- setThumbAngle(HALF_PI_INT_MULTIPLIED);
+ resetThumbAngle(0);
}
}
-
+
public void setResetThumbAutomatically(boolean resetThumbAutomatically) {
mResetThumbAutomatically = resetThumbAutomatically;
}
-
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec),
@@ -162,7 +200,7 @@ public class ZoomRing extends View {
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
-
+
// Cache the center point
mCenterX = (right - left) / 2;
mCenterY = (bottom - top) / 2;
@@ -172,8 +210,12 @@ public class ZoomRing extends View {
if (mThumbAngle == Integer.MIN_VALUE) {
resetThumbAngle();
}
+
+ if (DRAW_TRAIL) {
+ mTrail.setBounds(0, 0, right - left, bottom - top);
+ }
}
-
+
@Override
public boolean onTouchEvent(MotionEvent event) {
return handleTouch(event.getAction(), event.getEventTime(),
@@ -184,61 +226,66 @@ public class ZoomRing extends View {
private void resetState() {
mMode = MODE_IDLE;
mPreviousWidgetDragX = mPreviousWidgetDragY = Integer.MIN_VALUE;
- mAcculumalatedThumbDrag = 0;
+ mAcculumalatedTrailAngle = 0.0;
mIsThumbAngleValid = false;
}
-
+
public void setTapDragMode(boolean tapDragMode, int x, int y) {
resetState();
mMode = tapDragMode ? MODE_TAP_DRAG : MODE_IDLE;
mIsThumbAngleValid = false;
-
+
if (tapDragMode && mCallback != null) {
onThumbDragStarted(getAngle(x - mCenterX, y - mCenterY));
}
}
-
+
public boolean handleTouch(int action, long time, int x, int y, int rawX, int rawY) {
switch (action) {
-
+
case MotionEvent.ACTION_DOWN:
- if (mPreviousTapTime + DOUBLE_TAP_DISMISS_TIMEOUT >= time) {
+ if (mPreviousDownTime + DOUBLE_TAP_DISMISS_TIMEOUT >= time) {
if (mCallback != null) {
mCallback.onZoomRingDismissed();
}
} else {
- mPreviousTapTime = time;
+ mPreviousDownTime = time;
+ mPreviousDownX = x;
+ mPreviousDownY = y;
}
resetState();
return true;
-
+
case MotionEvent.ACTION_MOVE:
// Fall through to code below switch
break;
-
+
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mCallback != null) {
- if (mMode == MODE_MOVE_ZOOM_RING) {
- mCallback.onZoomRingMovingStopped();
+ if (mMode == MODE_MOVE_ZOOM_RING || mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+ mCallback.onZoomRingSetMovableHintVisible(false);
+ if (mMode == MODE_MOVE_ZOOM_RING) {
+ mCallback.onZoomRingMovingStopped();
+ }
} else if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG) {
onThumbDragStopped(getAngle(x - mCenterX, y - mCenterY));
}
}
mDisabler.setEnabling(true);
return true;
-
+
default:
return false;
}
-
+
// local{X,Y} will be where the center of the widget is (0,0)
int localX = x - mCenterX;
int localY = y - mCenterY;
boolean isTouchingThumb = true;
boolean isInBounds = true;
int touchAngle = getAngle(localX, localY);
-
+
int radiusSquared = localX * localX + localY * localY;
if (radiusSquared < mBoundInnerRadiusSquared ||
radiusSquared > mBoundOuterRadiusSquared) {
@@ -246,7 +293,7 @@ public class ZoomRing extends View {
isTouchingThumb = false;
isInBounds = false;
}
-
+
int deltaThumbAndTouch = getDelta(touchAngle, mThumbAngle);
int absoluteDeltaThumbAndTouch = deltaThumbAndTouch >= 0 ?
deltaThumbAndTouch : -deltaThumbAndTouch;
@@ -255,19 +302,35 @@ public class ZoomRing extends View {
// Didn't grab close enough to the thumb
isTouchingThumb = false;
}
-
+
if (mMode == MODE_IDLE) {
- mMode = isTouchingThumb ? MODE_DRAG_THUMB : MODE_MOVE_ZOOM_RING;
-
+ if (isTouchingThumb) {
+ mMode = MODE_DRAG_THUMB;
+ } else {
+ mMode = MODE_WAITING_FOR_MOVE_ZOOM_RING;
+ }
+
if (mCallback != null) {
if (mMode == MODE_DRAG_THUMB) {
onThumbDragStarted(touchAngle);
- } else if (mMode == MODE_MOVE_ZOOM_RING) {
+ } else if (mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+ mCallback.onZoomRingSetMovableHintVisible(true);
+ }
+ }
+
+ } else if (mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) {
+ if (Math.abs(x - mPreviousDownX) > mTouchSlop ||
+ Math.abs(y - mPreviousDownY) > mTouchSlop) {
+ /* Make sure the user has moved the slop amount before going into that mode. */
+ mMode = MODE_MOVE_ZOOM_RING;
+
+ if (mCallback != null) {
mCallback.onZoomRingMovingStarted();
}
}
}
-
+
+ // Purposefully not an "else if"
if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG) {
if (isInBounds) {
onThumbDragged(touchAngle, mIsThumbAngleValid ? deltaThumbAndTouch : 0);
@@ -277,13 +340,13 @@ public class ZoomRing extends View {
} else if (mMode == MODE_MOVE_ZOOM_RING) {
onZoomRingMoved(rawX, rawY);
}
-
+
return true;
}
-
+
private int getDelta(int angle1, int angle2) {
int delta = angle1 - angle2;
-
+
// Assume this is a result of crossing over the discontinuous 0 -> 2pi
if (delta > PI_INT_MULTIPLIED || delta < -PI_INT_MULTIPLIED) {
// Bring both the radians and previous angle onto a continuous range
@@ -295,7 +358,7 @@ public class ZoomRing extends View {
delta -= PI_INT_MULTIPLIED * 2;
}
}
-
+
return delta;
}
@@ -303,46 +366,69 @@ public class ZoomRing extends View {
mThumbDragStartAngle = startAngle;
mCallback.onZoomRingThumbDraggingStarted(startAngle);
}
-
+
private void onThumbDragged(int touchAngle, int deltaAngle) {
- mAcculumalatedThumbDrag += deltaAngle;
- if (mAcculumalatedThumbDrag > mCallbackThreshold
- || mAcculumalatedThumbDrag < -mCallbackThreshold) {
+ mAcculumalatedTrailAngle += Math.toDegrees(deltaAngle / (double) RADIAN_INT_MULTIPLIER);
+ int totalDeltaAngle = getDelta(touchAngle, mPreviousCallbackAngle);
+ if (totalDeltaAngle > mCallbackThreshold
+ || totalDeltaAngle < -mCallbackThreshold) {
if (mCallback != null) {
boolean canStillZoom = mCallback.onZoomRingThumbDragged(
- mAcculumalatedThumbDrag / mCallbackThreshold,
- mAcculumalatedThumbDrag, mThumbDragStartAngle, touchAngle);
+ totalDeltaAngle / mCallbackThreshold,
+ mThumbDragStartAngle, touchAngle);
mDisabler.setEnabling(canStillZoom);
+
+ if (canStillZoom) {
+ // TODO: we're trying the haptics to see how it goes with
+ // users, so we're ignoring the settings (for now)
+ performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK,
+ HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING |
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
}
- mAcculumalatedThumbDrag = 0;
+
+ // Get the closest tick and lock on there
+ mPreviousCallbackAngle = getClosestTickAngle(touchAngle);
}
-
+
setThumbAngle(touchAngle);
mIsThumbAngleValid = true;
}
-
+
+ private int getClosestTickAngle(int angle) {
+ int smallerAngleDistance = angle % mCallbackThreshold;
+ int smallerAngle = angle - smallerAngleDistance;
+ if (smallerAngleDistance < mCallbackThreshold / 2) {
+ // Closer to the smaller angle
+ return smallerAngle;
+ } else {
+ // Closer to the bigger angle (premodding)
+ return (smallerAngle + mCallbackThreshold) % (PI_INT_MULTIPLIED * 2);
+ }
+ }
+
private void onThumbDragStopped(int stopAngle) {
mCallback.onZoomRingThumbDraggingStopped(stopAngle);
}
-
+
private void onZoomRingMoved(int x, int y) {
if (mPreviousWidgetDragX != Integer.MIN_VALUE) {
int deltaX = x - mPreviousWidgetDragX;
int deltaY = y - mPreviousWidgetDragY;
-
+
if (mCallback != null) {
mCallback.onZoomRingMoved(deltaX, deltaY);
}
}
-
+
mPreviousWidgetDragX = x;
mPreviousWidgetDragY = y;
}
-
+
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
-
+
if (!hasWindowFocus && mCallback != null) {
mCallback.onZoomRingDismissed();
}
@@ -353,22 +439,25 @@ public class ZoomRing extends View {
// Convert from [-pi,pi] to {0,2pi]
if (radians < 0) {
- return -radians;
+ radians = -radians;
} else if (radians > 0) {
- return 2 * PI_INT_MULTIPLIED - radians;
+ radians = 2 * PI_INT_MULTIPLIED - radians;
} else {
- return 0;
+ radians = 0;
}
+
+ radians = radians - mZeroAngle;
+ return radians >= 0 ? radians : radians + 2 * PI_INT_MULTIPLIED;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
-
+
if (mDrawThumb) {
- mThumbDrawable.setBounds(mThumbCenterX - mThumbHalfWidth, mThumbCenterY
- - mThumbHalfHeight, mThumbCenterX + mThumbHalfWidth, mThumbCenterY
- + mThumbHalfHeight);
+ if (DRAW_TRAIL) {
+ mTrail.draw(canvas);
+ }
mThumbDrawable.draw(canvas);
}
}
@@ -409,12 +498,14 @@ public class ZoomRing extends View {
}
public interface OnZoomRingCallback {
+ void onZoomRingSetMovableHintVisible(boolean visible);
+
void onZoomRingMovingStarted();
boolean onZoomRingMoved(int deltaX, int deltaY);
void onZoomRingMovingStopped();
void onZoomRingThumbDraggingStarted(int startAngle);
- boolean onZoomRingThumbDragged(int numLevels, int dragAmount, int startAngle, int curAngle);
+ boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle);
void onZoomRingThumbDraggingStopped(int endAngle);
void onZoomRingDismissed();
diff --git a/core/java/android/widget/ZoomRingController.java b/core/java/android/widget/ZoomRingController.java
index 2ca03741b7b5a..eb287670c7a16 100644
--- a/core/java/android/widget/ZoomRingController.java
+++ b/core/java/android/widget/ZoomRingController.java
@@ -17,14 +17,17 @@
package android.widget;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.os.Vibrator;
import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
@@ -42,6 +45,7 @@ import android.view.animation.DecelerateInterpolator;
/**
* TODO: Docs
+ *
* @hide
*/
public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
@@ -222,7 +226,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
public ZoomRingController(Context context, View ownerView) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-
+
mOwnerView = ownerView;
mZoomRing = new ZoomRing(context);
@@ -437,7 +441,15 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
case MotionEvent.ACTION_UP:
mTouchMode = TOUCH_MODE_IDLE;
+
+ /*
+ * This is a power-user feature that only shows the
+ * zoom while the user is performing the tap-drag.
+ * That means once it is released, the zoom ring
+ * should disappear.
+ */
mZoomRing.setTapDragMode(false, (int) event.getX(), (int) event.getY());
+ dismissZoomRingDelayed(0);
break;
}
break;
@@ -560,10 +572,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
mZoomRing.handleTouch(event.getAction(), event.getEventTime(), x, y, rawX, rawY);
}
+ public void onZoomRingSetMovableHintVisible(boolean visible) {
+ setPanningArrowsVisible(visible);
+ }
+
public void onZoomRingMovingStarted() {
mHandler.removeMessages(MSG_DISMISS_ZOOM_RING);
mScroller.abortAnimation();
- setPanningArrowsVisible(true);
}
private void setPanningArrowsVisible(boolean visible) {
@@ -641,8 +656,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
}
}
- public boolean onZoomRingThumbDragged(int numLevels, int dragAmount, int startAngle,
- int curAngle) {
+ public boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle) {
if (mCallback != null) {
int deltaZoomLevel = -numLevels;
int globalZoomCenterX = mContainerLayoutParams.x + mZoomRing.getLeft() +
@@ -650,7 +664,8 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
int globalZoomCenterY = mContainerLayoutParams.y + mZoomRing.getTop() +
mZoomRingHeight / 2;
- return mCallback.onDragZoom(deltaZoomLevel, globalZoomCenterX - mOwnerViewBounds.left,
+ return mCallback.onDragZoom(deltaZoomLevel,
+ globalZoomCenterX - mOwnerViewBounds.left,
globalZoomCenterY - mOwnerViewBounds.top,
(float) startAngle / ZoomRing.RADIAN_INT_MULTIPLIER,
(float) curAngle / ZoomRing.RADIAN_INT_MULTIPLIER);
@@ -719,6 +734,45 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback,
ensureZoomRingIsCentered();
}
+ /**
+ * Shows a "tutorial" (some text) to the user teaching her the new zoom
+ * invocation method.
+ *
+ * It checks the global system setting to ensure this has not been seen
+ * before. Furthermore, if the application does not have privilege to write
+ * to the system settings, it will store this bit locally in a shared
+ * preference.
+ *
+ * @hide This should only be used by our main apps--browser, maps, and
+ * gallery
+ */
+ public static void showZoomTutorialOnce(Context context) {
+ ContentResolver cr = context.getContentResolver();
+ if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TOAST, 0) == 1) {
+ return;
+ }
+
+ SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
+ if (sp.getInt(SETTING_NAME_SHOWN_TOAST, 0) == 1) {
+ return;
+ }
+
+ try {
+ Settings.System.putInt(cr, SETTING_NAME_SHOWN_TOAST, 1);
+ } catch (SecurityException e) {
+ /*
+ * The app does not have permission to clear this global flag, make
+ * sure the user does not see the message when he comes back to this
+ * same app at least.
+ */
+ sp.edit().putInt(SETTING_NAME_SHOWN_TOAST, 1).commit();
+ }
+
+ Toast.makeText(context,
+ com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short,
+ Toast.LENGTH_LONG).show();
+ }
+
private class Panner implements Runnable {
private static final int RUN_DELAY = 15;
private static final float STOP_SLOWDOWN = 0.8f;
diff --git a/core/java/com/android/internal/gadget/IGadgetHost.aidl b/core/java/com/android/internal/gadget/IGadgetHost.aidl
index a5b865496db72..e7b5a1e22e60a 100644
--- a/core/java/com/android/internal/gadget/IGadgetHost.aidl
+++ b/core/java/com/android/internal/gadget/IGadgetHost.aidl
@@ -17,11 +17,12 @@
package com.android.internal.gadget;
import android.content.ComponentName;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
import android.widget.RemoteViews;
/** {@hide} */
oneway interface IGadgetHost {
void updateGadget(int gadgetId, in RemoteViews views);
+ void providerChanged(int gadgetId, in GadgetProviderInfo info);
}
diff --git a/core/java/com/android/internal/gadget/IGadgetService.aidl b/core/java/com/android/internal/gadget/IGadgetService.aidl
index 1b3946fce3a8d..a22f3f399ec43 100644
--- a/core/java/com/android/internal/gadget/IGadgetService.aidl
+++ b/core/java/com/android/internal/gadget/IGadgetService.aidl
@@ -17,7 +17,7 @@
package com.android.internal.gadget;
import android.content.ComponentName;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
import com.android.internal.gadget.IGadgetHost;
import android.widget.RemoteViews;
@@ -41,8 +41,8 @@ interface IGadgetService {
//
void updateGadgetIds(in int[] gadgetIds, in RemoteViews views);
void updateGadgetProvider(in ComponentName provider, in RemoteViews views);
- List getInstalledProviders();
- GadgetInfo getGadgetInfo(int gadgetId);
+ List getInstalledProviders();
+ GadgetProviderInfo getGadgetInfo(int gadgetId);
void bindGadgetId(int gadgetId, in ComponentName provider);
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index b0b00b2d4c520..ac72a20e64839 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -32,8 +32,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_DELETE_SURROUNDING_TEXT = 80;
private static final int DO_BEGIN_BATCH_EDIT = 90;
private static final int DO_END_BATCH_EDIT = 95;
- private static final int DO_HIDE_STATUS_ICON = 100;
- private static final int DO_SHOW_STATUS_ICON = 110;
+ private static final int DO_REPORT_FULLSCREEN_MODE = 100;
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
private static final int DO_CLEAR_META_KEY_STATES = 130;
@@ -133,12 +132,8 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
}
- public void hideStatusIcon() {
- dispatchMessage(obtainMessage(DO_HIDE_STATUS_ICON));
- }
-
- public void showStatusIcon(String packageName, int resId) {
- dispatchMessage(obtainMessageIO(DO_SHOW_STATUS_ICON, resId, packageName));
+ public void reportFullscreenMode(boolean enabled) {
+ dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
}
public void performPrivateCommand(String action, Bundle data) {
@@ -323,22 +318,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
ic.endBatchEdit();
return;
}
- case DO_HIDE_STATUS_ICON: {
- InputConnection ic = mInputConnection.get();
- if (ic == null || !isActive()) {
- Log.w(TAG, "hideStatusIcon on inactive InputConnection");
- return;
- }
- ic.hideStatusIcon();
- return;
- }
- case DO_SHOW_STATUS_ICON: {
+ case DO_REPORT_FULLSCREEN_MODE: {
InputConnection ic = mInputConnection.get();
if (ic == null || !isActive()) {
Log.w(TAG, "showStatusIcon on inactive InputConnection");
return;
}
- ic.showStatusIcon((String)msg.obj, msg.arg1);
+ ic.reportFullscreenMode(msg.arg1 != 1);
return;
}
case DO_PERFORM_PRIVATE_COMMAND: {
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 7cc8ada6044ec..02b604438a358 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -56,13 +56,11 @@ import com.android.internal.view.IInputContextCallback;
void endBatchEdit();
+ void reportFullscreenMode(boolean enabled);
+
void sendKeyEvent(in KeyEvent event);
void clearMetaKeyStates(int states);
void performPrivateCommand(String action, in Bundle data);
-
- void showStatusIcon(String packageName, int resId);
-
- void hideStatusIcon();
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 2f5cd14ea7ac9..1b1c7f78a7aff 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -47,7 +47,7 @@ interface IInputMethodManager {
void showInputMethodPickerFromClient(in IInputMethodClient client);
void setInputMethod(in IBinder token, String id);
void hideMySoftInput(in IBinder token, int flags);
- void updateStatusIcon(int iconId, String iconPackage);
+ void updateStatusIcon(in IBinder token, String packageName, int iconId);
boolean setInputMethodEnabled(String id, boolean enabled);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index af4ad25fc6f26..32d9f3dd22876 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -322,18 +322,9 @@ public class InputConnectionWrapper implements InputConnection {
}
}
- public boolean hideStatusIcon() {
+ public boolean reportFullscreenMode(boolean enabled) {
try {
- mIInputContext.showStatusIcon(null, 0);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
-
- public boolean showStatusIcon(String packageName, int resId) {
- try {
- mIInputContext.showStatusIcon(packageName, resId);
+ mIInputContext.reportFullscreenMode(enabled);
return true;
} catch (RemoteException e) {
return false;
diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java
index 20ea6a6d28793..1647c207ff006 100644
--- a/core/java/com/android/internal/widget/NumberPicker.java
+++ b/core/java/com/android/internal/widget/NumberPicker.java
@@ -28,12 +28,8 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.widget.EditText;
-import android.widget.LinearLayout;
import android.widget.TextView;
-import android.widget.ViewSwitcher;
+import android.widget.LinearLayout;
import com.android.internal.R;
@@ -71,25 +67,18 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
private final Runnable mRunnable = new Runnable() {
public void run() {
if (mIncrement) {
- changeCurrent(mCurrent + 1, mSlideUpInAnimation, mSlideUpOutAnimation);
+ changeCurrent(mCurrent + 1);
mHandler.postDelayed(this, mSpeed);
} else if (mDecrement) {
- changeCurrent(mCurrent - 1, mSlideDownInAnimation, mSlideDownOutAnimation);
+ changeCurrent(mCurrent - 1);
mHandler.postDelayed(this, mSpeed);
}
}
};
-
- private final LayoutInflater mInflater;
+
private final TextView mText;
- private final InputFilter mInputFilter;
private final InputFilter mNumberInputFilter;
-
- private final Animation mSlideUpOutAnimation;
- private final Animation mSlideUpInAnimation;
- private final Animation mSlideDownOutAnimation;
- private final Animation mSlideDownInAnimation;
-
+
private String[] mDisplayedValues;
private int mStart;
private int mEnd;
@@ -110,14 +99,14 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
this(context, attrs, 0);
}
- public NumberPicker(Context context, AttributeSet attrs,
- int defStyle) {
+ @SuppressWarnings({"UnusedDeclaration"})
+ public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
setOrientation(VERTICAL);
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mInflater.inflate(R.layout.number_picker, this, true);
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.number_picker, this, true);
mHandler = new Handler();
- mInputFilter = new NumberPickerInputFilter();
+ InputFilter inputFilter = new NumberPickerInputFilter();
mNumberInputFilter = new NumberRangeKeyListener();
mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
mIncrementButton.setOnClickListener(this);
@@ -130,30 +119,9 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
mText = (TextView) findViewById(R.id.timepicker_input);
mText.setOnFocusChangeListener(this);
- mText.setFilters(new InputFilter[] { mInputFilter });
+ mText.setFilters(new InputFilter[] {inputFilter});
mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
-
- mSlideUpOutAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, -100);
- mSlideUpOutAnimation.setDuration(200);
- mSlideUpInAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, 100,
- Animation.RELATIVE_TO_SELF, 0);
- mSlideUpInAnimation.setDuration(200);
- mSlideDownOutAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 100);
- mSlideDownOutAnimation.setDuration(200);
- mSlideDownInAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, -100,
- Animation.RELATIVE_TO_SELF, 0);
- mSlideDownInAnimation.setDuration(200);
-
+
if (!isEnabled()) {
setEnabled(false);
}
@@ -228,9 +196,9 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
// now perform the increment/decrement
if (R.id.increment == v.getId()) {
- changeCurrent(mCurrent + 1, mSlideUpInAnimation, mSlideUpOutAnimation);
+ changeCurrent(mCurrent + 1);
} else if (R.id.decrement == v.getId()) {
- changeCurrent(mCurrent - 1, mSlideDownInAnimation, mSlideDownOutAnimation);
+ changeCurrent(mCurrent - 1);
}
}
@@ -240,7 +208,7 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
: String.valueOf(value);
}
- private void changeCurrent(int current, Animation in, Animation out) {
+ private void changeCurrent(int current) {
// Wrap around the values if we go past the start or end
if (current > mEnd) {
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 307c6fdd89c93..288433af6a0d0 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -267,7 +267,7 @@ static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
(AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
if (lpRecorder) {
- //LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
+ LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
lpRecorder->stop();
delete lpRecorder;
}
@@ -448,6 +448,39 @@ static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobjec
}
+// ----------------------------------------------------------------------------
+// returns the minimum required size for the successful creation of an AudioRecord instance.
+// returns 0 if the parameter combination is not supported.
+// return -1 if there was an error querying the buffer size.
+static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
+ jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+
+ size_t inputBuffSize = 0;
+ LOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", sampleRateInHertz, nbChannels, audioFormat);
+
+ status_t result = AudioSystem::getInputBufferSize(
+ sampleRateInHertz,
+ (audioFormat == javaAudioRecordFields.PCM16 ?
+ AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT),
+ nbChannels, &inputBuffSize);
+ switch(result) {
+ case(NO_ERROR):
+ if(inputBuffSize == 0) {
+ LOGV("Recording parameters are not supported: %dHz, %d channel(s), (java) format %d",
+ sampleRateInHertz, nbChannels, audioFormat);
+ return 0;
+ } else {
+ // the minimum buffer size is twice the hardware input buffer size
+ return 2*inputBuffSize;
+ }
+ break;
+ case(PERMISSION_DENIED):
+ default:
+ return -1;
+ }
+}
+
+
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -470,6 +503,8 @@ static JNINativeMethod gMethods[] = {
"(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
{"native_get_pos_update_period",
"()I", (void *)android_media_AudioRecord_get_pos_update_period},
+ {"native_get_min_buff_size",
+ "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
};
// field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6bd365519567d..692610ea42cca 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -53,13 +53,8 @@ static int
android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
{
LOGV("setVolume(%d)", int(volume));
- if (int(type) == AudioTrack::VOICE_CALL) {
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, float(volume) / 100.0));
- } else if (int(type) == AudioTrack::BLUETOOTH_SCO) {
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, float(1.0)));
- } else {
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
- }
+
+ return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
}
static int
@@ -68,12 +63,7 @@ android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
float v;
int v_int = -1;
if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
- // voice call volume is converted to log scale in the hardware
- if (int(type) == AudioTrack::VOICE_CALL) {
- v_int = lrint(v * 100.0);
- } else {
- v_int = AudioSystem::logToLinear(v);
- }
+ v_int = AudioSystem::logToLinear(v);
}
return v_int;
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index bbecc1b6a0cf7..6ca821d2fca5e 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -72,6 +72,7 @@ class AudioTrackJniStorage {
sp mMemHeap;
sp mMemBase;
audiotrack_callback_cookie mCallbackData;
+ int mStreamType;
AudioTrackJniStorage() {
}
@@ -168,11 +169,11 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
int afSampleRate;
int afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
LOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
- if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
@@ -183,21 +184,21 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
}
// check the stream type
- AudioTrack::stream_type atStreamType;
+ AudioSystem::stream_type atStreamType;
if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
- atStreamType = AudioTrack::VOICE_CALL;
+ atStreamType = AudioSystem::VOICE_CALL;
} else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) {
- atStreamType = AudioTrack::SYSTEM;
+ atStreamType = AudioSystem::SYSTEM;
} else if (streamType == javaAudioTrackFields.STREAM_RING) {
- atStreamType = AudioTrack::RING;
+ atStreamType = AudioSystem::RING;
} else if (streamType == javaAudioTrackFields.STREAM_MUSIC) {
- atStreamType = AudioTrack::MUSIC;
+ atStreamType = AudioSystem::MUSIC;
} else if (streamType == javaAudioTrackFields.STREAM_ALARM) {
- atStreamType = AudioTrack::ALARM;
+ atStreamType = AudioSystem::ALARM;
} else if (streamType == javaAudioTrackFields.STREAM_NOTIFICATION) {
- atStreamType = AudioTrack::NOTIFICATION;
+ atStreamType = AudioSystem::NOTIFICATION;
} else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
- atStreamType = AudioTrack::BLUETOOTH_SCO;
+ atStreamType = AudioSystem::BLUETOOTH_SCO;
} else {
LOGE("Error creating AudioTrack: unknown stream type.");
return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
@@ -238,6 +239,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
// we use a weak reference so the AudioTrack object can be garbage collected.
lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+ lpJniStorage->mStreamType = atStreamType;
+
// create the native AudioTrack object
AudioTrack* lpTrack = new AudioTrack();
if (lpTrack == NULL) {
@@ -656,8 +659,14 @@ static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz) {
- int afSamplingRate;
- if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+ int afSamplingRate;
+ AudioTrackJniStorage* lpJniStorage = (AudioTrackJniStorage *)env->GetIntField(
+ thiz, javaAudioTrackFields.jniData);
+ if (lpJniStorage == NULL) {
+ return DEFAULT_OUTPUT_SAMPLE_RATE;
+ }
+
+ if (AudioSystem::getOutputSamplingRate(&afSamplingRate, lpJniStorage->mStreamType) != NO_ERROR) {
return DEFAULT_OUTPUT_SAMPLE_RATE;
} else {
return afSamplingRate;
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 75a0fbee23ebc..e5ae2ea19bea6 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -751,6 +751,10 @@ void onCreateBondingResult(DBusMessage *msg, void *user) {
// Other device is not responding at all
LOGV("... error = %s (%s)\n", err.name, err.message);
result = BOND_RESULT_REMOTE_DEVICE_DOWN;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
+ // already bonded
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_SUCCESS;
} else {
LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
result = BOND_RESULT_ERROR;
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index d0cac183ab678..5e5103a2fabea 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
-#include "utils/logger.h"
+#include "cutils/logger.h"
#define END_DELIMITER '\n'
#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
diff --git a/core/res/res/drawable/presence_away.png b/core/res/res/drawable/presence_away.png
index a539ec7787190..f8120df43bfe5 100644
Binary files a/core/res/res/drawable/presence_away.png and b/core/res/res/drawable/presence_away.png differ
diff --git a/core/res/res/drawable/presence_busy.png b/core/res/res/drawable/presence_busy.png
index 1e3f547b8cd31..9d7620b1d0c8d 100644
Binary files a/core/res/res/drawable/presence_busy.png and b/core/res/res/drawable/presence_busy.png differ
diff --git a/core/res/res/drawable/presence_invisible.png b/core/res/res/drawable/presence_invisible.png
index fb86cf1283421..21399a4f3618f 100644
Binary files a/core/res/res/drawable/presence_invisible.png and b/core/res/res/drawable/presence_invisible.png differ
diff --git a/core/res/res/drawable/presence_offline.png b/core/res/res/drawable/presence_offline.png
index da54fe7fccf40..3941b82052517 100644
Binary files a/core/res/res/drawable/presence_offline.png and b/core/res/res/drawable/presence_offline.png differ
diff --git a/core/res/res/drawable/presence_online.png b/core/res/res/drawable/presence_online.png
index 879a762955d18..22d5683e2f597 100644
Binary files a/core/res/res/drawable/presence_online.png and b/core/res/res/drawable/presence_online.png differ
diff --git a/core/res/res/drawable/zoom_ring_trail.xml b/core/res/res/drawable/zoom_ring_trail.xml
new file mode 100644
index 0000000000000..08931ac5aafc1
--- /dev/null
+++ b/core/res/res/drawable/zoom_ring_trail.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index a398bd006bccd..0760cc0b7123d 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -24,6 +24,7 @@
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 879f3398f1bfd..949c8a3082c73 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -17,11 +17,9 @@
*/
-->
-
-
-
+
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index 422733a002c59..bbdb31cb44e6e 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -22,23 +22,21 @@
-
-
-
+ android:background="@drawable/timepicker_up_btn" />
+
+
+
-
+ android:background="@drawable/timepicker_down_btn" />
+
diff --git a/core/res/res/layout/number_picker_edit.xml b/core/res/res/layout/number_picker_edit.xml
index 46f4845ad3e76..f3af6e9b211ea 100644
--- a/core/res/res/layout/number_picker_edit.xml
+++ b/core/res/res/layout/number_picker_edit.xml
@@ -23,6 +23,7 @@
android:gravity="center_horizontal"
android:singleLine="true"
style="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/primary_text_light"
android:textSize="30sp"
android:background="@drawable/timepicker_input"
/>
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index bdfe4900e6637..c601e0e830779 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -21,6 +21,7 @@
@@ -55,5 +56,6 @@
android:paddingLeft="20dip"
android:paddingRight="20dip"
style="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/primary_text_light_nodisable"
/>
diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index 6dc1bf62d1506..d5a6b5eb9bc17 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -17,11 +17,9 @@
*/
-->
-
-
-
+
diff --git a/core/res/res/layout/time_picker_text.xml b/core/res/res/layout/time_picker_text.xml
deleted file mode 100644
index bad980b64324d..0000000000000
--- a/core/res/res/layout/time_picker_text.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
diff --git a/core/res/res/values-cs-rCZ/strings.xml b/core/res/res/values-cs-rCZ/strings.xml
deleted file mode 100644
index e1eb3f475b6c3..0000000000000
--- a/core/res/res/values-cs-rCZ/strings.xml
+++ /dev/null
@@ -1,1112 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "<bez názvu>"
- "…"
- "(žádné telefonní číslo)"
- "(neznámý)"
- "Hlasová schránka"
- "Msisdn1"
- "Chyba sítě nebo neplatný kód MMI."
- "Služba povolena"
- "Služba povolena pro:"
- "Služba zakázána"
- "Registrace úspěšná"
- "Odstranění úspěšné"
- "Nesprávné heslo."
- "MMI dokončeno"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Výchozí nastavení omezení ID - omezení. Další hovor: omezení"
- "Výchozí nastavení omezení ID - omezení. Další hovor: bez omezení"
- "Výchozí nastavení omezení ID - bez omezení. Další hovor: omezení"
- "Výchozí nastavení omezení ID - bez omezení. Další hovor: bez omezení"
- "Služba není poskytována."
- "Omezení ID v trvalém režimu."
- "Hlasový záznam"
- "Data"
- "FAX"
- "SMS"
- "Asynchronní"
- "Synchronizace"
- "Pakety"
- "PAD"
- "{0}: Nepřesměrováno"
- "{0}: {1}"
- "{0}: {1} po {2} sekundách"
- "{0}: Nepřesměrováno ({1})"
- "{0}: Nepřesměrováno ({1} po {2} sekundách)"
- "OK"
- "Neznámá chyba"
- "Neznámý hostitel"
- "Nepodporované schéma ověření. Ověření se nezdařilo."
- "Ověřování se nezdařilo"
- "Ověření serverem proxy se nezdařilo"
- "Připojení k serveru se nezdařilo"
- "Čtení nebo zápis na server se nezdařil"
- "Časový limit připojení k serveru vypršel"
- "Příliš mnoho přesměrování serverů"
- "Nepodporovaný protokol"
- "Navázání spojení typu SSL handshake se nezdařilo"
- "Nepodařilo se analyzovat URL"
- "File error"
- "File not found"
-
-
- "Synchronizace"
- "Synchronizace"
-
-
-
-
-
-
- "Možnosti napájení"
- "Tichý režim"
- "Zapnout rádio"
- "Vypnout rádio"
-
-
- "Vypnuto"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Příjem zpráv SMS"
- "Umožňuje aplikacím přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."
- "Příjem zpráv MMS"
- "Umožňuje aplikacím přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."
-
-
-
-
-
-
-
-
-
-
-
-
- "Příjem zpráv WAP"
- "Umožňuje aplikacím přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."
- "Získat informace o úkolech"
- "Umožňuje aplikacím načítat informace o aktuálně a naposledy spuštěných úkolech. Umožňuje škodlivým aplikacím zjišťovat soukromé informace o jiných aplikacích."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Výpis stavu systému"
- "Umožňuje aplikacím načítat vnitřní stav systému. Škodlivé aplikace mohou načítat široký rozsah soukromých a důvěrných informací, jež by obvykle neměly nikdy vyžadovat."
- "Přidat systémovou službu"
- "Umožňuje aplikacím vydávat vlastní systémové služby nižší úrovně. Škodlivé aplikace mohou napadnout systém a vykrást nebo poškodit jeho data."
- "Nastavení sledování činností"
- "Umožňuje aplikacím sledovat a řídit spouštění činností systému. Škodlivé aplikace mohou zcela zničit systém. Toto oprávnění je nutné pouze pro vývoj, nikdy pro normální používání zařízení."
- "Sada vysílání odebrána"
- "Umožňuje aplikacím vysílat oznámení o odebrání sady aplikací. Škodlivé aplikace toho mohou využít k likvidaci jiné spuštěné aplikace."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Instalace aktualizace systému"
- "Umožňuje aplikacím přijímat oznámení o aktualizacích systému čekajících na dokončení a spouštět jejich instalaci. Škodlivé aplikace toho mohou využít k poškození systému neautorizovanými aktualizacemi nebo obecně k zásahům do aktualizačního procesu."
-
-
-
-
- "Okno vnitřního systému"
- "Umožňuje vytváření oken určených k použití uživatelským rozhraním vnitřního systému . Není určeno k použití normálními aplikacemi."
- "Okno systémových výstrah"
- "Umožňuje aplikacím zobrazovat okna systémových výstrah. Škodlivé aplikace mohou ovládnout celou obrazovku zařízení."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Signálové trvalé procesy"
- "Umožňuje aplikacím vyžadovat, aby se přiváděný signál odesílal do všech trvalých procesů."
-
-
-
-
- "Odstranit sady"
- "Umožňuje aplikacím odstranit sady systému Android. Škodlivé aplikace toho mohou využít k odstranění důležitých aplikací."
-
-
-
-
-
-
-
-
-
-
-
-
- "Instalovat sady"
- "Umožňuje aplikacím instalovat nové nebo aktualizované sady systému Android. Škodlivé aplikace toho mohou využít k přidání nových aplikací s libovolně silnými oprávněními."
-
-
-
-
-
-
-
-
-
-
-
-
- "Povolit nebo zakázat součásti aplikací"
- "Umožňuje změnu aplikace bez ohledu na to, zda je součást další aplikace povolená nebo zakázaná. Škodlivá aplikace toho může využít k zakázání důležitých funkcí zařízení. Je třeba nakládat s oprávněními opatrně, protože se mohou součásti aplikace dostat do stavu nepoužitelnosti, nekonzistence nebo nestability."
- "Nastavení upřednostňovaných aplikací"
- "Umožňuje aplikacím upravovat oblíbené aplikace. Škodlivé aplikace tak mohou bez upozornění měnit spouštěné aplikace a klamně využívat stávající aplikace ke shromažďování vašich soukromých dat."
- "Nastavení systému pro zápis"
- "Umožňuje aplikacím upravovat data nastavení systému. Škodlivé aplikace mohou narušit systémovou konfiguraci."
-
-
-
-
-
-
-
-
- "Spustit při spouštění"
- "Umožňuje aplikacím spouštět se po dokončení spuštění systému. Tím se může prodlužovat doba spouštění zařízení a aplikace může svým stálým spouštěním zpomalovat celé zařízení."
- "Vysílat lepivý obsah (sticky)"
- "Umožňuje aplikacím odesílat tzv. lepivé (sticky) vysílání, které zůstává i po ukončení vysílání. Škodlivé aplikace mohou zpomalit zařízení nebo narušit jeho stabilitu vynucením využívání příliš velké části paměti."
- "Čtení dat o kontaktech"
- "Umožňuje aplikacím číst všechna data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k odesílání vašich dat jiným osobám."
- "Zápis dat o kontaktech"
- "Umožňuje aplikacím upravovat data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k vymazání nebo úpravě dat o kontaktech."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Používat službu GPS"
- "Technologii GPS v zařízení lze používat, pokud je k dispozici. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší polohy a mohou spotřebovávat zbytečně energii baterie."
- "Používat službu Cell ID"
- "Identifikátory pro technologii využívající polohu vysílačů mobilních sítí (je-li k dispozici) se používají k určení přibližné polohy zařízení. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší přibližné polohy."
- "Používat službu SurfaceFlinger"
- "Umožňuje aplikacím používat funkce nižší úrovně SurfaceFlinger."
- "Čtení vyrovnávací paměti rámce"
- "Umožňuje aplikacím používat čtení obsahu vyrovnávací paměti rámce."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Volat telefonní čísla"
- "Umožňuje aplikacím volat telefonní čísla bez vašeho zásahu. Škodlivé aplikace mohou přinést na váš telefonní účet neočekávané hovory."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - "Výchozí"
- - "Zaměstnání"
- - "Primární"
- - "Vlastní…"
-
-
- - "Poštovní"
- - "Výchozí"
- - "Zaměstnání"
- - "Vlastní…"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Telefon odemknete stisknutím tlačítka nabídky a poté 0."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Výrobní test skončil chybou"
- "Akce FACTORY_TEST je podporována pouze pro sady instalované v adresáři /system/app."
- "Nebyla nalezena žádná sada, která zajišťuje akci FACTORY_TEST."
- "Restartovat"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Další"
- "Menu+"
-
-
-
-
-
-
- "PŘEJÍT"
- "Dnes"
- "Včera"
- "Zítra"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "den"
- "dnů"
- "hodinu"
- "hodin"
- "minutu"
- "minut"
- "sekund"
- "sekund"
- "týden"
- "týdnů"
-
-
-
-
- "Neděle"
- "Pondělí"
- "Úterý"
- "Středa"
- "Čtvrtek"
- "Pátek"
- "Sobota"
- "Každý den v týdnu (Po–Pá)"
- "Denně"
- "Týdně (%s)"
- "Měsíčně"
- "Ročně"
-
-
-
-
-
-
- "dop."
- "odp."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 37632f8e44918..e0c0a64ee7f52 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3015957a1039c..d9c417434a30f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -818,6 +818,5 @@
-
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4cb3ee1c004c9..d9cf3d5122acc 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1,765 +1,5 @@
- "B"
- "KB"
- "MB"
- "GB"
- "TB"
- "PB"
- "<untitled>"
- "…"
- "(No phone number)"
- "(Unknown)"
- "Voicemail"
- "MSISDN1"
- "Connection problem or invalid MMI code."
- "Service was enabled."
- "Service was enabled for:"
- "Service has been disabled."
- "Registration was successful."
- "Erasure was successful."
- "Incorrect password."
- "MMI complete."
- "The old PIN you typed is not correct."
- "The PUK you typed is not correct."
- "The PINs you entered do not match."
- "Type a PIN that is 4 to 8 numbers."
-
-
- "Type PUK2 to unblock SIM card."
- "Incoming Caller ID"
- "Outgoing Caller ID"
- "Call forwarding"
- "Call waiting"
- "Call barring"
- "Password change"
- "PIN change"
- "Caller ID defaults to restricted. Next call: Restricted"
- "Caller ID defaults to restricted. Next call: Not restricted"
- "Caller ID defaults to not restricted. Next call: Restricted"
- "Caller ID defaults to not restricted. Next call: Not restricted"
- "Service not provisioned."
- "The caller ID setting cannot be changed."
- "Voice"
- "Data"
- "FAX"
- "SMS"
- "Async"
- "Sync"
- "Packet"
- "PAD"
- "{0}: Not forwarded"
- "{0}: {1}"
- "{0}: {1} after {2} seconds"
- "{0}: Not forwarded"
- "{0}: Not forwarded"
- "OK"
- "The Web page contains an error."
- "The URL could not be found."
- "The site authentication scheme is not supported."
- "Authentication was unsuccessful."
- "Authentication via the proxy server was unsuccessful."
- "The connection to the server was unsuccessful."
- "The server failed to communicate. Try again later."
- "The connection to the server timed out."
- "The page contains too many server redirects."
- "The protocol is not supported."
- "A secure connection could not be established."
- "The page could not be opened because the URL is invalid."
- "The file could not be accessed."
- "The requested file was not found."
- "Too many requests are being processed. Try again later."
- "Sync"
- "Sync"
- "Too many %s deletes."
- "Phone storage is full! Delete some files to free space."
- "Me"
- "Phone options"
- "Silent mode"
- "Turn on wireless"
- "Turn off wireless"
- "Screen lock"
- "Power off"
- "Shutting down…"
- "Your phone will shut down."
- "No recent applications."
- "Phone options"
- "Screen lock"
- "Power off"
- "Silent mode"
- "Sound is OFF"
- "Sound is ON"
- "Safe mode"
- "Cost you money"
- "Allow applications to do things that can cost you money."
- "Your messages"
- "Read and write your SMS, e-mail, and other messages."
- "Your personal information"
- "Direct access to your contacts and calendar stored on the phone."
- "Your location"
- "Monitor your physical location"
- "Network communication"
- "Allow applications to access various network features."
- "Your Google accounts"
- "Access the available Google accounts."
- "Hardware controls"
- "Direct access to hardware on the handset."
- "Phone calls"
- "Monitor, record, and process phone calls."
- "System tools"
- "Lower-level access and control of the system."
- "Development tools"
- "Features only needed for application developers."
- "disable or modify status bar"
- "Allows application to disable the status bar or add and remove system icons."
- "expand/collapse status bar"
- "Allows application to expand or collapse the status bar."
- "intercept outgoing calls"
- "Allows application to process outgoing calls and change the number to be dialed. Malicious applications may monitor, redirect, or prevent outgoing calls."
- "receive SMS"
- "Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you."
- "receive MMS"
- "Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you."
- "send SMS messages"
- "Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation."
- "read SMS or MMS"
- "Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages."
- "edit SMS or MMS"
- "Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages."
- "receive WAP"
- "Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you."
- "retrieve running applications"
- "Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications."
- "reorder running applications"
- "Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control."
- "enable application debugging"
- "Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications."
- "change your UI settings"
- "Allows an application to change the current configuration, such as the locale or overall font size."
- "restart other applications"
- "Allows an application to forcibly restart other applications."
- "keep from being stopped"
-
-
- "force application to close"
- "Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for normal applications."
- "retrieve system internal state"
- "Allows application to retrieve internal state of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never normally need."
- "publish low-level services"
- "Allows application to publish its own low-level system services. Malicious applications may hijack the system, and steal or corrupt any data on it."
- "monitor and control all application launching"
- "Allows an application to monitor and control how the system launches activities. Malicious applications may completely compromise the system. This permission is only needed for development, never for normal phone usage."
- "send package removed broadcast"
- "Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other running application."
-
-
-
-
-
-
-
-
- "limit number of running processes"
- "Allows an application to control the maximum number of processes that will run. Never needed for normal applications."
- "make all background applications close"
- "Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for normal applications."
- "automatically install system updates"
- "Allows an application to receive notifications about pending system updates and trigger their installation. Malicious applications may use this to corrupt the system with unauthorized updates, or generally interfere with the update process."
- "modify battery statistics"
- "Allows the modification of collected battery statistics. Not for use by normal applications."
- "display unauthorized windows"
- "Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by normal applications."
- "display system-level alerts"
- "Allows an application to show system alert windows. Malicious applications can take over the entire screen of the phone."
- "modify global animation speed"
- "Allows an application to change the global animation speed (faster or slower animations) at any time."
- "manage application tokens"
- "Allows applications to create and manage their own tokens, bypassing their normal Z-ordering. Should never be needed for normal applications."
- "press keys and control buttons"
- "Allows an application to deliver its own input events (key presses, etc.) to other applications. Malicious applications can use this to take over the phone."
- "record what you type and actions you take"
- "Allows applications to watch the keys you press even when interacting with another application (such as entering a password). Should never be needed for normal applications."
- "change screen orientation"
- "Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications."
- "send Linux signals to applications"
- "Allows application to request that the supplied signal be sent to all persistent processes."
- "make application always run"
-
-
- "delete applications"
- "Allows an application to delete Android packages. Malicious applications can use this to delete important applications."
- "delete other applications data"
- "Allows an application to clear user data."
- "delete other applications cache"
- "Allows an application to delete cache files."
- "measure application storage space"
- "Allows an application to retrieve its code, data, and cache sizes"
- "directly install applications"
- "Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions."
- "delete all application cache data"
- "Allows an application to free phone storage by deleting files in application cache directory. Access is very restricted usually to system process."
- "read system log files"
-
-
-
-
-
-
- "enable or disable application components"
- "Allows an application to change whether a component of another application is enabled or not. Malicious applications can use this to disable important phone capabilities. Care must be used with permission, as it is possible to get application components into an unusable, inconsistant, or unstable state."
- "set preferred applications"
- "Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you."
- "modify global system settings"
- "Allows an application to modify the systems settings data. Malicious applications can corrupt your systems configuration."
-
-
-
-
-
-
-
-
- "automatically start at boot"
- "Allows an application to have itself started as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running."
- "send sticky broadcast"
- "Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory."
- "read contact data"
- "Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people."
- "write contact data"
- "Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data."
- "write owner data"
- "Allows an application to modify the phone owner data stored on your phone. Malicious applications can use this to erase or modify owner data."
- "read owner data"
- "Allows an application read the phone owner data stored on your phone. Malicious applications can use this to read phone owner data."
- "read calendar data"
- "Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people."
- "write calendar data"
- "Allows an application to modify the calendar events stored on your phone. Malicious applications can use this to erase or modify your calendar data."
- "mock location sources for testing"
- "Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real location sources such as GPS or Network providers."
-
-
-
-
- "fine (GPS) location"
- "Access fine location sources such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are, and may consume additional battery power."
- "coarse (network-based) location"
- "Access coarse location sources such as the cellular network database to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are."
- "access SurfaceFlinger"
- "Allows application to use SurfaceFlinger low-level features."
- "read frame buffer"
- "Allows application to use read the content of the frame buffer."
- "change your audio settings"
- "Allows application to modify global audio settings such as volume and routing."
- "record audio"
- "Allows application to access the audio record path."
- "take pictures"
- "Allows application to take pictures with the camera. This allows the application at any time to collect images the camera is seeing."
- "permanently disable phone"
- "Allows the application to disable the entire phone permanently. This is very dangerous."
-
-
-
-
- "mount and unmount filesystems"
- "Allows the application to mount and unmount filesystems for removable storage."
- "control vibrator"
- "Allows the application to control the vibrator."
- "control flashlight"
- "Allows the application to control the flashlight."
- "test hardware"
- "Allows the application to control various peripherals for the purpose of hardware testing."
- "directly call phone numbers"
- "Allows the application to call phone numbers without your intervention. Malicious applications may cause unexpected calls on your phone bill. Note that this does not allow the application to call emergency numbers."
-
-
-
-
-
-
-
-
-
-
-
-
- "modify phone state"
- "Allows the application to control the phone features of the device. An application with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."
- "read phone state"
- "Allows the application to access the phone features of the device. An application with this permission can determine the phone number of this phone, whether a call is active, the number that call is connected to and the like."
- "prevent phone from sleeping"
- "Allows an application to prevent the phone from going to sleep."
- "power phone on or off"
- "Allows the application to turn the phone on or off."
- "run in factory test mode"
- "Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode."
- "set wallpaper"
- "Allows the application to set the system wallpaper."
- "set wallpaper size hints"
- "Allows the application to set the system wallpaper size hints."
- "reset system to factory defaults"
- "Allows an application to completely reset the system to its factory settings, erasing all data, configuration, and installed applications."
- "set time zone"
- "Allows an application to change the phones time zone."
- "discover known accounts"
- "Allows an application to get the list of accounts known by the phone."
- "view network state"
- "Allows an application to view the state of all networks."
- "full Internet access"
- "Allows an application to create network sockets."
-
-
-
-
- "change network connectivity"
- "Allows an application to change the state network connectivity."
- "view Wi-Fi state"
- "Allows an application to view the information about the state of Wi-Fi."
- "change Wi-Fi state"
- "Allows an application to connect to and disconnect from Wi-Fi access points, and to make changes to configured Wi-Fi networks."
- "bluetooth administration"
- "Allows an application to configure the local Bluetooth phone, and to discover and pair with remote devices."
- "create Bluetooth connections"
- "Allows an application to view configuration of the local Bluetooth phone, and to make and accept connections with paired devices."
- "disable keylock"
- "Allows an application to disable the keylock and any associated password security. A legitimate example of this is the phone disabling the keylock when receiving an incoming phone call, then re-enabling the keylock when the call is finished."
- "read sync settings"
- "Allows an application to read the sync settings, such as whether sync is enabled for Contacts."
- "write sync settings"
- "Allows an application to modify the sync settings, such as whether sync is enabled for Contacts."
- "read sync statistics"
- "Allows an application to reafocusd the sync stats; e.g., the history of syncs that have occurred."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Enter PIN code:"
- "Incorrect PIN code!"
- "To unlock, press Menu then 0."
- "Emergency number"
- "(No service)"
- "Screen locked"
- "Press Menu to unlock or place emergency call."
- "Press Menu to unlock."
- "Draw pattern to unlock:"
- "Emergency call"
- "Correct!"
- "Sorry, try again:"
- "Charging (%d%%)"
- "Connect your charger."
- "No SIM card."
- "No SIM card in phone."
- "Please insert a SIM card."
-
-
- "SIM card is PUK-locked."
- "Please contact Customer Care."
- "SIM card is locked."
- "Unlocking SIM card…"
- "You have incorrectly drawn your unlock pattern %d times. "\n\n"Please try again in %d seconds."
- "You have incorrectly drawn your unlock pattern %d times. After %d more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in %d seconds."
- "Try again in %d seconds."
- "Forgot pattern?"
- "Too many pattern attempts!"
- "To unlock,"\n"sign in with your Google account:"
- "Username (email)"
- "Password"
- "Sign in"
- "Invalid username or password."
-
-
-
-
-
-
-
-
-
-
- "Clear notifications"
- "No notifications"
- "Ongoing"
- "Notifications"
- "%d"
- "Charging…"
- "Please connect charger"
- "The battery is getting low:"
- "less than %d%% remaining."
- "Factory test failed"
- "The FACTORY_TEST action is only supported for packages installed in /system/app."
- "No package was found that provides the FACTORY_TEST action."
- "Reboot"
- "Confirm"
- "Do you want the browser to remember this password?"
- "Not now"
- "Remember"
- "Never"
- "You do not have permission to open this page."
- "Text copied to clipboard."
- "More"
- "Menu+"
-
-
-
-
-
-
- "Search"
- "Today"
- "Yesterday"
- "Tomorrow"
- "1 month ago"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "on %s"
- "at %s"
- "in %s"
- "day"
- "days"
- "hour"
- "hours"
- "min"
- "mins"
- "sec"
- "secs"
- "week"
- "weeks"
- "year"
- "years"
- "Sunday"
- "Monday"
- "Tuesday"
- "Wednesday"
- "Thursday"
- "Friday"
- "Saturday"
- "Every weekday (Mon–Fri)"
- "Daily"
- "Weekly on %s"
- "Monthly"
- "Yearly"
- "Cannot play video"
- "Sorry, this video cannot be played."
- "OK"
- "AM"
- "PM"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "noon"
- "Noon"
- "midnight"
- "Midnight"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- "Sunday"
- "Monday"
- "Tuesday"
- "Wednesday"
- "Thursday"
- "Friday"
- "Saturday"
- "Sun"
- "Mon"
- "Tue"
- "Wed"
- "Thu"
- "Fri"
- "Sat"
- "Su"
- "Mo"
- "Tu"
- "We"
- "Th"
- "Fr"
- "Sa"
- "Su"
- "M"
- "Tu"
- "W"
- "Th"
- "F"
- "Sa"
- "S"
- "M"
- "T"
- "W"
- "T"
- "F"
- "S"
- "January"
- "February"
- "March"
- "April"
- "May"
- "June"
- "July"
- "August"
- "September"
- "October"
- "November"
- "December"
- "Jan"
- "Feb"
- "Mar"
- "Apr"
- "May"
- "Jun"
- "Jul"
- "Aug"
- "Sep"
- "Oct"
- "Nov"
- "Dec"
- "J"
- "F"
- "M"
- "A"
- "M"
- "J"
- "J"
- "A"
- "S"
- "O"
- "N"
- "D"
-
-
-
-
- "Select all"
- "Cut"
- "Cut all"
- "Copy"
- "Copy all"
- "Paste"
- "Copy URL"
-
-
-
-
- "Low on space"
- "Your phone is running low on internal storage space."
- "OK"
- "Cancel"
- "OK"
- "Cancel"
- "ON"
- "OFF"
- "Complete action using"
- "Use by default for this action."
- "Clear default in Home Settings > Applications > Manage applications."
- "Select an action"
- "No applications can perform this action."
- "Sorry!"
- "The application %1$s (process %2$s) has stopped unexpectedly. Please try again."
- "The process %1$s has stopped unexpectedly. Please try again."
- "Application unresponsive"
- "Activity %1$s (in application %2$s) is not responding."
- "Activity %1$s (in process %2$s) is not responding."
- "Application %1$s (in process %2$s) is not responding."
- "Process %1$s is not responding."
- "Force close"
- "Wait"
- "Debug"
- "Select an action for text"
- "Ringer volume"
- "Music/video volume"
- "In-call volume"
- "Alarm volume"
- "Volume"
- "Default ringtone"
- "Default ringtone (%1$s)"
- "Silent"
- "Select a ringtone"
- "Unknown ringtone"
-
-
-
-
- "Select character to insert"
-
-
- "Sending SMS messages"
- "A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."
- "OK"
- "Cancel"
- "Set"
- "Default"
- "No permissions required"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ B
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f8881b6f4dbc9..dc17445527399 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 47f1bf49dad53..95e30528a1093 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 710c49340ce43..2cf7b43b2cf34 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0eba7f55144d5..24e3cb6e7cad1 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -558,12 +558,12 @@
"%2$s、%1$s"
- "yyyy\'年\'MMMMd\'日\'"
- "yyyy\'年\'MMMMd\'日\'"
- "yyyy\'年\'MMMd\'日\'"
- "yyyy\'年\'MMMd\'日\'"
- "h:mm a"
- "H:mm"
+ "yyyy'\'\'年\'\''MMMMd'\'\'日\'\''"
+ "yyyy'\'\'年\'\''MMMMd'\'\'日\'\''"
+ "yyyy'\'\'年\'\''MMMd'\'\'日\'\''"
+ "yyyy'\'\'年\'\''MMMd'\'\'日\'\''"
+ "h':'mm' 'a"
+ "H':'mm"
"正午"
"正午"
"午前0時"
@@ -573,7 +573,8 @@
"%Y年%B%-d日"
- "%Y年 %B"
+
+
"%H:%M:%S"
"%Y年%B%-d日%H:%M:%S"
"%2$s%3$s日~%7$s%8$s日"
@@ -816,6 +817,5 @@
-
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4272684f8bb67..140f32f16527c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 9f49557735411..466f2b175619d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -262,10 +262,8 @@
"Lar applikasjonen tvinge telefonen til å starte på nytt."
"montere og avmontere filsystemer"
"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."
-
-
-
-
+ "formatere ekstern lagringsplass"
+ "Lar applikasjonen formatere ekstern lagringsplass."
"kontrollere vibratoren"
"Lar applikasjonen kontrollere vibratoren."
"kontrollere lommelykten"
@@ -280,10 +278,8 @@
"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."
"få tilgang til egenskaper for innsjekking"
"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."
-
-
-
-
+ "velg gadgeter"
+ "Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner."
"endre telefontilstand"
"Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren."
"lese telefontilstand"
@@ -312,10 +308,8 @@
"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."
"endre nettverkskonnektivitet"
"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."
-
-
-
-
+ "endre innstilling for bakgrunnsdata"
+ "Lar applikasjonen endre innstillingen for bakgrunnsdata."
"se tilstand for trådløse nettverk"
"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."
"endre tilstand for trådløse nettverk"
@@ -336,14 +330,10 @@
"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."
"endre abonnement på nyhetskilder"
"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."
-
-
-
-
-
-
-
-
+ "lese brukerdefinert ordliste"
+ "Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."
+ "skrive til brukerdefinert ordliste"
+ "Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."
- "Hjemme"
- "Mobil"
@@ -440,12 +430,9 @@
"The FACTORY_TEST action is only supported for packages installed in /system/app."
"No package was found that provides the FACTORY_TEST action."
"Reboot"
-
-
-
-
-
-
+ "Siden \\\'%s\\\' sier:"
+ "JavaScript"
+ "Naviger bort fra denne siden?"\n\n"%s"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."
"Bekreft"
"Ønsker du at nettleseren skal huske dette passordet?"
"Ikke nå"
@@ -569,17 +556,15 @@
"%1$s, %2$s %3$s"
"%2$s %3$s"
"%1$s, %3$s"
-
-
-
-
+ "%1$s, %2$s"
+ "%1$s, %2$s"
"%1$s, %2$s"
- "MMMM' 'd'., 'yyyy"
- "d'. 'MMMM' 'yyyy"
- "MMM' 'd', 'yyyy"
- "d'. 'MMM' 'yyyy"
- "h':'mm' 'a"
- "H':'mm"
+ "MMMM'\\\'\'\\\'\' \\\'\'\\\'\''d'\\\'\'\\\'\'., \\\'\'\\\'\''yyyy"
+ "d'\\\'\'\\\'\'. \\\'\'\\\'\''MMMM'\\\'\'\\\'\' \\\'\'\\\'\''yyyy"
+ "MMM'\\\'\'\\\'\' \\\'\'\\\'\''d'\\\'\'\\\'\', \\\'\'\\\'\''yyyy"
+ "d'\\\'\'\\\'\'. \\\'\'\\\'\''MMM'\\\'\'\\\'\' \\\'\'\\\'\''yyyy"
+ "h'\\\'\'\\\'\':\\\'\'\\\'\''mm'\\\'\'\\\'\' \\\'\'\\\'\''a"
+ "H'\\\'\'\\\'\':\\\'\'\\\'\''mm"
"middag"
"Middag"
"midnatt"
@@ -596,18 +581,14 @@
"%2$s %3$s – %7$s %8$s"
"%1$s %3$s. %2$s – %6$s %8$s. %7$s"
"%3$s. %2$s – %8$s. %7$s %9$s"
-
-
+ "%1$s %2$s %3$s – %6$s %7$s %8$s, %9$s"
"%3$s. %2$s %5$s – %8$s. %7$s %10$s"
"%1$s %3$s. %2$s %5$s – %6$s %8$s. %7$s %10$s"
-
-
-
-
+ "%3$s. %2$s %4$s %5$s – %8$s. %7$s %9$s %10$s"
+ "%1$s %3$s. %2$s %4$s %5$s – %6$s %8$s. %7$s %9$s %10$s"
"%3$s.%2$s. – %8$s.%7$s."
"%1$s %3$s.%2$s. – %6$s %8$s.%7$s."
-
-
+ "%3$s.%2$s.%4$s – %8$s.%7$s.%9$s"
"%1$s %3$s.%2$s.%4$s – %6$s %8$s.%7$s.%9$s"
"%3$s.%2$s. %5$s – %8$s.%7$s. %10$s"
"%1$s %3$s.%2$s. %5$s – %6$s %8$s.%7$s. %10$s"
@@ -711,8 +692,7 @@
"Lim inn"
"Kopier URL"
"Inndatametode"
-
-
+ "Legg \\\"%s\\\" til ordlisten"
"Rediger tekst"
"Lite plass"
"Det begynner å bli lite lagringsplass på telefonen."
@@ -720,8 +700,7 @@
"Avbryt"
"OK"
"Avbryt"
-
-
+ "Merk"
"På"
"Av"
"Complete action using"
@@ -745,8 +724,7 @@
"Medievolum"
"Spiller over Bluetooth"
"Samtalevolum"
-
-
+ "Bluetooth-samtalevolum"
"Alarmvolum"
"Varslingsvolum"
"Volum"
@@ -766,7 +744,7 @@
"Sett inn tegn"
"Ukjent applikasjon"
"Sending SMS messages"
- "A large number of SMS messages are being sent. Select \\\"OK\\\" to continue, or \\\"Cancel\\\" to stop sending."
+ "A large number of SMS messages are being sent. Select \\\\\\\"OK\\\\\\\" to continue, or \\\\\\\"Cancel\\\\\\\" to stop sending."
"OK"
"Avbryt"
"Lagre"
@@ -776,67 +754,39 @@
"Vis alle"
"Laster inn…"
"USB koblet til"
- "Du har koblet telefonen til en datamaskin via USB. Velg \\\"Monter\\\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."
+ "Du har koblet telefonen til en datamaskin via USB. Velg \\\\\\\"Monter\\\\\\\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."
"Monter"
"Ikke monter"
"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."
"USB tilkoblet"
"Velg om du ønsker å kopiere filer til/fra en datamaskin."
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ "Slå av USB-lagring"
+ "Velg for å slå av USB-lagring."
+ "Slå av USB-lagring"
+ "Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."
+ "Slå av"
+ "Avbryt"
+ "Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."
+ "Formatere minnekort"
+ "Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."
+ "Format"
"Velg inndatametode"
"ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"
-
- "TAG_FONT""kandidater""u>CLOSE_FONT"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ "TAG_FONT""kandidater""CLOSE_FONT"
+ "Forbereder minnekort"
+ "Sjekker for feil"
+ "Tomt minnekort"
+ "Minnekortet er tomt eller bruker et ustøttet filsystem."
+ "Skadet minnekort"
+ "Minnekortet er skadet. Det kan være du må formatere kortet."
+ "Minnekortet ble tatt ut uventet"
+ "Avmonter minnekortet før det tas ut, for å unngå datatap."
+ "Trygt å ta ut minnekort"
+ "Minnekortet kan nå trygt tas ut."
+ "Minnekortet ble tatt ut"
+ "Minnekortet ble tatt ut. Sett inn et nytt minnekort for å øke lagringsplassen."
+ "Fant ingen tilsvarende aktiviteter"
+ "oppdater statistikk over komponentbruk"
+ "Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7ce4c66c95ff8..a2810a1f15270 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 03c4f8b25a7b8..12f16163e210b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d25ab8da57839..76a358dddc21f 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 447fccdaba670..13d4e9c696979 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e97c142be81db..419e8c2eb4b8a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -817,6 +817,5 @@
-
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3f21303b6b397..593d1ff2a8a22 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1056,6 +1056,10 @@
enabled for events such as clicking and touching. -->
+
+
+
+
+
+
+
+
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 103158511bdb2..9175f31abca54 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1001,6 +1001,9 @@
+
+
+
- Congratulations on downloading the Android software update. This update includes a number of great new features for you to enjoy. One major improvement we've made is to how you zoom. Now, when you want to zoom, just double tap on the screen. This will bring up a zoom widget. Drag the widget's handle clockwise to zoom in, and counter-clockwise to zoom out.
-
+ Double tap to zoom
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 82cb795deccb7..3db45f0daa082 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -47,7 +47,9 @@ import java.io.IOException;
* @attr ref android.R.styleable#GradientDrawable_visible
* @attr ref android.R.styleable#GradientDrawable_shape
* @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+ * @attr ref android.R.styleable#GradientDrawable_innerRadius
* @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+ * @attr ref android.R.styleable#GradientDrawable_thickness
* @attr ref android.R.styleable#GradientDrawable_useLevel
* @attr ref android.R.styleable#GradientDrawableSize_width
* @attr ref android.R.styleable#GradientDrawableSize_height
@@ -121,6 +123,8 @@ public class GradientDrawable extends Drawable {
private Paint mLayerPaint; // internal, used if we use saveLayer()
private boolean mRectIsDirty; // internal state
private boolean mMutated;
+ private Path mRingPath;
+ private boolean mPathIsDirty;
/**
* Controls how the gradient is oriented relative to the drawable's bounds
@@ -213,6 +217,7 @@ public class GradientDrawable extends Drawable {
}
public void setShape(int shape) {
+ mRingPath = null;
mGradientState.setShape(shape);
}
@@ -248,14 +253,12 @@ public class GradientDrawable extends Drawable {
// remember the alpha values, in case we temporarily overwrite them
// when we modulate them with mAlpha
final int prevFillAlpha = mFillPaint.getAlpha();
- final int prevStrokeAlpha = mStrokePaint != null ?
- mStrokePaint.getAlpha() : 0;
+ final int prevStrokeAlpha = mStrokePaint != null ? mStrokePaint.getAlpha() : 0;
// compute the modulate alpha values
final int currFillAlpha = modulateAlpha(prevFillAlpha);
final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha);
- final boolean haveStroke = currStrokeAlpha > 0 &&
- mStrokePaint.getStrokeWidth() > 0;
+ final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint.getStrokeWidth() > 0;
final boolean haveFill = currFillAlpha > 0;
final GradientState st = mGradientState;
/* we need a layer iff we're drawing both a fill and stroke, and the
@@ -264,7 +267,7 @@ public class GradientDrawable extends Drawable {
of the fill (if any) without worrying about blending artifacts.
*/
final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
- currStrokeAlpha < 255;
+ currStrokeAlpha < 255;
/* Drawing with a layer is slower than direct drawing, but it
allows us to apply paint effects like alpha and colorfilter to
@@ -336,10 +339,10 @@ public class GradientDrawable extends Drawable {
break;
}
case RING:
- Path ring = buildRing(st);
- canvas.drawPath(ring, mFillPaint);
+ Path path = buildRing(st);
+ canvas.drawPath(path, mFillPaint);
if (haveStroke) {
- canvas.drawPath(ring, mStrokePaint);
+ canvas.drawPath(path, mStrokePaint);
}
break;
}
@@ -355,6 +358,9 @@ public class GradientDrawable extends Drawable {
}
private Path buildRing(GradientState st) {
+ if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
+ mPathIsDirty = false;
+
float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
RectF bounds = new RectF(mRect);
@@ -362,9 +368,11 @@ public class GradientDrawable extends Drawable {
float x = bounds.width() / 2.0f;
float y = bounds.height() / 2.0f;
- float thickness = bounds.width() / st.mThickness;
+ float thickness = st.mThickness != -1 ?
+ st.mThickness : bounds.width() / st.mThicknessRatio;
// inner radius
- float radius = bounds.width() / st.mInnerRadius;
+ float radius = st.mInnerRadius != -1 ?
+ st.mInnerRadius : bounds.width() / st.mInnerRadiusRatio;
RectF innerBounds = new RectF(bounds);
innerBounds.inset(x - radius, y - radius);
@@ -372,27 +380,33 @@ public class GradientDrawable extends Drawable {
bounds = new RectF(innerBounds);
bounds.inset(-thickness, -thickness);
- Path path = new Path();
+ if (mRingPath == null) {
+ mRingPath = new Path();
+ } else {
+ mRingPath.reset();
+ }
+
+ final Path ringPath = mRingPath;
// arcTo treats the sweep angle mod 360, so check for that, since we
// think 360 means draw the entire oval
if (sweep < 360 && sweep > -360) {
- path.setFillType(Path.FillType.EVEN_ODD);
+ ringPath.setFillType(Path.FillType.EVEN_ODD);
// inner top
- path.moveTo(x + radius, y);
+ ringPath.moveTo(x + radius, y);
// outer top
- path.lineTo(x + radius + thickness, y);
+ ringPath.lineTo(x + radius + thickness, y);
// outer arc
- path.arcTo(bounds, 0.0f, sweep, false);
+ ringPath.arcTo(bounds, 0.0f, sweep, false);
// inner arc
- path.arcTo(innerBounds, sweep, -sweep, false);
- path.close();
+ ringPath.arcTo(innerBounds, sweep, -sweep, false);
+ ringPath.close();
} else {
// add the entire ovals
- path.addOval(bounds, Path.Direction.CW);
- path.addOval(innerBounds, Path.Direction.CCW);
+ ringPath.addOval(bounds, Path.Direction.CW);
+ ringPath.addOval(innerBounds, Path.Direction.CCW);
}
- return path;
+ return ringPath;
}
public void setColor(int argb) {
@@ -430,6 +444,8 @@ public class GradientDrawable extends Drawable {
@Override
protected void onBoundsChange(Rect r) {
super.onBoundsChange(r);
+ mRingPath = null;
+ mPathIsDirty = true;
mRectIsDirty = true;
}
@@ -437,6 +453,7 @@ public class GradientDrawable extends Drawable {
protected boolean onLevelChange(int level) {
super.onLevelChange(level);
mRectIsDirty = true;
+ mPathIsDirty = true;
invalidateSelf();
return true;
}
@@ -462,8 +479,9 @@ public class GradientDrawable extends Drawable {
mRect.set(bounds.left + inset, bounds.top + inset,
bounds.right - inset, bounds.bottom - inset);
-
- if (st.mColors != null) {
+
+ final int[] colors = st.mColors;
+ if (colors != null) {
RectF r = mRect;
float x0, x1, y0, y1;
@@ -505,8 +523,7 @@ public class GradientDrawable extends Drawable {
}
mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
- st.mColors, st.mPositions,
- Shader.TileMode.CLAMP));
+ colors, st.mPositions, Shader.TileMode.CLAMP));
} else if (st.mGradient == RADIAL_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -514,30 +531,38 @@ public class GradientDrawable extends Drawable {
final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;
mFillPaint.setShader(new RadialGradient(x0, y0,
- level * st.mGradientRadius, st.mColors, null,
+ level * st.mGradientRadius, colors, null,
Shader.TileMode.CLAMP));
} else if (st.mGradient == SWEEP_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
- float[] positions = null;
- int[] colors = st.mColors;
+ int[] tempColors = colors;
+ float[] tempPositions = null;
if (st.mUseLevel) {
- final int length = st.mColors.length;
- colors = new int[length + 1];
- System.arraycopy(st.mColors, 0, colors, 0, length);
- colors[length] = st.mColors[length - 1];
+ tempColors = st.mTempColors;
+ final int length = colors.length;
+ if (tempColors == null || tempColors.length != length + 1) {
+ tempColors = st.mTempColors = new int[length + 1];
+ }
+ System.arraycopy(colors, 0, tempColors, 0, length);
+ tempColors[length] = colors[length - 1];
+ tempPositions = st.mTempPositions;
final float fraction = 1.0f / (float) (length - 1);
- positions = new float[length + 1];
+ if (tempPositions == null || tempPositions.length != length + 1) {
+ tempPositions = st.mTempPositions = new float[length + 1];
+ }
+
final float level = (float) getLevel() / 10000.0f;
for (int i = 0; i < length; i++) {
- positions[i] = i * fraction * level;
+ tempPositions[i] = i * fraction * level;
}
- positions[length] = 1.0f;
+ tempPositions[length] = 1.0f;
+
}
- mFillPaint.setShader(new SweepGradient(x0, y0, colors, positions));
+ mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));
}
}
}
@@ -561,10 +586,18 @@ public class GradientDrawable extends Drawable {
com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE);
if (shapeType == RING) {
- st.mInnerRadius = a.getFloat(
- com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
- st.mThickness = a.getFloat(
- com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+ st.mInnerRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawable_innerRadius, -1);
+ if (st.mInnerRadius == -1) {
+ st.mInnerRadiusRatio = a.getFloat(
+ com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
+ }
+ st.mThickness = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawable_thickness, -1);
+ if (st.mThickness == -1) {
+ st.mThicknessRatio = a.getFloat(
+ com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+ }
st.mUseLevelForShape = a.getBoolean(
com.android.internal.R.styleable.GradientDrawable_useLevel, true);
}
@@ -808,6 +841,8 @@ public class GradientDrawable extends Drawable {
public int mGradient = LINEAR_GRADIENT;
public Orientation mOrientation;
public int[] mColors;
+ public int[] mTempColors; // no need to copy
+ public float[] mTempPositions; // no need to copy
public float[] mPositions;
public boolean mHasSolidColor;
public int mSolidColor;
@@ -820,8 +855,10 @@ public class GradientDrawable extends Drawable {
public Rect mPadding;
public int mWidth = -1;
public int mHeight = -1;
- public float mInnerRadius;
- public float mThickness;
+ public float mInnerRadiusRatio;
+ public float mThicknessRatio;
+ public int mInnerRadius;
+ public int mThickness;
private float mCenterX = 0.5f;
private float mCenterY = 0.5f;
private float mGradientRadius = 0.5f;
@@ -844,17 +881,25 @@ public class GradientDrawable extends Drawable {
mGradient = state.mGradient;
mOrientation = state.mOrientation;
mColors = state.mColors.clone();
- mPositions = state.mPositions.clone();
+ if (state.mPositions != null) {
+ mPositions = state.mPositions.clone();
+ }
mHasSolidColor = state.mHasSolidColor;
mStrokeWidth = state.mStrokeWidth;
mStrokeColor = state.mStrokeColor;
mStrokeDashWidth = state.mStrokeDashWidth;
mStrokeDashGap = state.mStrokeDashGap;
mRadius = state.mRadius;
- mRadiusArray = state.mRadiusArray.clone();
- mPadding = new Rect(state.mPadding);
+ if (state.mRadiusArray != null) {
+ mRadiusArray = state.mRadiusArray.clone();
+ }
+ if (state.mPadding != null) {
+ mPadding = new Rect(state.mPadding);
+ }
mWidth = state.mWidth;
mHeight = state.mHeight;
+ mInnerRadiusRatio = state.mInnerRadiusRatio;
+ mThicknessRatio = state.mThicknessRatio;
mInnerRadius = state.mInnerRadius;
mThickness = state.mThickness;
mCenterX = state.mCenterX;
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index e4b821a905c0c..cb16cb711b427 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -88,6 +88,13 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
canvas.restoreToCount(saveCount);
}
+ /**
+ * Returns the drawable rotated by this RotateDrawable.
+ */
+ public Drawable getDrawable() {
+ return mState.mDrawable;
+ }
+
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations()
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index b3322c9634bb9..7125ab1e689e8 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -63,6 +63,13 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
}
}
+ /**
+ * Returns the drawable scaled by this ScaleDrawable.
+ */
+ public Drawable getDrawable() {
+ return mScaleState.mDrawable;
+ }
+
private static float getPercent(TypedArray a, int name) {
String s = a.getString(name);
if (s != null) {
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 6bd54ba6611ea..7437f65266601 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -29,8 +29,27 @@ class AudioSystem
{
public:
+ enum stream_type {
+ DEFAULT =-1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ NUM_STREAM_TYPES
+ };
+
+ enum audio_output_type {
+ AUDIO_OUTPUT_DEFAULT =-1,
+ AUDIO_OUTPUT_HARDWARE = 0,
+ AUDIO_OUTPUT_A2DP = 1,
+ NUM_AUDIO_OUTPUT_TYPES
+ };
+
enum audio_format {
- DEFAULT = 0,
+ FORMAT_DEFAULT = 0,
PCM_16_BIT,
PCM_8_BIT,
INVALID_FORMAT
@@ -96,9 +115,11 @@ public:
static float linearToLog(int volume);
static int logToLinear(float volume);
- static status_t getOutputSamplingRate(int* samplingRate);
- static status_t getOutputFrameCount(int* frameCount);
- static status_t getOutputLatency(uint32_t* latency);
+ static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT);
+ static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT);
+ static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
+
+ static bool routedToA2dpOutput(int streamType);
static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
size_t* buffSize);
@@ -117,9 +138,10 @@ private:
virtual void binderDied(const wp& who);
// IAudioFlingerClient
- virtual void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency);
+ virtual void a2dpEnabledChanged(bool enabled);
};
+ static int getOutput(int streamType);
static sp gAudioFlingerClient;
@@ -128,9 +150,10 @@ private:
static Mutex gLock;
static sp gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
- static int gOutSamplingRate;
- static int gOutFrameCount;
- static uint32_t gOutLatency;
+ static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+ static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+ static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+ static bool gA2dpEnabled;
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 5b2bab98bb27c..659f5f8aa335e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -42,19 +42,6 @@ class audio_track_cblk_t;
class AudioTrack
{
public:
-
- enum stream_type {
- DEFAULT =-1,
- VOICE_CALL = 0,
- SYSTEM = 1,
- RING = 2,
- MUSIC = 3,
- ALARM = 4,
- NOTIFICATION = 5,
- BLUETOOTH_SCO = 6,
- NUM_STREAM_TYPES
- };
-
enum channel_index {
MONO = 0,
LEFT = 0,
@@ -128,7 +115,7 @@ public:
* Parameters:
*
* streamType: Select the type of audio stream this track is attached to
- * (e.g. AudioTrack::MUSIC).
+ * (e.g. AudioSystem::MUSIC).
* sampleRate: Track sampling rate in Hz.
* format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
* 16 bits per sample).
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index df601d7ca03fe..6f13fe0b52c25 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -65,11 +65,11 @@ public:
/* query the audio hardware state. This state never changes,
* and therefore can be cached.
*/
- virtual uint32_t sampleRate() const = 0;
- virtual int channelCount() const = 0;
- virtual int format() const = 0;
- virtual size_t frameCount() const = 0;
- virtual uint32_t latency() const = 0;
+ virtual uint32_t sampleRate(int output) const = 0;
+ virtual int channelCount(int output) const = 0;
+ virtual int format(int output) const = 0;
+ virtual size_t frameCount(int output) const = 0;
+ virtual uint32_t latency(int output) const = 0;
/* set/get the audio hardware state. This will probably be used by
* the preference panel, mostly.
@@ -117,6 +117,9 @@ public:
// force AudioFlinger thread out of standby
virtual void wakeUp() = 0;
+
+ // is A2DP output enabled
+ virtual bool isA2dpEnabled() const = 0;
};
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index 10c3e0fd9f384..c3deb0b4e8f28 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -32,7 +32,7 @@ public:
DECLARE_META_INTERFACE(AudioFlingerClient);
// Notifies a change of audio output from/to hardware to/from A2DP.
- virtual void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) = 0;
+ virtual void a2dpEnabledChanged(bool enabled) = 0;
};
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 49e45d138ffdc..0dff84e87ce15 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -38,6 +38,7 @@ public:
virtual status_t setVideoEncoder(int ve) = 0;
virtual status_t setAudioEncoder(int ae) = 0;
virtual status_t setOutputFile(const char* path) = 0;
+ virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
virtual status_t prepare() = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index 5fee0d6a7eadc..f795d040e950d 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -43,6 +43,7 @@ public:
status_t setCamera(const sp& camera);
status_t setPreviewSurface(const sp& surface);
status_t setOutputFile(const char *path);
+ status_t setOutputFile(int fd, int64_t offset, int64_t length);
status_t prepare();
status_t start();
status_t stop();
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index a901d32ee3c96..436e8f1d0cf26 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -102,6 +102,7 @@ public:
status_t setVideoEncoder(int ve);
status_t setAudioEncoder(int ae);
status_t setOutputFile(const char* path);
+ status_t setOutputFile(int fd, int64_t offset, int64_t length);
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
status_t prepare();
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 1c8043dbf048d..87b320f431b88 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -25,6 +25,8 @@
#include
#include
+#include
+
namespace android {
typedef int32_t SurfaceID;
@@ -49,16 +51,8 @@ public:
class BufferHeap {
public:
enum {
- /* flip source image horizontally */
- FLIP_H = 0x01,
- /* flip source image vertically */
- FLIP_V = 0x02,
/* rotate source image 90 degrees */
- ROT_90 = 0x04,
- /* rotate source image 180 degrees */
- ROT_180 = 0x03,
- /* rotate source image 270 degrees */
- ROT_270 = 0x07,
+ ROT_90 = HAL_TRANSFORM_ROT_90,
};
BufferHeap();
diff --git a/include/utils/logger.h b/include/utils/logger.h
deleted file mode 100644
index 3a08019a8866c..0000000000000
--- a/include/utils/logger.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* utils/logger.h
-**
-** Copyright 2007, The Android Open Source Project
-**
-** This file is dual licensed. It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _UTILS_LOGGER_H
-#define _UTILS_LOGGER_H
-
-#include
-
-struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t __pad; /* no matter what, we get 2 bytes of padding */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- char msg[0]; /* the entry's payload */
-};
-
-#define LOGGER_LOG_MAIN "log/main"
-#define LOGGER_LOG_RADIO "log/radio"
-#define LOGGER_LOG_EVENTS "log/events"
-
-#define LOGGER_ENTRY_MAX_LEN (4*1024)
-#define LOGGER_ENTRY_MAX_PAYLOAD \
- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
-
-#ifdef HAVE_IOCTL
-
-#include
-
-#define __LOGGERIO 0xAE
-
-#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
-
-#endif // HAVE_IOCTL
-
-#endif /* _UTILS_LOGGER_H */
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 017a298c69274..d347f14caeeea 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -47,6 +47,15 @@
#include "A2dpAudioInterface.h"
#endif
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
namespace android {
//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
@@ -59,6 +68,13 @@ static const float MAX_GAIN = 4096.0f;
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
#define AUDIOFLINGER_SECURITY_ENABLED 1
// ----------------------------------------------------------------------------
@@ -98,13 +114,10 @@ static bool settingsAllowed() {
// ----------------------------------------------------------------------------
AudioFlinger::AudioFlinger()
- : BnAudioFlinger(), Thread(false),
- mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
- mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0),
- mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0),
- mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
- mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false)
+ : BnAudioFlinger(),
+ mAudioHardware(0), mA2dpAudioInterface(0),
+ mA2dpEnabled(false), mA2dpEnabledReq(false),
+ mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false)
{
mHardwareStatus = AUDIO_HW_IDLE;
mAudioHardware = AudioHardwareInterface::create();
@@ -113,42 +126,43 @@ AudioFlinger::AudioFlinger()
// open 16-bit output stream for s/w mixer
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
status_t status;
- mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
mHardwareStatus = AUDIO_HW_IDLE;
- if (mHardwareOutput) {
- mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate());
- mRequestedOutput = mHardwareOutput;
- doSetOutput(mHardwareOutput);
-
- // FIXME - this should come from settings
- setMasterVolume(1.0f);
- setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
- setMode(AudioSystem::MODE_NORMAL);
- mMasterMute = false;
+ if (hwOutput) {
+ mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
} else {
- LOGE("Failed to initialize output stream, status: %d", status);
+ LOGE("Failed to initialize hardware output stream, status: %d", status);
}
#ifdef WITH_A2DP
// Create A2DP interface
mA2dpAudioInterface = new A2dpAudioInterface();
- mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
-
- // create a buffer big enough for both hardware and A2DP audio output.
- size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
- size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
- size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
-#else
- size_t frameCount = getOutputFrameCount(mHardwareOutput);
+ AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ if (a2dpOutput) {
+ mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+ if (hwOutput) {
+ uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+ MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+ hwOutput->sampleRate(),
+ AudioSystem::PCM_16_BIT,
+ hwOutput->channelCount(),
+ frameCount);
+ mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
+ }
+ } else {
+ LOGE("Failed to initialize A2DP output stream, status: %d", status);
+ }
#endif
- // FIXME - Current mixer implementation only supports stereo output: Always
- // Allocate a stereo buffer even if HW output is mono.
- mMixBuffer = new int16_t[frameCount * 2];
- memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
-
+
+ // FIXME - this should come from settings
+ setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+ setMode(AudioSystem::MODE_NORMAL);
+
+ setMasterVolume(1.0f);
+ setMasterMute(false);
+
// Start record thread
mAudioRecordThread = new AudioRecordThread(mAudioHardware);
if (mAudioRecordThread != 0) {
@@ -162,7 +176,7 @@ AudioFlinger::AudioFlinger()
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
LOGD("Silence is golden");
- mMasterMute = true;
+ setMasterMute(true);
}
}
@@ -172,64 +186,36 @@ AudioFlinger::~AudioFlinger()
mAudioRecordThread->exit();
mAudioRecordThread.clear();
}
+ mHardwareMixerThread.clear();
delete mAudioHardware;
// deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+ mA2dpMixerThread.clear();
delete mA2dpAudioInterface;
- delete [] mMixBuffer;
- delete mHardwareAudioMixer;
- delete mA2dpAudioMixer;
-}
-
-void AudioFlinger::setOutput(AudioStreamOut* output)
-{
- mRequestedOutput = output;
- mWaitWorkCV.broadcast();
+#endif
}
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
-{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
-
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
- }
- mFormat = output->format();
- mFrameCount = getOutputFrameCount(output);
- mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
- mOutput = output;
- notifyOutputChange_l();
-}
-
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output)
-{
- return output->bufferSize() / output->channelCount() / sizeof(int16_t);
-}
#ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
-{
- return (streamType == AudioTrack::SYSTEM ||
- streamType == AudioTrack::RING ||
- streamType == AudioTrack::ALARM ||
- streamType == AudioTrack::VOICE_CALL ||
- streamType == AudioTrack::BLUETOOTH_SCO ||
- streamType == AudioTrack::NOTIFICATION);
-}
-
void AudioFlinger::setA2dpEnabled(bool enable)
{
- if (enable) {
- LOGD("set output to A2DP\n");
- setOutput(mA2dpOutput);
- } else {
- LOGD("set output to hardware audio\n");
- setOutput(mHardwareOutput);
- }
+ LOGV_IF(enable, "set output to A2DP\n");
+ LOGV_IF(!enable, "set output to hardware audio\n");
+
+ mA2dpEnabledReq = enable;
+ mA2dpMixerThread->wakeUp();
}
#endif // WITH_A2DP
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+ // NOTE that streams listed here must not be routed to A2DP by default:
+ // AudioSystem::routedToA2dpOutput(streamType) == false
+ return (streamType == AudioSystem::RING ||
+ streamType == AudioSystem::ALARM ||
+ streamType == AudioSystem::NOTIFICATION);
+}
+
status_t AudioFlinger::dumpClients(int fd, const Vector& args)
{
const size_t SIZE = 256;
@@ -251,40 +237,6 @@ status_t AudioFlinger::dumpClients(int fd, const Vector& args)
return NO_ERROR;
}
-status_t AudioFlinger::dumpTracks(int fd, const Vector& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append("Tracks:\n");
- result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
- for (size_t i = 0; i < mTracks.size(); ++i) {
- wp