e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
if (v == this) {
@@ -2660,10 +2661,10 @@ class ApplicationContext extends Context {
if (hasListeners) {
for (int i = keysModified.size() - 1; i >= 0; i--) {
final String key = keysModified.get(i);
- // Call in the order they were registered
- final int listenersSize = listeners.size();
- for (int j = 0; j < listenersSize; j++) {
- listeners.get(j).onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
+ for (OnSharedPreferenceChangeListener listener : listeners) {
+ if (listener != null) {
+ listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
+ }
}
}
}
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index d6fcbb1a6aa7e..8d249da960bdb 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -65,6 +65,7 @@ public abstract class LauncherActivity extends ListActivity {
public Drawable icon;
public String packageName;
public String className;
+ public Bundle extras;
ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
label = resolveInfo.loadLabel(pm);
@@ -115,6 +116,9 @@ public abstract class LauncherActivity extends ListActivity {
Intent intent = new Intent(mIntent);
ListItem item = mActivitiesList.get(position);
intent.setClassName(item.packageName, item.className);
+ if (item.extras != null) {
+ intent.putExtras(item.extras);
+ }
return intent;
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index a6a436f4fd097..d2fb6052e9ade 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -278,11 +278,11 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
- * Stop the service, if the most recent time it was started was
+ * Stop the service if the most recent time it was started was
* startId. This is the same as calling {@link
* android.content.Context#stopService} for this particular service but allows you to
* safely avoid stopping if there is a start request from a client that you
- * haven't yet see in {@link #onStart}.
+ * haven't yet seen in {@link #onStart}.
*
* @param startId The most recent start identifier received in {@link
* #onStart}.
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 3b10ed282d1c7..eca04b3113308 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -108,6 +108,23 @@ public class AppWidgetManager {
*/
public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
+ /**
+ * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
+ * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
+ * installed. (This is how the launcher shows the search widget).
+ */
+ public static final String EXTRA_CUSTOM_INFO = "customInfo";
+
+ /**
+ * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
+ * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
+ * installed. It will be added to the extras object on the {@link android.content.Intent}
+ * that is returned from the picker activity.
+ *
+ * {@more}
+ */
+ public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
+
/**
* A sentiel value that the AppWidget manager will never return as a appWidgetId.
*/
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 1ba1c1e86f7b9..abf08cbfc7658 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -31,6 +31,12 @@ import java.io.UnsupportedEncodingException;
* @hide
*/
public class BluetoothDevice {
+
+ public static final int BLUETOOTH_STATE_OFF = 0;
+ public static final int BLUETOOTH_STATE_TURNING_ON = 1;
+ public static final int BLUETOOTH_STATE_ON = 2;
+ public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
+
/** Inquiry scan and page scan are both off.
* Device is neither discoverable nor connectable */
public static final int SCAN_MODE_NONE = 0;
@@ -83,7 +89,7 @@ public class BluetoothDevice {
}
/**
- * Get the current status of Bluetooth hardware.
+ * Is Bluetooth currently turned on.
*
* @return true if Bluetooth enabled, false otherwise.
*/
@@ -94,38 +100,31 @@ public class BluetoothDevice {
return false;
}
+ /**
+ * Get the current state of Bluetooth.
+ *
+ * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
+ */
+ public int getBluetoothState() {
+ try {
+ return mService.getBluetoothState();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR;
+ }
+
/**
* Enable the Bluetooth device.
* Turn on the underlying hardware.
- * This is an asynchronous call, BluetoothIntent.ENABLED_ACTION will be
- * sent if and when the device is successfully enabled.
+ * This is an asynchronous call,
+ * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
+ * and when the device is sucessfully enabled.
* @return false if we cannot enable the Bluetooth device. True does not
* imply the device was enabled, it only implies that so far there were no
* problems.
*/
public boolean enable() {
- return enable(null);
- }
-
- /**
- * Enable the Bluetooth device.
- * Turns on the underlying hardware.
- * This is an asynchronous call. onEnableResult() of your callback will be
- * called when the call is complete, with either RESULT_SUCCESS or
- * RESULT_FAILURE.
- *
- * Your callback will be called from a binder thread, not the main thread.
- *
- * In addition to the callback, BluetoothIntent.ENABLED_ACTION will be
- * broadcast if the device is successfully enabled.
- *
- * @param callback Your callback, null is ok.
- * @return true if your callback was successfully registered, or false if
- * there was an error, implying your callback will never be called.
- */
- public boolean enable(IBluetoothDeviceCallback callback) {
try {
- return mService.enable(callback);
+ return mService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -138,7 +137,7 @@ public class BluetoothDevice {
*/
public boolean disable() {
try {
- return mService.disable();
+ return mService.disable(true);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -551,7 +550,6 @@ public class BluetoothDevice {
}
return pinBytes;
}
-
private static final int ADDRESS_LENGTH = 17;
/** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index 9273d0defaeb0..344601b0b89a8 100644
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ b/core/java/android/bluetooth/BluetoothIntent.java
@@ -41,6 +41,10 @@ public interface BluetoothIntent {
"android.bluetooth.intent.RSSI";
public static final String CLASS =
"android.bluetooth.intent.CLASS";
+ public static final String BLUETOOTH_STATE =
+ "android.bluetooth.intent.BLUETOOTH_STATE";
+ public static final String BLUETOOTH_PREVIOUS_STATE =
+ "android.bluetooth.intent.BLUETOOTH_PREVIOUS_STATE";
public static final String HEADSET_STATE =
"android.bluetooth.intent.HEADSET_STATE";
public static final String HEADSET_PREVIOUS_STATE =
@@ -54,12 +58,12 @@ public interface BluetoothIntent {
public static final String REASON =
"android.bluetooth.intent.REASON";
+ /** Broadcast when the local Bluetooth device state changes, for example
+ * when Bluetooth is enabled. Will contain int extra's BLUETOOTH_STATE and
+ * BLUETOOTH_PREVIOUS_STATE. */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ENABLED_ACTION =
- "android.bluetooth.intent.action.ENABLED";
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String DISABLED_ACTION =
- "android.bluetooth.intent.action.DISABLED";
+ public static final String BLUETOOTH_STATE_CHANGED_ACTION =
+ "android.bluetooth.intent.action.BLUETOOTH_STATE_CHANGED";
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String NAME_CHANGED_ACTION =
diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetoothDevice.aidl
index 4351d2ebc3863..6cd792e26a52a 100644
--- a/core/java/android/bluetooth/IBluetoothDevice.aidl
+++ b/core/java/android/bluetooth/IBluetoothDevice.aidl
@@ -26,8 +26,9 @@ import android.bluetooth.IBluetoothDeviceCallback;
interface IBluetoothDevice
{
boolean isEnabled();
- boolean enable(in IBluetoothDeviceCallback callback); // async
- boolean disable();
+ int getBluetoothState();
+ boolean enable();
+ boolean disable(boolean persistSetting);
String getAddress();
String getName();
diff --git a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
index d25bd560d0347..d05709330b761 100644
--- a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
@@ -22,6 +22,4 @@ package android.bluetooth;
oneway interface IBluetoothDeviceCallback
{
void onGetRemoteServiceChannelResult(in String address, int channel);
-
- void onEnableResult(int result);
}
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
index a43a08be10567..1bf786ffd3adc 100644
--- a/core/java/android/bluetooth/ScoSocket.java
+++ b/core/java/android/bluetooth/ScoSocket.java
@@ -76,7 +76,7 @@ public class ScoSocket {
try {
if (VDBG) log(this + " SCO OBJECT DTOR");
destroyNative();
- releaseWakeLock();
+ releaseWakeLockNow();
} finally {
super.finalize();
}
@@ -98,7 +98,7 @@ public class ScoSocket {
return true;
} else {
mState = STATE_CLOSED;
- releaseWakeLock();
+ releaseWakeLockNow();
return false;
}
}
@@ -148,7 +148,7 @@ public class ScoSocket {
mState = STATE_CLOSED;
}
mHandler.obtainMessage(mConnectedCode, mState, -1, this).sendToTarget();
- releaseWakeLock();
+ releaseWakeLockNow();
}
private synchronized void onAccepted(int result) {
@@ -183,7 +183,19 @@ public class ScoSocket {
private void releaseWakeLock() {
if (mWakeLock.isHeld()) {
- if (VDBG) log("mWakeLock.release() " + this);
+ // Keep apps processor awake for a further 2 seconds.
+ // This is a hack to resolve issue http://b/1616263 - in which
+ // we are left in a 80 mA power state when remotely terminating a
+ // call while connected to BT headset "HTC BH S100 " with A2DP and
+ // HFP profiles.
+ if (VDBG) log("mWakeLock.release() in 2 sec" + this);
+ mWakeLock.acquire(2000);
+ }
+ }
+
+ private void releaseWakeLockNow() {
+ if (mWakeLock.isHeld()) {
+ if (VDBG) log("mWakeLock.release() now" + this);
mWakeLock.release();
}
}
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 08f6191ac71e7..a41627aa3ab4d 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -68,7 +68,7 @@ import android.util.Log;
* these broadcasts, the Intent broadcast mechanism here is completely separate
* from Intents that are used to start Activities with
* {@link Context#startActivity Context.startActivity()}.
- * There is no way for an BroadcastReceiver
+ * There is no way for a BroadcastReceiver
* to see or capture Intents used with startActivity(); likewise, when
* you broadcast an Intent, you will never find or start an Activity.
* These two operations are semantically very different: starting an
@@ -103,7 +103,7 @@ import android.util.Log;
* its process before the asynchronous operation completes.
*
* In particular, you may not show a dialog or bind to a service from
- * within an BroadcastReceiver. For the former, you should instead use the
+ * within a BroadcastReceiver. For the former, you should instead use the
* {@link android.app.NotificationManager} API. For the latter, you can
* use {@link android.content.Context#startService Context.startService()} to
* send a command to the service.
@@ -141,7 +141,7 @@ import android.util.Log;
*
*
Process Lifecycle
*
- * A process that is currently executing an BroadcastReceiver (that is,
+ *
A process that is currently executing a BroadcastReceiver (that is,
* currently running the code in its {@link #onReceive} method) is
* considered to be a foreground process and will be kept running by the
* system except under cases of extreme memory pressure.
@@ -156,7 +156,7 @@ import android.util.Log;
* more important processes.
*
*
This means that for longer-running operations you will often use
- * a {@link android.app.Service} in conjunction with an BroadcastReceiver to keep
+ * an {@link android.app.Service} in conjunction with a BroadcastReceiver to keep
* the containing process active for the entire time of your operation.
*/
public abstract class BroadcastReceiver {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 90ff78a59485c..306c02eca3d82 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1035,7 +1035,7 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
-
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
@@ -1052,7 +1052,7 @@ public class Intent implements Parcelable {
public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
/**
- * Broadcast Action: Sent when the user is present after device wakes up (e.g when the
+ * Broadcast Action: Sent when the user is present after device wakes up (e.g when the
* keyguard is gone).
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -1210,7 +1210,7 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: The charging state, or charge level of the battery has
* changed.
- *
+ *
*
* You can not receive this through components declared
* in manifests, only by exlicitly registering for it with
@@ -1380,7 +1380,7 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_GTALK_SERVICE_DISCONNECTED =
"android.intent.action.GTALK_DISCONNECTED";
-
+
/**
* Broadcast Action: An input method has been changed.
* {@hide pending API Council approval}
@@ -1450,12 +1450,12 @@ public class Intent implements Parcelable {
*
*
The Intent will have the following extra value:
*
- * - {@link android.content.Intent#EXTRA_PHONE_NUMBER} -
+ *
- {@link android.content.Intent#EXTRA_PHONE_NUMBER} -
* the phone number originally intended to be dialed.
*
* Once the broadcast is finished, the resultData is used as the actual
* number to call. If null, no call will be placed.
- * It is perfectly acceptable for multiple receivers to process the
+ *
It is perfectly acceptable for multiple receivers to process the
* outgoing call in turn: for example, a parental control application
* might verify that the user is authorized to place the call at that
* time, then a number-rewriting application might add an area code if
@@ -1463,7 +1463,7 @@ public class Intent implements Parcelable {
*
For consistency, any receiver whose purpose is to prohibit phone
* calls should have a priority of 0, to ensure it will see the final
* phone number to be dialed.
- * Any receiver whose purpose is to rewrite phone numbers to be called
+ * Any receiver whose purpose is to rewrite phone numbers to be called
* should have a positive priority.
* Negative priorities are reserved for the system for this broadcast;
* using them may cause problems.
@@ -1472,7 +1472,7 @@ public class Intent implements Parcelable {
* Emergency calls cannot be intercepted using this mechanism, and
* other calls cannot be modified to call emergency numbers using this
* mechanism.
- *
You must hold the
+ *
You must hold the
* {@link android.Manifest.permission#PROCESS_OUTGOING_CALLS}
* permission to receive this Intent.
*/
@@ -1709,7 +1709,7 @@ public class Intent implements Parcelable {
* implying that this is an update).
*/
public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
-
+
/**
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
* intents to indicate that this is a replacement of the package, so this
@@ -1717,7 +1717,7 @@ public class Intent implements Parcelable {
* different version of the same package.
*/
public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
-
+
/**
* Used as an int extra field in {@link android.app.AlarmManager} intents
* to tell the application being invoked how many pending alarms are being
@@ -1728,15 +1728,6 @@ public class Intent implements Parcelable {
*/
public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
- /**
- * Used as an int extra field in {@link android.content.Intent#ACTION_VOICE_COMMAND}
- * intents to request which audio route the voice command should prefer.
- * The value should be a route from {@link android.media.AudioManager}, for
- * example ROUTE_BLUETOOTH_SCO. Providing this value is optional.
- * {@hide pending API Council approval}
- */
- public static final String EXTRA_AUDIO_ROUTE = "android.intent.extra.AUDIO_ROUTE";
-
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
@@ -1781,7 +1772,7 @@ public class Intent implements Parcelable {
* next task activity) defines an atomic group of activities that the
* user can move to. Tasks can be moved to the foreground and background;
* all of the activities inside of a particular task always remain in
- * the same order. See
+ * the same order. See
* Application Fundamentals:
* Activities and Tasks for more details on tasks.
*
@@ -1812,7 +1803,7 @@ public class Intent implements Parcelable {
* Because the default system does not include graphical task management,
* you should not use this flag unless you provide some way for a user to
* return back to the tasks you have launched.
- *
+ *
*
This flag is ignored if
* {@link #FLAG_ACTIVITY_NEW_TASK} is not set.
*
@@ -1901,7 +1892,7 @@ public class Intent implements Parcelable {
* the user re-launching it from home), this activity and all on top of
* it will be finished so that the user does not return to them, but
* instead returns to whatever activity preceeded it.
- *
+ *
*
This is useful for cases where you have a logical break in your
* application. For example, an e-mail application may have a command
* to view an attachment, which launches an image view activity to
@@ -1919,31 +1910,31 @@ public class Intent implements Parcelable {
* If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaveHint}
* callback from occurring on the current frontmost activity before it is
* paused as the newly-started activity is brought to the front.
- *
+ *
*
Typically, an activity can rely on that callback to indicate that an
* explicit user action has caused their activity to be moved out of the
* foreground. The callback marks an appropriate point in the activity's
* lifecycle for it to dismiss any notifications that it intends to display
* "until the user has seen them," such as a blinking LED.
- *
+ *
*
If an activity is ever started via any non-user-driven events such as
* phone-call receipt or an alarm handler, this flag should be passed to {@link
* Context#startActivity Context.startActivity}, ensuring that the pausing
- * activity does not think the user has acknowledged its notification.
+ * activity does not think the user has acknowledged its notification.
*/
public static final int FLAG_ACTIVITY_NO_USER_ACTION = 0x00040000;
/**
* If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
* this flag will cause the launched activity to be brought to the front of its
* task's history stack if it is already running.
- *
+ *
*
For example, consider a task consisting of four activities: A, B, C, D.
* If D calls startActivity() with an Intent that resolves to the component
* of activity B, then B will be brought to the front of the history stack,
* with this resulting order: A, C, D, B.
- *
+ *
* This flag will be ignored if {@link #FLAG_ACTIVITY_CLEAR_TOP} is also
- * specified.
+ * specified.
*/
public static final int FLAG_ACTIVITY_REORDER_TO_FRONT = 0X00020000;
/**
@@ -1957,11 +1948,11 @@ public class Intent implements Parcelable {
* will be launched. Sticky intent state will be recorded properly even
* if no receivers wind up being called. If {@link #FLAG_RECEIVER_REGISTERED_ONLY}
* is specified in the broadcast intent, this flag is unnecessary.
- *
+ *
*
This flag is only for use by system sevices as a convenience to
* avoid having to implement a more complex mechanism around detection
* of boot completion.
- *
+ *
* @hide
*/
public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000;
@@ -2121,7 +2112,7 @@ public class Intent implements Parcelable {
// old format Intent URI
if (!uri.startsWith("#Intent;", i)) return getIntentOld(uri);
-
+
// new format
Intent intent = new Intent(ACTION_VIEW);
@@ -2130,7 +2121,7 @@ public class Intent implements Parcelable {
intent.mData = Uri.parse(uri.substring(0, i));
}
i += "#Intent;".length();
-
+
// loop over contents of Intent, all name=value;
while (!uri.startsWith("end", i)) {
int eq = uri.indexOf('=', i);
@@ -2161,7 +2152,7 @@ public class Intent implements Parcelable {
else if (uri.startsWith("component=", i)) {
intent.mComponent = ComponentName.unflattenFromString(value);
}
-
+
// extra
else {
String key = Uri.decode(uri.substring(i + 2, eq));
@@ -2181,18 +2172,18 @@ public class Intent implements Parcelable {
else if (uri.startsWith("s.", i)) b.putShort(key, Short.parseShort(value));
else throw new URISyntaxException(uri, "unknown EXTRA type", i);
}
-
+
// move to the next item
i = semi + 1;
}
return intent;
-
+
} catch (IndexOutOfBoundsException e) {
throw new URISyntaxException(uri, "illegal Intent URI format", i);
}
}
-
+
public static Intent getIntentOld(String uri) throws URISyntaxException {
Intent intent;
@@ -2257,7 +2248,7 @@ public class Intent implements Parcelable {
if (uri.regionMatches(i, "extras(", 0, 7)) {
i += 7;
-
+
final int closeParen = uri.indexOf(')', i);
if (closeParen == -1) throw new URISyntaxException(uri,
"EXTRA missing trailing ')'", i);
@@ -2272,7 +2263,7 @@ public class Intent implements Parcelable {
i++;
String key = uri.substring(i, j);
i = j + 1;
-
+
// get type-value
j = uri.indexOf('!', i);
if (j == -1 || j >= closeParen) j = closeParen;
@@ -2282,7 +2273,7 @@ public class Intent implements Parcelable {
// create Bundle if it doesn't already exist
if (intent.mExtras == null) intent.mExtras = new Bundle();
-
+
// add item to bundle
try {
switch (type) {
@@ -2319,7 +2310,7 @@ public class Intent implements Parcelable {
} catch (NumberFormatException e) {
throw new URISyntaxException(uri, "EXTRA value can't be parsed", i);
}
-
+
char ch = uri.charAt(i);
if (ch == ')') break;
if (ch != '!') throw new URISyntaxException(uri, "EXTRA missing '!'", i);
@@ -2522,7 +2513,7 @@ public class Intent implements Parcelable {
public boolean hasFileDescriptors() {
return mExtras != null && mExtras.hasFileDescriptors();
}
-
+
/**
* Retrieve extended data from the intent.
*
@@ -3889,7 +3880,7 @@ public class Intent implements Parcelable {
/**
* Completely replace the extras in the Intent with the extras in the
* given Intent.
- *
+ *
* @param src The exact extras contained in this Intent are copied
* into the target intent, replacing any that were previously there.
*/
@@ -3897,11 +3888,11 @@ public class Intent implements Parcelable {
mExtras = src.mExtras != null ? new Bundle(src.mExtras) : null;
return this;
}
-
+
/**
* Completely replace the extras in the Intent with the given Bundle of
* extras.
- *
+ *
* @param extras The new set of extras in the Intent, or null to erase
* all extras.
*/
@@ -3909,7 +3900,7 @@ public class Intent implements Parcelable {
mExtras = extras != null ? new Bundle(extras) : null;
return this;
}
-
+
/**
* Remove extended data from the intent.
*
@@ -4397,12 +4388,12 @@ public class Intent implements Parcelable {
}
}
}
-
+
uri.append("end");
return uri.toString();
}
-
+
public int describeContents() {
return (mExtras != null) ? mExtras.describeContents() : 0;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7287d9cd58e93..3e9473472dcb3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -340,6 +340,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_FAILED_OLDER_SDK = -12;
+ /**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package failed because it contains a content provider with the
+ * same authority as a provider already installed in the system.
+ */
+ public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
+
/**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
diff --git a/core/java/android/emoji/EmojiFactory.java b/core/java/android/emoji/EmojiFactory.java
index 389bd07d6b735..e0b12ae31d9a6 100644
--- a/core/java/android/emoji/EmojiFactory.java
+++ b/core/java/android/emoji/EmojiFactory.java
@@ -253,6 +253,22 @@ public final class EmojiFactory {
* is returned.
*/
public static native EmojiFactory newAvailableInstance();
+
+ /**
+ * Returns the lowest code point corresponding to an Android
+ * emoji character.
+ */
+ public int getMinimumAndroidPua() {
+ return nativeGetMinimumAndroidPua(mNativeEmojiFactory);
+ }
+
+ /**
+ * Returns the highest code point corresponding to an Android
+ * emoji character.
+ */
+ public int getMaximumAndroidPua() {
+ return nativeGetMaximumAndroidPua(mNativeEmojiFactory);
+ }
// native methods
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 32270c46d039a..6ee92ce6b019a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -22,8 +22,8 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ResultReceiver;
@@ -44,6 +44,7 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
+import android.view.animation.AnimationUtils;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -54,6 +55,8 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -204,6 +207,10 @@ import java.io.PrintWriter;
* You can use these to reset and initialize your input state for the current
* target. For example, you will often want to clear any input state, and
* update a soft keyboard to be appropriate for the new inputType.
+ *
+ * @attr ref android.R.styleable#InputMethodService_imeFullscreenBackground
+ * @attr ref android.R.styleable#InputMethodService_imeExtractEnterAnimation
+ * @attr ref android.R.styleable#InputMethodService_imeExtractExitAnimation
*/
public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
@@ -211,13 +218,19 @@ public class InputMethodService extends AbstractInputMethodService {
InputMethodManager mImm;
+ int mTheme = android.R.style.Theme_InputMethod;
+
LayoutInflater mInflater;
+ TypedArray mThemeAttrs;
View mRootView;
SoftInputWindow mWindow;
boolean mInitialized;
boolean mWindowCreated;
boolean mWindowAdded;
boolean mWindowVisible;
+ boolean mWindowWasVisible;
+ boolean mInShowWindow;
+ ViewGroup mFullscreenArea;
FrameLayout mExtractFrame;
FrameLayout mCandidatesFrame;
FrameLayout mInputFrame;
@@ -243,6 +256,7 @@ public class InputMethodService extends AbstractInputMethodService {
boolean mFullscreenApplied;
boolean mIsFullscreen;
View mExtractView;
+ boolean mExtractViewHidden;
ExtractEditText mExtractEditText;
ViewGroup mExtractAccessories;
Button mExtractAction;
@@ -260,8 +274,8 @@ public class InputMethodService extends AbstractInputMethodService {
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
- if (isFullscreenMode()) {
- // In fullscreen mode, we just say the window isn't covering
+ if (isExtractViewShown()) {
+ // In true fullscreen mode, we just say the window isn't covering
// any content so we don't impact whatever is behind.
View decor = getWindow().getWindow().getDecorView();
info.contentInsets.top = info.visibleInsets.top
@@ -519,12 +533,28 @@ public class InputMethodService extends AbstractInputMethodService {
public int touchableInsets;
}
+ /**
+ * You can call this to customize the theme used by your IME's window.
+ * This theme should typically be one that derives from
+ * {@link android.R.style#Theme_InputMethod}, which is the default theme
+ * you will get. This must be set before {@link #onCreate}, so you
+ * will typically call it in your constructor with the resource ID
+ * of your custom theme.
+ */
+ public void setTheme(int theme) {
+ if (mWindow != null) {
+ throw new IllegalStateException("Must be called before onCreate()");
+ }
+ mTheme = theme;
+ }
+
@Override public void onCreate() {
+ super.setTheme(mTheme);
super.onCreate();
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- mWindow = new SoftInputWindow(this);
+ mWindow = new SoftInputWindow(this, mTheme);
initViews();
mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
}
@@ -551,6 +581,7 @@ public class InputMethodService extends AbstractInputMethodService {
mShowInputRequested = false;
mShowInputForced = false;
+ mThemeAttrs = obtainStyledAttributes(android.R.styleable.InputMethodService);
mRootView = mInflater.inflate(
com.android.internal.R.layout.input_method, null);
mWindow.setContentView(mRootView);
@@ -560,6 +591,8 @@ public class InputMethodService extends AbstractInputMethodService {
mWindow.getWindow().setWindowAnimations(
com.android.internal.R.style.Animation_InputMethodFancy);
}
+ mFullscreenArea = (ViewGroup)mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
+ mExtractViewHidden = false;
mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
mExtractView = null;
mExtractEditText = null;
@@ -731,14 +764,20 @@ public class InputMethodService extends AbstractInputMethodService {
if (ic != null) ic.reportFullscreenMode(isFullscreen);
mFullscreenApplied = true;
initialize();
- Drawable bg = onCreateBackgroundDrawable();
- if (bg == null) {
- // We need to give the window a real drawable, so that it
- // correctly sets its mode.
- bg = getResources().getDrawable(android.R.color.transparent);
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ mFullscreenArea.getLayoutParams();
+ if (isFullscreen) {
+ mFullscreenArea.setBackgroundDrawable(mThemeAttrs.getDrawable(
+ com.android.internal.R.styleable.InputMethodService_imeFullscreenBackground));
+ lp.height = 0;
+ lp.weight = 1;
+ } else {
+ mFullscreenArea.setBackgroundDrawable(null);
+ lp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
+ lp.weight = 0;
}
- mWindow.getWindow().setBackgroundDrawable(bg);
- mExtractFrame.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+ ((ViewGroup)mFullscreenArea.getParent()).updateViewLayout(
+ mFullscreenArea, lp);
if (isFullscreen) {
if (mExtractView == null) {
View v = onCreateExtractTextView();
@@ -748,6 +787,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
startExtractingText(false);
}
+ updateExtractFrameVisibility();
}
if (changed) {
@@ -804,13 +844,67 @@ public class InputMethodService extends AbstractInputMethodService {
return config.orientation == Configuration.ORIENTATION_LANDSCAPE;
}
+ /**
+ * Controls the visibility of the extracted text area. This only applies
+ * when the input method is in fullscreen mode, and thus showing extracted
+ * text. When false, the extracted text will not be shown, allowing some
+ * of the application to be seen behind. This is normally set for you
+ * by {@link #onUpdateExtractingVisibility}. This controls the visibility
+ * of both the extracted text and candidate view; the latter since it is
+ * not useful if there is no text to see.
+ */
+ public void setExtractViewShown(boolean shown) {
+ if (mExtractViewHidden == shown) {
+ mExtractViewHidden = !shown;
+ updateExtractFrameVisibility();
+ }
+ }
+
+ /**
+ * Return whether the fullscreen extract view is shown. This will only
+ * return true if {@link #isFullscreenMode()} returns true, and in that
+ * case its value depends on the last call to
+ * {@link #setExtractViewShown(boolean)}. This effectively lets you
+ * determine if the application window is entirely covered (when this
+ * returns true) or if some part of it may be shown (if this returns
+ * false, though if {@link #isFullscreenMode()} returns true in that case
+ * then it is probably only a sliver of the application).
+ */
+ public boolean isExtractViewShown() {
+ return mIsFullscreen && !mExtractViewHidden;
+ }
+
+ void updateExtractFrameVisibility() {
+ int vis;
+ if (isFullscreenMode()) {
+ vis = mExtractViewHidden ? View.INVISIBLE : View.VISIBLE;
+ mExtractFrame.setVisibility(View.VISIBLE);
+ } else {
+ vis = View.VISIBLE;
+ mExtractFrame.setVisibility(View.GONE);
+ }
+ updateCandidatesVisibility(mCandidatesVisibility == View.VISIBLE);
+ if (mWindowWasVisible && mFullscreenArea.getVisibility() != vis) {
+ int animRes = mThemeAttrs.getResourceId(vis == View.VISIBLE
+ ? com.android.internal.R.styleable.InputMethodService_imeExtractEnterAnimation
+ : com.android.internal.R.styleable.InputMethodService_imeExtractExitAnimation,
+ 0);
+ if (animRes != 0) {
+ mFullscreenArea.startAnimation(AnimationUtils.loadAnimation(
+ this, animRes));
+ }
+ }
+ mFullscreenArea.setVisibility(vis);
+ }
+
/**
* Compute the interesting insets into your UI. The default implementation
* uses the top of the candidates frame for the visible insets, and the
* top of the input frame for the content insets. The default touchable
* insets are {@link Insets#TOUCHABLE_INSETS_VISIBLE}.
*
- * Note that this method is not called when in fullscreen mode, since
+ *
Note that this method is not called when
+ * {@link #isExtractViewShown} returns true, since
* in that case the application is left as-is behind the input method and
* not impacted by anything in its UI.
*
@@ -821,9 +915,16 @@ public class InputMethodService extends AbstractInputMethodService {
if (mInputFrame.getVisibility() == View.VISIBLE) {
mInputFrame.getLocationInWindow(loc);
} else {
- loc[1] = 0;
+ View decor = getWindow().getWindow().getDecorView();
+ loc[1] = decor.getHeight();
+ }
+ if (isFullscreenMode()) {
+ // In fullscreen mode, we never resize the underlying window.
+ View decor = getWindow().getWindow().getDecorView();
+ outInsets.contentTopInsets = decor.getHeight();
+ } else {
+ outInsets.contentTopInsets = loc[1];
}
- outInsets.contentTopInsets = loc[1];
if (mCandidatesFrame.getVisibility() == View.VISIBLE) {
mCandidatesFrame.getLocationInWindow(loc);
}
@@ -889,11 +990,7 @@ public class InputMethodService extends AbstractInputMethodService {
* it is hidden.
*/
public void setCandidatesViewShown(boolean shown) {
- int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
- if (mCandidatesVisibility != vis) {
- mCandidatesFrame.setVisibility(vis);
- mCandidatesVisibility = vis;
- }
+ updateCandidatesVisibility(shown);
if (!mShowInputRequested && mWindowVisible != shown) {
// If we are being asked to show the candidates view while the app
// has not asked for the input view to be shown, then we need
@@ -906,17 +1003,26 @@ public class InputMethodService extends AbstractInputMethodService {
}
}
+ void updateCandidatesVisibility(boolean shown) {
+ int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
+ if (mCandidatesVisibility != vis) {
+ mCandidatesFrame.setVisibility(vis);
+ mCandidatesVisibility = vis;
+ }
+ }
+
/**
* Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
* or {@link View#GONE View.GONE}) of the candidates view when it is not
- * shown. The default implementation returns GONE when in fullscreen mode,
+ * shown. The default implementation returns GONE when
+ * {@link #isExtractViewShown} returns true,
* otherwise VISIBLE. Be careful if you change this to return GONE in
* other situations -- if showing or hiding the candidates view causes
* your window to resize, this can cause temporary drawing artifacts as
* the resize takes place.
*/
public int getCandidatesHiddenVisibility() {
- return isFullscreenMode() ? View.GONE : View.INVISIBLE;
+ return isExtractViewShown() ? View.GONE : View.INVISIBLE;
}
public void showStatusIcon(int iconResId) {
@@ -991,20 +1097,6 @@ public class InputMethodService extends AbstractInputMethodService {
mInputView = view;
}
- /**
- * Called by the framework to create a Drawable for the background of
- * the input method window. May return null for no background. The default
- * implementation returns a non-null standard background only when in
- * fullscreen mode. This is called each time the fullscreen mode changes.
- */
- public Drawable onCreateBackgroundDrawable() {
- if (isFullscreenMode()) {
- return getResources().getDrawable(
- com.android.internal.R.drawable.input_method_fullscreen_background);
- }
- return null;
- }
-
/**
* Called by the framework to create the layout for showing extacted text.
* Only called when in fullscreen mode. The returned view hierarchy must
@@ -1174,6 +1266,23 @@ public class InputMethodService extends AbstractInputMethodService {
+ " mWindowCreated=" + mWindowCreated
+ " mWindowVisible=" + mWindowVisible
+ " mInputStarted=" + mInputStarted);
+
+ if (mInShowWindow) {
+ Log.w(TAG, "Re-entrance in to showWindow");
+ return;
+ }
+
+ try {
+ mWindowWasVisible = mWindowVisible;
+ mInShowWindow = true;
+ showWindowInner(showInput);
+ } finally {
+ mWindowWasVisible = true;
+ mInShowWindow = false;
+ }
+ }
+
+ void showWindowInner(boolean showInput) {
boolean doShowInput = false;
boolean wasVisible = mWindowVisible;
mWindowVisible = true;
@@ -1241,6 +1350,7 @@ public class InputMethodService extends AbstractInputMethodService {
mWindow.hide();
mWindowVisible = false;
onWindowHidden();
+ mWindowWasVisible = false;
}
}
@@ -1559,7 +1669,7 @@ public class InputMethodService extends AbstractInputMethodService {
boolean doMovementKey(int keyCode, KeyEvent event, int count) {
final ExtractEditText eet = mExtractEditText;
- if (isFullscreenMode() && isInputViewShown() && eet != null) {
+ if (isExtractViewShown() && isInputViewShown() && eet != null) {
// If we are in fullscreen mode, the cursor will move around
// the extract edit text, but should NOT cause focus to move
// to other fields.
@@ -1583,10 +1693,10 @@ public class InputMethodService extends AbstractInputMethodService {
if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
reportExtractedMovement(keyCode, count);
} else {
- KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
+ KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
if (movement.onKeyDown(eet,
(Spannable)eet.getText(), keyCode, down)) {
- KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
+ KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
movement.onKeyUp(eet,
(Spannable)eet.getText(), keyCode, up);
while (--count > 0) {
@@ -1800,18 +1910,52 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
- * Called when it is time to update the actions available from a full-screen
- * IME. You do not need to deal with this if you are using the standard
- * full screen extract UI. If replacing it, you will need to re-implement
- * this to put the action in your own UI and handle it.
+ * Called when the fullscreen-mode extracting editor info has changed,
+ * to determine whether the extracting (extract text and candidates) portion
+ * of the UI should be shown. The standard implementation hides or shows
+ * the extract area depending on whether it makes sense for the
+ * current editor. In particular, a {@link InputType#TYPE_NULL}
+ * input type or {@link EditorInfo#IME_FLAG_NO_EXTRACT_UI} flag will
+ * turn off the extract area since there is no text to be shown.
*/
- public void onUpdateExtractingAccessories(EditorInfo ei) {
+ public void onUpdateExtractingVisibility(EditorInfo ei) {
+ if (ei.inputType == InputType.TYPE_NULL ||
+ (ei.imeOptions&EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0) {
+ // No reason to show extract UI!
+ setExtractViewShown(false);
+ return;
+ }
+
+ setExtractViewShown(true);
+ }
+
+ /**
+ * Called when the fullscreen-mode extracting editor info has changed,
+ * to update the state of its UI such as the action buttons shown.
+ * You do not need to deal with this if you are using the standard
+ * full screen extract UI. If replacing it, you will need to re-implement
+ * this to put the appropriate action button in your own UI and handle it,
+ * and perform any other changes.
+ *
+ *
The standard implementation turns on or off its accessory area
+ * depending on whether there is an action button, and hides or shows
+ * the entire extract area depending on whether it makes sense for the
+ * current editor. In particular, a {@link InputType#TYPE_NULL} or
+ * {@link InputType#TYPE_TEXT_VARIATION_FILTER} input type will turn off the
+ * extract area since there is no text to be shown.
+ */
+ public void onUpdateExtractingViews(EditorInfo ei) {
+ if (!isExtractViewShown()) {
+ return;
+ }
+
if (mExtractAccessories == null) {
return;
}
final boolean hasAction = ei.actionLabel != null || (
(ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
- (ei.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0);
+ (ei.imeOptions&EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION) == 0 &&
+ ei.inputType != InputType.TYPE_NULL);
if (hasAction) {
mExtractAccessories.setVisibility(View.VISIBLE);
if (ei.actionLabel != null) {
@@ -1855,7 +1999,8 @@ public class InputMethodService extends AbstractInputMethodService {
try {
eet.startInternalChanges();
- onUpdateExtractingAccessories(ei);
+ onUpdateExtractingVisibility(ei);
+ onUpdateExtractingViews(ei);
int inputType = ei.inputType;
if ((inputType&EditorInfo.TYPE_MASK_CLASS)
== EditorInfo.TYPE_CLASS_TEXT) {
@@ -1890,8 +2035,10 @@ public class InputMethodService extends AbstractInputMethodService {
final Printer p = new PrintWriterPrinter(fout);
p.println("Input method service state for " + this + ":");
p.println(" mWindowCreated=" + mWindowCreated
- + " mWindowAdded=" + mWindowAdded
- + " mWindowVisible=" + mWindowVisible);
+ + " mWindowAdded=" + mWindowAdded);
+ p.println(" mWindowVisible=" + mWindowVisible
+ + " mWindowWasVisible=" + mWindowWasVisible
+ + " mInShowWindow=" + mInShowWindow);
p.println(" Configuration=" + getResources().getConfiguration());
p.println(" mToken=" + mToken);
p.println(" mInputBinding=" + mInputBinding);
@@ -1914,7 +2061,8 @@ public class InputMethodService extends AbstractInputMethodService {
+ " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
p.println(" mCandidatesVisibility=" + mCandidatesVisibility
+ " mFullscreenApplied=" + mFullscreenApplied
- + " mIsFullscreen=" + mIsFullscreen);
+ + " mIsFullscreen=" + mIsFullscreen
+ + " mExtractViewHidden=" + mExtractViewHidden);
if (mExtractedText != null) {
p.println(" mExtractedText:");
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index c37845f02b632..d91ace6b778f6 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -31,18 +31,6 @@ import android.view.WindowManager;
*/
class SoftInputWindow extends Dialog {
- /**
- * Create a DockWindow that uses the default style.
- *
- * @param context The Context the DockWindow is to run it. In particular, it
- * uses the window manager and theme in this context to present its
- * UI.
- */
- public SoftInputWindow(Context context) {
- super(context, com.android.internal.R.style.Theme_InputMethod);
- initDockWindow();
- }
-
public void setToken(IBinder token) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.token = token;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7590bfef45355..76c74df27838a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4,6 +4,8 @@ import java.io.PrintWriter;
import java.util.Formatter;
import java.util.Map;
+import com.android.internal.os.BatteryStatsImpl.Timer;
+
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -39,6 +41,20 @@ public abstract class BatteryStats implements Parcelable {
* {@hide}
*/
public static final int SENSOR = 3;
+
+ /**
+ * A constant indicating a full wifi lock timer
+ *
+ * {@hide}
+ */
+ public static final int FULL_WIFI_LOCK = 4;
+
+ /**
+ * A constant indicating a scan wifi lock timer
+ *
+ * {@hide}
+ */
+ public static final int SCAN_WIFI_LOCK = 5;
/**
* Include all of the data in the stats, including previously saved data.
@@ -74,6 +90,7 @@ public abstract class BatteryStats implements Parcelable {
private static final String WAKELOCK_DATA = "wakelock";
private static final String NETWORK_DATA = "network";
private static final String BATTERY_DATA = "battery";
+ private static final String WIFI_LOCK_DATA = "wifilock";
private static final String MISC_DATA = "misc";
private final StringBuilder mFormatBuilder = new StringBuilder(8);
@@ -162,6 +179,13 @@ public abstract class BatteryStats implements Parcelable {
* {@hide}
*/
public abstract long getTcpBytesSent(int which);
+
+ public abstract void noteFullWifiLockAcquiredLocked();
+ public abstract void noteFullWifiLockReleasedLocked();
+ public abstract void noteScanWifiLockAcquiredLocked();
+ public abstract void noteScanWifiLockReleasedLocked();
+ public abstract long getFullWifiLockTime(long batteryRealtime, int which);
+ public abstract long getScanWifiLockTime(long batteryRealtime, int which);
public static abstract class Sensor {
// Magic sensor number for the GPS.
@@ -269,6 +293,22 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getPhoneOnTime(long batteryRealtime, int which);
+ /**
+ * Returns the time in milliseconds that wifi has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getWifiOnTime(long batteryRealtime, int which);
+
+ /**
+ * Returns the time in milliseconds that bluetooth has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getBluetoothOnTime(long batteryRealtime, int which);
+
/**
* Return whether we are currently running on battery.
*/
@@ -292,6 +332,17 @@ public abstract class BatteryStats implements Parcelable {
* @param curTime the amount of elapsed realtime in microseconds.
*/
public abstract long getBatteryRealtime(long curTime);
+
+ /**
+ * Returns the battery percentage level at the last time the device was unplugged from power,
+ * or the last time it was booted while unplugged.
+ */
+ public abstract int getUnpluggedStartLevel();
+
+ /**
+ * Returns the battery percentage level at the last time the device was plugged into power.
+ */
+ public abstract int getPluggedStartLevel();
/**
* Returns the total, last, or current battery uptime in microseconds.
@@ -483,6 +534,8 @@ public abstract class BatteryStats implements Parcelable {
final long totalUptime = computeUptime(rawUptime, which);
final long screenOnTime = getScreenOnTime(batteryRealtime, which);
final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+ final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
+ final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
StringBuilder sb = new StringBuilder(128);
@@ -496,7 +549,12 @@ public abstract class BatteryStats implements Parcelable {
// Dump misc stats
dumpLine(pw, 0 /* uid */, category, MISC_DATA,
- screenOnTime / 1000, phoneOnTime / 1000);
+ screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000, bluetoothOnTime / 1000);
+
+ if (which == STATS_UNPLUGGED) {
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, getUnpluggedStartLevel(),
+ getPluggedStartLevel());
+ }
SparseArray extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
@@ -506,7 +564,15 @@ public abstract class BatteryStats implements Parcelable {
// Dump Network stats per uid, if any
long rx = u.getTcpBytesReceived(which);
long tx = u.getTcpBytesSent(which);
+ long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
+ long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
+
if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
+
+ if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
+ dumpLine(pw, uid, category, WIFI_LOCK_DATA,
+ fullWifiLockOnTime, scanWifiLockOnTime);
+ }
Map wakelocks = u.getWakelockStats();
if (wakelocks.size() > 0) {
@@ -624,13 +690,35 @@ public abstract class BatteryStats implements Parcelable {
+ formatTimeMs(totalRealtime / 1000)
+ "realtime");
- long screenOnTime = getScreenOnTime(batteryRealtime, which);
- long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+ final long screenOnTime = getScreenOnTime(batteryRealtime, which);
+ final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+ final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
+ final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
pw.println(prefix
+ " Time with screen on: " + formatTimeMs(screenOnTime / 1000)
+ "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime)
+ "), time with phone on: " + formatTimeMs(phoneOnTime / 1000)
- + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")");
+ + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime)
+ + "), time with wifi on: " + formatTimeMs(wifiOnTime / 1000)
+ + "(" + formatRatioLocked(wifiOnTime, whichBatteryRealtime)
+ + "), time with bluetooth on: " + formatTimeMs(bluetoothOnTime / 1000)
+ + "(" + formatRatioLocked(bluetoothOnTime, whichBatteryRealtime)+ ")");
+
+ pw.println(" ");
+
+ if (which == STATS_UNPLUGGED) {
+ if (getIsOnBattery()) {
+ pw.println(prefix + " Device is currently unplugged");
+ pw.println(prefix + " Discharge cycle start level: " +
+ getUnpluggedStartLevel());
+ } else {
+ pw.println(prefix + " Device is currently plugged into power");
+ pw.println(prefix + " Last discharge cycle start level: " +
+ getUnpluggedStartLevel());
+ pw.println(prefix + " Last discharge cycle end level: " +
+ getPluggedStartLevel());
+ }
+ }
pw.println(" ");
@@ -644,10 +732,23 @@ public abstract class BatteryStats implements Parcelable {
long tcpReceived = u.getTcpBytesReceived(which);
long tcpSent = u.getTcpBytesSent(which);
+ long fullWifiLockOnTime = u.getFullWifiLockTime(batteryRealtime, which);
+ long scanWifiLockOnTime = u.getScanWifiLockTime(batteryRealtime, which);
+
if (tcpReceived != 0 || tcpSent != 0) {
pw.println(prefix + " Network: " + tcpReceived + " bytes received, "
+ tcpSent + " bytes sent");
}
+ if (fullWifiLockOnTime != 0 || scanWifiLockOnTime != 0) {
+ pw.println(prefix + " Full Wifi Lock Time: "
+ + formatTime(fullWifiLockOnTime / 1000)
+ + "(" + formatRatioLocked(fullWifiLockOnTime,
+ whichBatteryRealtime)+ ")");
+ pw.println(prefix + " Scan Wifi Lock Time: "
+ + formatTime(scanWifiLockOnTime / 1000)
+ + "(" + formatRatioLocked(scanWifiLockOnTime,
+ whichBatteryRealtime)+ ")");
+ }
Map wakelocks = u.getWakelockStats();
if (wakelocks.size() > 0) {
diff --git a/core/java/android/os/Hardware.java b/core/java/android/os/Hardware.java
index 3b6c9d7b2defe..efc5617451fc1 100644
--- a/core/java/android/os/Hardware.java
+++ b/core/java/android/os/Hardware.java
@@ -21,22 +21,29 @@ package android.os;
*/
public class Hardware
{
- /**
- * Control the LED.
- */
- public static native int setLedState(int colorARGB, int onMS, int offMS);
-
- /**
- * Control the Flashlight
- */
+
+
+ /* ********************************************************************************
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Don't add anything else to this class. Add it to HardwareService instead.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * ********************************************************************************/
+
+
public static native boolean getFlashlightEnabled();
public static native void setFlashlightEnabled(boolean on);
public static native void enableCameraFlash(int milliseconds);
-
- /**
- * Control the backlights
- */
- public static native void setScreenBacklight(int brightness);
- public static native void setKeyboardBacklight(boolean on);
- public static native void setButtonBacklight(boolean on);
}
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
index 4f6029f59fb2f..fb121bb5e2ee1 100755
--- a/core/java/android/os/IHardwareService.aidl
+++ b/core/java/android/os/IHardwareService.aidl
@@ -29,12 +29,10 @@ interface IHardwareService
void setFlashlightEnabled(boolean on);
void enableCameraFlash(int milliseconds);
- // backlight support
- void setScreenBacklight(int brightness);
- void setKeyboardBacklight(boolean on);
- void setButtonBacklight(boolean on);
-
- // LED support
- void setLedState(int colorARGB, int onMS, int offMS);
+ // sets the brightness of the backlights (screen, keyboard, button) 0-255
+ void setBacklights(int brightness);
+
+ // for the phone
+ void setAttentionLight(boolean on);
}
diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java
index b53e22704d1f5..47497e547ff1f 100644
--- a/core/java/android/os/Power.java
+++ b/core/java/android/os/Power.java
@@ -44,26 +44,6 @@ public class Power
public static native void acquireWakeLock(int lock, String id);
public static native void releaseWakeLock(String id);
- /**
- * Flag to turn on and off the keyboard light.
- */
- public static final int KEYBOARD_LIGHT = 0x00000001;
-
- /**
- * Flag to turn on and off the screen backlight.
- */
- public static final int SCREEN_LIGHT = 0x00000002;
-
- /**
- * Flag to turn on and off the button backlight.
- */
- public static final int BUTTON_LIGHT = 0x00000004;
-
- /**
- * Flags to turn on and off all the backlights.
- */
- public static final int ALL_LIGHTS = (KEYBOARD_LIGHT|SCREEN_LIGHT|BUTTON_LIGHT);
-
/**
* Brightness value for fully off
*/
@@ -90,14 +70,6 @@ public class Power
*/
public static final int LOW_BATTERY_THRESHOLD = 10;
- /**
- * Set the brightness for one or more lights
- *
- * @param mask flags indicating which lights to change brightness
- * @param brightness new brightness value (0 = off, 255 = fully bright)
- */
- public static native int setLightBrightness(int mask, int brightness);
-
/**
* Turn the screen on or off
*
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 04e7ef05c3a2d..63f6dffba87e5 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -211,7 +211,7 @@ public class RemoteCallbackList {
for (Callback cb : mCallbacks.values()) {
active[i++] = cb.mCallback;
}
- return N;
+ return i;
}
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index d75a25fe8a35d..4a709f6c7517a 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -1054,6 +1054,9 @@ public final class Calendar {
if (cursor == null) {
return;
}
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "missed alarms found: " + cursor.getCount());
+ }
try {
while (cursor.moveToNext()) {
@@ -1068,6 +1071,8 @@ public final class Calendar {
intent.putExtra(android.provider.Calendar.EVENT_END_TIME, end);
PendingIntent sender = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ Log.w(TAG, "rescheduling missed alarm, id: " + id + " begin: " + begin
+ + " end: " + end + " alarmTime: " + alarmTime);
manager.set(AlarmManager.RTC_WAKEUP, alarmTime, sender);
}
} finally {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 10fe3f5c5487f..abd6934a86b39 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -22,6 +22,8 @@ import android.content.Context;
import android.net.Uri;
import android.provider.Contacts.People;
import com.android.internal.telephony.CallerInfo;
+import com.android.internal.telephony.Connection;
+
import android.text.TextUtils;
import android.util.Log;
@@ -137,7 +139,8 @@ public class CallLog {
* if the contact is unknown.
* @param context the context used to get the ContentResolver
* @param number the phone number to be added to the calls db
- * @param isPrivateNumber true if the call was marked as private by the network
+ * @param presentation the number presenting rules set by the network for
+ * "allowed", "payphone", "restricted" or "unknown"
* @param callType enumerated values for "incoming", "outgoing", or "missed"
* @param start time stamp for the call in milliseconds
* @param duration call duration in seconds
@@ -145,12 +148,14 @@ public class CallLog {
* {@hide}
*/
public static Uri addCall(CallerInfo ci, Context context, String number,
- boolean isPrivateNumber, int callType, long start, int duration) {
+ int presentation, int callType, long start, int duration) {
final ContentResolver resolver = context.getContentResolver();
if (TextUtils.isEmpty(number)) {
- if (isPrivateNumber) {
+ if (presentation == Connection.PRESENTATION_RESTRICTED) {
number = CallerInfo.PRIVATE_NUMBER;
+ } else if (presentation == Connection.PRESENTATION_PAYPHONE) {
+ number = CallerInfo.PAYPHONE_NUMBER;
} else {
number = CallerInfo.UNKNOWN_NUMBER;
}
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 2aa77eab026d3..be31c0a55d815 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -1459,13 +1459,24 @@ public class Contacts {
"com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
/**
- * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new contact if no matching
- * contact found. Otherwise, default behavior is to prompt user with dialog before creating.
- *
- * Type: BOOLEAN
+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
+ * contact if no matching contact found. Otherwise, default behavior is
+ * to prompt user with dialog before creating.
+ *
+ * Type: BOOLEAN
*/
public static final String EXTRA_FORCE_CREATE =
"com.android.contacts.action.FORCE_CREATE";
+
+ /**
+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
+ * description to be shown when prompting user about creating a new
+ * contact.
+ *
+ * Type: STRING
+ */
+ public static final String EXTRA_CREATE_DESCRIPTION =
+ "com.android.contacts.action.CREATE_DESCRIPTION";
/**
* Intents related to the Contacts app UI.
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 3aa407858100c..3c507074af833 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -63,6 +63,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private final IntentFilter mIntentFilter;
private HashMap mAudioDevices;
private final AudioManager mAudioManager;
+ private final BluetoothDevice mBluetooth;
private class SinkState {
public String address;
@@ -75,9 +76,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- BluetoothDevice device =
- (BluetoothDevice)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
+ mBluetooth = (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (mBluetooth == null) {
throw new RuntimeException("Platform does not support Bluetooth");
}
@@ -85,13 +85,12 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
throw new RuntimeException("Could not init BluetoothA2dpService");
}
- mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION);
- mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION);
+ mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
mContext.registerReceiver(mReceiver, mIntentFilter);
- if (device.isEnabled()) {
+ if (mBluetooth.isEnabled()) {
onBluetoothEnable();
}
}
@@ -110,10 +109,17 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
- if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
- onBluetoothEnable();
- } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
- onBluetoothDisable();
+ if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
+ BluetoothError.ERROR);
+ switch (state) {
+ case BluetoothDevice.BLUETOOTH_STATE_ON:
+ onBluetoothEnable();
+ break;
+ case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+ onBluetoothDisable();
+ break;
+ }
} else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) {
int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE,
BluetoothError.ERROR);
@@ -145,9 +151,10 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
switch (msg.what) {
case MESSAGE_CONNECT_TO:
String address = (String)msg.obj;
- // check device is still preferred, and nothing is currently
- // connected
- if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
+ // check bluetooth is still on, device is still preferred, and
+ // nothing is currently connected
+ if (mBluetooth.isEnabled() &&
+ getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
lookupSinksMatchingStates(new int[] {
BluetoothA2dp.STATE_CONNECTING,
BluetoothA2dp.STATE_CONNECTED,
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 9e9ba6237613a..b7e3846ab9eb2 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -37,8 +37,10 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemService;
import android.provider.Settings;
import android.util.Log;
@@ -51,6 +53,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import com.android.internal.app.IBatteryStats;
+
public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private static final String TAG = "BluetoothDeviceService";
private static final boolean DBG = true;
@@ -60,14 +64,18 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private IntentFilter mIntentFilter;
private boolean mIsAirplaneSensitive;
private final BondState mBondState = new BondState(); // local cache of bondings
- private volatile boolean mIsEnabled; // local cache of isEnabledNative()
+ private int mBluetoothState;
private boolean mIsDiscovering;
+ private final IBatteryStats mBatteryStats;
private final Context mContext;
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
+ private static final int MESSAGE_FINISH_DISABLE = 2;
+
static {
classInitNative();
}
@@ -75,6 +83,12 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public BluetoothDeviceService(Context context) {
mContext = context;
+
+ // Need to do this in place of:
+ // mBatteryStats = BatteryStatsService.getService();
+ // Since we can not import BatteryStatsService from here. This class really needs to be
+ // moved to java/services/com/android/server/
+ mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
}
/** Must be called after construction, and before any other method.
@@ -87,7 +101,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
disableNative();
}
- mIsEnabled = false;
+ setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
mIsDiscovering = false;
mEventLoop = new BluetoothEventLoop(mContext, this);
registerForAirplaneMode();
@@ -109,10 +123,16 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public boolean isEnabled() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mIsEnabled;
+ return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON;
}
private native int isEnabledNative();
+ public int getBluetoothState() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothState;
+ }
+
+
/**
* Bring down bluetooth and disable BT in settings. Returns true on success.
*/
@@ -124,17 +144,36 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
* Bring down bluetooth. Returns true on success.
*
* @param saveSetting If true, disable BT in settings
- *
*/
public synchronized boolean disable(boolean saveSetting) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
+ switch (mBluetoothState) {
+ case BluetoothDevice.BLUETOOTH_STATE_OFF:
+ return true;
+ case BluetoothDevice.BLUETOOTH_STATE_ON:
+ break;
+ default:
+ return false;
+ }
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
- if (!mIsEnabled) {
- return true;
+ setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF);
+
+ // Allow 3 seconds for profiles to gracefully disconnect
+ // TODO: Introduce a callback mechanism so that each profile can notify
+ // BluetoothDeviceService when it is done shutting down
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
+ return true;
+ }
+
+
+ private synchronized void finishDisable(boolean saveSetting) {
+ if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+ return;
}
mEventLoop.stop();
disableNative();
@@ -163,38 +202,37 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mIsEnabled = false;
+ mIsDiscovering = false;
+
if (saveSetting) {
persistBluetoothOnSetting(false);
}
- mIsDiscovering = false;
- intent = new Intent(BluetoothIntent.DISABLED_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- return true;
+
+ setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
+
+ // Log bluetooth off to battery stats.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteBluetoothOff();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
- /**
- * Bring up bluetooth, asynchronously, and enable BT in settings.
- * This turns on/off the underlying hardware.
- *
- * @return True on success (so far), guaranteeing the callback with be
- * notified when complete.
- */
- public boolean enable(IBluetoothDeviceCallback callback) {
- return enable(callback, true);
+ /** Bring up BT and persist BT on in settings */
+ public boolean enable() {
+ return enable(true);
}
/**
* Enable this Bluetooth device, asynchronously.
* This turns on/off the underlying hardware.
*
- * @param saveSetting If true, enable BT in settings
- *
- * @return True on success (so far), guaranteeing the callback with be
- * notified when complete.
+ * @param saveSetting If true, persist the new state of BT in settings
+ * @return True on success (so far)
*/
- public synchronized boolean enable(IBluetoothDeviceCallback callback,
- boolean saveSetting) {
+ public synchronized boolean enable(boolean saveSetting) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -202,28 +240,49 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
if (mIsAirplaneSensitive && isAirplaneModeOn()) {
return false;
}
- if (mIsEnabled) {
+ if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) {
return false;
}
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
- mEnableThread = new EnableThread(callback, saveSetting);
+ setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON);
+ mEnableThread = new EnableThread(saveSetting);
mEnableThread.start();
return true;
}
- private static final int REGISTER_SDP_RECORDS = 1;
+ private synchronized void setBluetoothState(int state) {
+ if (state == mBluetoothState) {
+ return;
+ }
+
+ if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
+
+ Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState);
+ intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+ mBluetoothState = state;
+
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case REGISTER_SDP_RECORDS:
+ case MESSAGE_REGISTER_SDP_RECORDS:
//TODO: Don't assume HSP/HFP is running, don't use sdptool,
if (isEnabled()) {
SystemService.start("hsag");
SystemService.start("hfag");
}
+ break;
+ case MESSAGE_FINISH_DISABLE:
+ finishDisable(msg.arg1 != 0);
+ break;
}
}
};
@@ -231,10 +290,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private EnableThread mEnableThread;
private class EnableThread extends Thread {
- private final IBluetoothDeviceCallback mEnableCallback;
private final boolean mSaveSetting;
- public EnableThread(IBluetoothDeviceCallback callback, boolean saveSetting) {
- mEnableCallback = callback;
+ public EnableThread(boolean saveSetting) {
mSaveSetting = saveSetting;
}
public void run() {
@@ -244,7 +301,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
boolean running = false;
while ((retryCount-- > 0) && !running) {
mEventLoop.start();
- // it may take a momement for the other thread to do its
+ // it may take a momement for the other thread to do its
// thing. Check periodically for a while.
int pollCount = 5;
while ((pollCount-- > 0) && !running) {
@@ -264,36 +321,37 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
}
}
- if (mEnableCallback != null) {
- try {
- mEnableCallback.onEnableResult(res ?
- BluetoothDevice.RESULT_SUCCESS :
- BluetoothDevice.RESULT_FAILURE);
- } catch (RemoteException e) {}
- }
if (res) {
- mIsEnabled = true;
if (mSaveSetting) {
persistBluetoothOnSetting(true);
}
mIsDiscovering = false;
mBondState.loadBondState();
- mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS), 3000);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS),
+ 3000);
+ // Log bluetooth on to battery stats.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteBluetoothOn();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ mEnableThread = null;
+
+ setBluetoothState(res ?
+ BluetoothDevice.BLUETOOTH_STATE_ON :
+ BluetoothDevice.BLUETOOTH_STATE_OFF);
+
+ if (res) {
// Update mode
mEventLoop.onModeChanged(getModeNative());
}
- Intent intent = null;
- if (res) {
- intent = new Intent(BluetoothIntent.ENABLED_ACTION);
- } else {
- intent = new Intent(BluetoothIntent.DISABLED_ACTION);
- }
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mEnableThread = null;
}
}
@@ -320,18 +378,24 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private final HashMap mState = new HashMap();
private final HashMap mPinAttempt = new HashMap();
private final ArrayList mAutoPairingFailures = new ArrayList();
- // List of all the vendor_id prefix of Bluetooth addresses for which
- // auto pairing is not attempted
+ // List of all the vendor_id prefix of Bluetooth addresses for
+ // which auto pairing is not attempted.
+ // The following companies are included in the list below:
+ // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
+ // Parrot, Zhongshan General K-mate Electronics, Great Well
+ // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
+ // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
private final ArrayList mAutoPairingBlacklisted =
new ArrayList(Arrays.asList(
- "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", //ALPS
- "00:21:4F", "00:23:06", "00:24:33", "00:A0:79", // ALPS
- "00:0E:6D", "00:13:E0", "00:21:E8", "00:60:57",// Murata for Prius 2007
- "00:0E:9F" // TEMIC SDS for Porsche
+ "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
+ "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
+ "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
+ "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
+ "00:0A:30"
));
public synchronized void loadBondState() {
- if (!mIsEnabled) {
+ if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) {
return;
}
String[] bonds = listBondingsNative();
@@ -1051,7 +1115,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
// If bluetooth is currently expected to be on, then enable or disable bluetooth
if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
if (enabled) {
- enable(null, false);
+ enable(false);
} else {
disable(false);
}
@@ -1079,52 +1143,63 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mIsEnabled) {
- pw.println("\nBluetooth ENABLED: " + getAddress() + " (" + getName() + ")");
- pw.println("\nisDiscovering() = " + isDiscovering());
+ pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
- BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
-
- String[] addresses = listRemoteDevices();
-
- pw.println("\n--Known devices--");
- for (String address : addresses) {
- pw.printf("%s %10s (%d) %s\n", address,
- toBondStateString(mBondState.getBondState(address)),
- mBondState.getAttempt(address),
- getRemoteName(address));
- }
-
- addresses = listAclConnections();
- pw.println("\n--ACL connected devices--");
- for (String address : addresses) {
- pw.println(address);
- }
-
- // Rather not do this from here, but no-where else and I need this
- // dump
- pw.println("\n--Headset Service--");
- switch (headset.getState()) {
- case BluetoothHeadset.STATE_DISCONNECTED:
- pw.println("getState() = STATE_DISCONNECTED");
- break;
- case BluetoothHeadset.STATE_CONNECTING:
- pw.println("getState() = STATE_CONNECTING");
- break;
- case BluetoothHeadset.STATE_CONNECTED:
- pw.println("getState() = STATE_CONNECTED");
- break;
- case BluetoothHeadset.STATE_ERROR:
- pw.println("getState() = STATE_ERROR");
- break;
- }
- pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
- headset.close();
-
- } else {
- pw.println("\nBluetooth DISABLED");
+ switch(mBluetoothState) {
+ case BluetoothDevice.BLUETOOTH_STATE_OFF:
+ pw.println("\nBluetooth OFF\n");
+ return;
+ case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON:
+ pw.println("\nBluetooth TURNING ON\n");
+ return;
+ case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+ pw.println("\nBluetooth TURNING OFF\n");
+ return;
+ case BluetoothDevice.BLUETOOTH_STATE_ON:
+ pw.println("\nBluetooth ON\n");
}
- pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive);
+
+ pw.println("\nLocal address = " + getAddress());
+ pw.println("\nLocal name = " + getName());
+ pw.println("\nisDiscovering() = " + isDiscovering());
+
+ BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
+
+ String[] addresses = listRemoteDevices();
+
+ pw.println("\n--Known devices--");
+ for (String address : addresses) {
+ pw.printf("%s %10s (%d) %s\n", address,
+ toBondStateString(mBondState.getBondState(address)),
+ mBondState.getAttempt(address),
+ getRemoteName(address));
+ }
+
+ addresses = listAclConnections();
+ pw.println("\n--ACL connected devices--");
+ for (String address : addresses) {
+ pw.println(address);
+ }
+
+ // Rather not do this from here, but no-where else and I need this
+ // dump
+ pw.println("\n--Headset Service--");
+ switch (headset.getState()) {
+ case BluetoothHeadset.STATE_DISCONNECTED:
+ pw.println("getState() = STATE_DISCONNECTED");
+ break;
+ case BluetoothHeadset.STATE_CONNECTING:
+ pw.println("getState() = STATE_CONNECTING");
+ break;
+ case BluetoothHeadset.STATE_CONNECTED:
+ pw.println("getState() = STATE_CONNECTED");
+ break;
+ case BluetoothHeadset.STATE_ERROR:
+ pw.println("getState() = STATE_ERROR");
+ break;
+ }
+ pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
+ headset.close();
}
/* package */ static int bluezStringToScanMode(String mode) {
@@ -1159,3 +1234,4 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
Log.d(TAG, msg);
}
}
+
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 8e77eed9c067c..6be8eb96ba21d 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -46,10 +46,10 @@ class BluetoothEventLoop {
private Thread mThread;
private boolean mStarted;
private boolean mInterrupted;
- private HashMap mPasskeyAgentRequestData;
- private HashMap mGetRemoteServiceChannelCallbacks;
- private BluetoothDeviceService mBluetoothService;
- private Context mContext;
+ private final HashMap mPasskeyAgentRequestData;
+ private final HashMap mGetRemoteServiceChannelCallbacks;
+ private final BluetoothDeviceService mBluetoothService;
+ private final Context mContext;
private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
private static final int EVENT_RESTART_BLUETOOTH = 2;
@@ -77,7 +77,7 @@ class BluetoothEventLoop {
break;
case EVENT_RESTART_BLUETOOTH:
mBluetoothService.disable();
- mBluetoothService.enable(null);
+ mBluetoothService.enable();
break;
}
}
@@ -309,6 +309,12 @@ class BluetoothEventLoop {
address = address.toUpperCase();
mPasskeyAgentRequestData.put(address, new Integer(nativeData));
+ if (mBluetoothService.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+ // shutdown path
+ mBluetoothService.cancelPin(address);
+ return;
+ }
+
if (mBluetoothService.getBondState().getBondState(address) ==
BluetoothDevice.BOND_BONDING) {
// we initiated the bonding
@@ -347,7 +353,7 @@ class BluetoothEventLoop {
private boolean onAuthAgentAuthorize(String address, String service, String uuid) {
boolean authorized = false;
- if (service.endsWith("service_audio")) {
+ if (mBluetoothService.isEnabled() && service.endsWith("service_audio")) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF;
if (authorized) {
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 849571485dc7a..6f0be3a64f8df 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -28,6 +28,8 @@ import org.xml.sax.XMLReader;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.AlignmentSpan;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
@@ -41,6 +43,7 @@ import android.text.style.SuperscriptSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
+import android.util.Log;
import com.android.internal.util.XmlUtils;
import java.io.IOException;
@@ -137,11 +140,52 @@ public class Html {
*/
public static String toHtml(Spanned text) {
StringBuilder out = new StringBuilder();
+ withinHtml(out, text);
+ return out.toString();
+ }
+
+ private static void withinHtml(StringBuilder out, Spanned text) {
int len = text.length();
int next;
for (int i = 0; i < text.length(); i = next) {
- next = text.nextSpanTransition(i, len, QuoteSpan.class);
+ next = text.nextSpanTransition(i, len, ParagraphStyle.class);
+ ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
+ if (style.length > 0) {
+ out.append(" 0) {
+ out.append(">");
+ }
+
+ withinDiv(out, text, i, next);
+
+ if (style.length > 0) {
+ out.append("
");
+ }
+ }
+ }
+
+ private static void withinDiv(StringBuilder out, Spanned text,
+ int start, int end) {
+ int next;
+ for (int i = start; i < end; i = next) {
+ next = text.nextSpanTransition(i, end, QuoteSpan.class);
QuoteSpan[] quotes = text.getSpans(i, next, QuoteSpan.class);
for (QuoteSpan quote: quotes) {
@@ -154,8 +198,6 @@ public class Html {
out.append("\n");
}
}
-
- return out.toString();
}
private static void withinBlockquote(StringBuilder out, Spanned text,
@@ -234,11 +276,32 @@ public class Html {
// Don't output the dummy character underlying the image.
i = next;
}
+ if (style[j] instanceof AbsoluteSizeSpan) {
+ out.append("");
+ }
+ if (style[j] instanceof ForegroundColorSpan) {
+ out.append("");
+ }
}
withinStyle(out, text, i, next);
for (int j = style.length - 1; j >= 0; j--) {
+ if (style[j] instanceof ForegroundColorSpan) {
+ out.append("");
+ }
+ if (style[j] instanceof AbsoluteSizeSpan) {
+ out.append("");
+ }
if (style[j] instanceof URLSpan) {
out.append("");
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 95acf9d236171..23e740d305141 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,8 @@
package android.text;
+import android.emoji.EmojiFactory;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -36,6 +38,20 @@ import android.view.KeyEvent;
* For text that will not change, use a {@link StaticLayout}.
*/
public abstract class Layout {
+ /* package */ static final EmojiFactory EMOJI_FACTORY =
+ EmojiFactory.newAvailableInstance();
+ /* package */ static final int MIN_EMOJI, MAX_EMOJI;
+
+ static {
+ if (EMOJI_FACTORY != null) {
+ MIN_EMOJI = EMOJI_FACTORY.getMinimumAndroidPua();
+ MAX_EMOJI = EMOJI_FACTORY.getMaximumAndroidPua();
+ } else {
+ MIN_EMOJI = -1;
+ MAX_EMOJI = -1;
+ }
+ };
+
/**
* Return how wide a layout would be necessary to display the
* specified text with one line per paragraph.
@@ -445,7 +461,9 @@ public abstract class Layout {
public abstract int getParagraphDirection(int line);
/**
- * Returns whether the specified line contains one or more tabs.
+ * Returns whether the specified line contains one or more
+ * characters that need to be handled specially, like tabs
+ * or emoji.
*/
public abstract boolean getLineContainsTab(int line);
@@ -1352,6 +1370,26 @@ public abstract class Layout {
h = dir * nextTab(text, start, end, h * dir, parspans);
segstart = j + 1;
+ } else if (hasTabs && buf[j] >= 0xD800 && buf[j] <= 0xDFFF && j + 1 < there) {
+ int emoji = Character.codePointAt(buf, j);
+
+ if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
+ Bitmap bm = EMOJI_FACTORY.
+ getBitmapFromAndroidPua(emoji);
+
+ if (bm != null) {
+ h += Styled.drawText(canvas, text,
+ start + segstart, start + j,
+ dir, (i & 1) != 0, x + h,
+ top, y, bottom, paint, workPaint,
+ start + j != end);
+
+ canvas.drawBitmap(bm, x + h, y - bm.getHeight(), paint);
+ h += bm.getWidth();
+ j++;
+ segstart = j + 1;
+ }
+ }
}
}
@@ -1394,7 +1432,22 @@ public abstract class Layout {
int segstart = here;
for (int j = hasTabs ? here : there; j <= there; j++) {
- if (j == there || buf[j] == '\t') {
+ int codept = 0;
+ Bitmap bm = null;
+
+ if (hasTabs && j < there) {
+ codept = buf[j];
+ }
+
+ if (codept >= 0xD800 && codept <= 0xDFFF && j + 1 < there) {
+ codept = Character.codePointAt(buf, j);
+
+ if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
+ bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
+ }
+ }
+
+ if (j == there || codept == '\t' || bm != null) {
float segw;
if (offset < start + j ||
@@ -1449,6 +1502,16 @@ public abstract class Layout {
h = dir * nextTab(text, start, end, h * dir, tabs);
}
+ if (bm != null) {
+ if (dir == DIR_RIGHT_TO_LEFT) {
+ h -= bm.getWidth();
+ } else {
+ h += bm.getWidth();
+ }
+
+ j++;
+ }
+
segstart = j + 1;
}
}
@@ -1488,7 +1551,22 @@ public abstract class Layout {
}
for (int i = hasTabs ? 0 : len; i <= len; i++) {
- if (i == len || buf[i] == '\t') {
+ int codept = 0;
+ Bitmap bm = null;
+
+ if (hasTabs && i < len) {
+ codept = buf[i];
+ }
+
+ if (codept >= 0xD800 && codept <= 0xDFFF && i < len) {
+ codept = Character.codePointAt(buf, i);
+
+ if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
+ bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
+ }
+ }
+
+ if (i == len || codept == '\t' || bm != null) {
workPaint.baselineShift = 0;
h += Styled.measureText(paint, workPaint, text,
@@ -1505,8 +1583,14 @@ public abstract class Layout {
}
}
- if (i != len)
- h = nextTab(text, start, end, h, tabs);
+ if (i != len) {
+ if (bm == null) {
+ h = nextTab(text, start, end, h, tabs);
+ } else {
+ h += bm.getWidth();
+ i++;
+ }
+ }
if (fm != null) {
if (fm.ascent < ab) {
@@ -1522,6 +1606,17 @@ public abstract class Layout {
if (fm.bottom > bot) {
bot = fm.bottom;
}
+
+ if (bm != null) {
+ int ht = -bm.getHeight();
+
+ if (ht < ab) {
+ ab = ht;
+ }
+ if (ht < top) {
+ top = ht;
+ }
+ }
}
here = i + 1;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 0fef40beb89f9..720d15aa59805 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,6 +16,7 @@
package android.text;
+import android.graphics.Bitmap;
import android.graphics.Paint;
import com.android.internal.util.ArrayUtils;
import android.util.Log;
@@ -421,11 +422,16 @@ extends Layout
// dump(chdirs, n, "final");
- // extra: enforce that all tabs go the primary direction
+ // extra: enforce that all tabs and surrogate characters go the
+ // primary direction
+ // TODO: actually do directions right for surrogates
for (int j = 0; j < n; j++) {
- if (chs[j] == '\t')
+ char c = chs[j];
+
+ if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) {
chdirs[j] = SOR;
+ }
}
// extra: enforce that object replacements go to the
@@ -548,16 +554,29 @@ extends Layout
char c = chs[j - start];
float before = w;
- switch (c) {
- case '\n':
- break;
-
- case '\t':
+ if (c == '\n') {
+ ;
+ } else if (c == '\t') {
w = Layout.nextTab(sub, start, end, w, null);
tab = true;
- break;
+ } else if (c >= 0xD800 && c <= 0xDFFF && j + 1 < next) {
+ int emoji = Character.codePointAt(chs, j - start);
- default:
+ if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
+ Bitmap bm = EMOJI_FACTORY.
+ getBitmapFromAndroidPua(emoji);
+
+ if (bm != null) {
+ w += bm.getWidth();
+ tab = true;
+ j++;
+ } else {
+ w += widths[j - start + (end - start)];
+ }
+ } else {
+ w += widths[j - start + (end - start)];
+ }
+ } else {
w += widths[j - start + (end - start)];
}
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index f7ac522aba6e0..23f3e3c3ece9d 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -201,8 +201,6 @@ public class GestureDetector {
private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
- // TODO make new double-tap timeout, and define its events (i.e. either time
- // between down-down or time between up-down)
private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
// constants for Message.what used by GestureHandler below
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a856b24c63506..15e7eb2269d3c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -62,7 +62,8 @@ interface IWindowManager
void addAppToken(int addPos, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen);
void setAppGroupId(IBinder token, int groupId);
- Configuration updateOrientationFromAppTokens(IBinder freezeThisOneIfNeeded);
+ Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
+ IBinder freezeThisOneIfNeeded);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 430cc71de6108..41779baedaf70 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -234,6 +234,22 @@ public class KeyEvent implements Parcelable {
*/
public static final int FLAG_KEEP_TOUCH_MODE = 0x4;
+ /**
+ * This mask is set if an event was known to come from a trusted part
+ * of the system. That is, the event is known to come from the user,
+ * and could not have been spoofed by a third party component.
+ */
+ public static final int FLAG_FROM_SYSTEM = 0x8;
+
+ /**
+ * This mask is used for compatibility, to identify enter keys that are
+ * coming from an IME whose enter key has been auto-labelled "next" or
+ * "done". This allows TextView to dispatch these as normal enter keys
+ * for old applications, but still do the appropriate action when
+ * receiving them.
+ */
+ public static final int FLAG_EDITOR_ACTION = 0x10;
+
/**
* Returns the maximum keycode.
*/
@@ -439,6 +455,22 @@ public class KeyEvent implements Parcelable {
mFlags = flags;
}
+ /**
+ * Make an exact copy of an existing key event.
+ */
+ public KeyEvent(KeyEvent origEvent) {
+ mDownTime = origEvent.mDownTime;
+ mEventTime = origEvent.mEventTime;
+ mAction = origEvent.mAction;
+ mKeyCode = origEvent.mKeyCode;
+ mRepeatCount = origEvent.mRepeatCount;
+ mMetaState = origEvent.mMetaState;
+ mDeviceId = origEvent.mDeviceId;
+ mScancode = origEvent.mScancode;
+ mFlags = origEvent.mFlags;
+ mCharacters = origEvent.mCharacters;
+ }
+
/**
* Copy an existing key event, modifying its time and repeat count.
*
@@ -460,13 +492,27 @@ public class KeyEvent implements Parcelable {
mCharacters = origEvent.mCharacters;
}
+ /**
+ * Create a new key event that is the same as the given one, but whose
+ * event time and repeat count are replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param eventTime The new event time
+ * (in {@link android.os.SystemClock#uptimeMillis}) of the event.
+ * @param newRepeat The new repeat count of the event.
+ */
+ public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
+ int newRepeat) {
+ return new KeyEvent(event, eventTime, newRepeat);
+ }
+
/**
* Copy an existing key event, modifying its action.
*
* @param origEvent The existing event to be copied.
* @param action The new action code of the event.
*/
- public KeyEvent(KeyEvent origEvent, int action) {
+ private KeyEvent(KeyEvent origEvent, int action) {
mDownTime = origEvent.mDownTime;
mEventTime = origEvent.mEventTime;
mAction = action;
@@ -480,6 +526,30 @@ public class KeyEvent implements Parcelable {
// when changing the action.
}
+ /**
+ * Create a new key event that is the same as the given one, but whose
+ * action is replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param action The new action code of the event.
+ */
+ public static KeyEvent changeAction(KeyEvent event, int action) {
+ return new KeyEvent(event, action);
+ }
+
+ /**
+ * Create a new key event that is the same as the given one, but whose
+ * flags are replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param flags The new flags constant.
+ */
+ public static KeyEvent changeFlags(KeyEvent event, int flags) {
+ event = new KeyEvent(event);
+ event.mFlags = flags;
+ return event;
+ }
+
/**
* Don't use in new code, instead explicitly check
* {@link #getAction()}.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c3e00c40d941c..04447ca4719df 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3409,6 +3409,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
imm.focusOut(this);
}
+ if (mPendingCheckForLongPress != null) {
+ removeCallbacks(mPendingCheckForLongPress);
+ }
} else if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
imm.focusIn(this);
}
@@ -7656,7 +7659,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
private int mOriginalWindowAttachCount;
public void run() {
- if (isPressed() && (mParent != null) && hasWindowFocus()
+ if (isPressed() && (mParent != null)
&& mOriginalWindowAttachCount == mWindowAttachCount) {
if (performLongClick()) {
mHasPerformedLongPress = true;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 6ea7a82f7c92f..f604bc56a06e7 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -19,6 +19,7 @@ package android.view;
import android.util.Log;
import android.util.DisplayMetrics;
import android.content.res.Resources;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Environment;
@@ -800,7 +801,7 @@ public class ViewDebug {
View view = root.getRootView();
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
- dumpViewHierarchyWithProperties(group, out, 0);
+ dumpViewHierarchyWithProperties(group.getContext(), group, out, 0);
}
out.write("DONE.");
out.newLine();
@@ -838,9 +839,9 @@ public class ViewDebug {
return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
}
- private static void dumpViewHierarchyWithProperties(ViewGroup group,
+ private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group,
BufferedWriter out, int level) {
- if (!dumpViewWithProperties(group, out, level)) {
+ if (!dumpViewWithProperties(context, group, out, level)) {
return;
}
@@ -848,14 +849,16 @@ public class ViewDebug {
for (int i = 0; i < count; i++) {
final View view = group.getChildAt(i);
if (view instanceof ViewGroup) {
- dumpViewHierarchyWithProperties((ViewGroup) view, out, level + 1);
+ dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1);
} else {
- dumpViewWithProperties(view, out, level + 1);
+ dumpViewWithProperties(context, view, out, level + 1);
}
}
}
- private static boolean dumpViewWithProperties(View view, BufferedWriter out, int level) {
+ private static boolean dumpViewWithProperties(Context context, View view,
+ BufferedWriter out, int level) {
+
try {
for (int i = 0; i < level; i++) {
out.write(' ');
@@ -864,7 +867,7 @@ public class ViewDebug {
out.write('@');
out.write(Integer.toHexString(view.hashCode()));
out.write(' ');
- dumpViewProperties(view, out);
+ dumpViewProperties(context, view, out);
out.newLine();
} catch (IOException e) {
Log.w("View", "Error while dumping hierarchy tree");
@@ -945,23 +948,26 @@ public class ViewDebug {
return methods;
}
- private static void dumpViewProperties(Object view, BufferedWriter out) throws IOException {
- dumpViewProperties(view, out, "");
+ private static void dumpViewProperties(Context context, Object view,
+ BufferedWriter out) throws IOException {
+
+ dumpViewProperties(context, view, out, "");
}
- private static void dumpViewProperties(Object view, BufferedWriter out, String prefix)
- throws IOException {
+ private static void dumpViewProperties(Context context, Object view,
+ BufferedWriter out, String prefix) throws IOException {
+
Class> klass = view.getClass();
do {
- exportFields(view, out, klass, prefix);
- exportMethods(view, out, klass, prefix);
+ exportFields(context, view, out, klass, prefix);
+ exportMethods(context, view, out, klass, prefix);
klass = klass.getSuperclass();
} while (klass != Object.class);
}
- private static void exportMethods(Object view, BufferedWriter out, Class> klass,
- String prefix) throws IOException {
+ private static void exportMethods(Context context, Object view, BufferedWriter out,
+ Class> klass, String prefix) throws IOException {
final Method[] methods = getExportedPropertyMethods(klass);
@@ -976,9 +982,9 @@ public class ViewDebug {
if (returnType == int.class) {
final ExportedProperty property = sAnnotations.get(method);
- if (property.resolveId() && view instanceof View) {
+ if (property.resolveId() && context != null) {
final int id = (Integer) methodValue;
- methodValue = resolveId(view, id);
+ methodValue = resolveId(context, id);
} else {
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
@@ -1005,11 +1011,11 @@ public class ViewDebug {
final String valuePrefix = prefix + method.getName() + '_';
final String suffix = "()";
- exportUnrolledArray(view, out, property, array, valuePrefix, suffix);
+ exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
} else if (!returnType.isPrimitive()) {
final ExportedProperty property = sAnnotations.get(method);
if (property.deepExport()) {
- dumpViewProperties(methodValue, out, prefix + property.prefix());
+ dumpViewProperties(context, methodValue, out, prefix + property.prefix());
continue;
}
}
@@ -1021,8 +1027,9 @@ public class ViewDebug {
}
}
- private static void exportFields(Object view, BufferedWriter out, Class> klass, String prefix)
- throws IOException {
+ private static void exportFields(Context context, Object view, BufferedWriter out,
+ Class> klass, String prefix) throws IOException {
+
final Field[] fields = getExportedPropertyFields(klass);
int count = fields.length;
@@ -1036,9 +1043,9 @@ public class ViewDebug {
if (type == int.class) {
final ExportedProperty property = sAnnotations.get(field);
- if (property.resolveId() && view instanceof View) {
+ if (property.resolveId() && context != null) {
final int id = field.getInt(view);
- fieldValue = resolveId(view, id);
+ fieldValue = resolveId(context, id);
} else {
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
@@ -1063,14 +1070,15 @@ public class ViewDebug {
final String valuePrefix = prefix + field.getName() + '_';
final String suffix = "";
- exportUnrolledArray(view, out, property, array, valuePrefix, suffix);
+ exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
// We exit here!
return;
} else if (!type.isPrimitive()) {
final ExportedProperty property = sAnnotations.get(field);
if (property.deepExport()) {
- dumpViewProperties(field.get(view), out, prefix + property.prefix());
+ dumpViewProperties(context, field.get(view), out,
+ prefix + property.prefix());
continue;
}
}
@@ -1096,7 +1104,7 @@ public class ViewDebug {
out.write(' ');
}
- private static void exportUnrolledArray(Object view, BufferedWriter out,
+ private static void exportUnrolledArray(Context context, BufferedWriter out,
ExportedProperty property, int[] array, String prefix, String suffix)
throws IOException {
@@ -1106,7 +1114,7 @@ public class ViewDebug {
final IntToString[] mapping = property.mapping();
final boolean hasMapping = mapping.length > 0;
- final boolean resolveId = property.resolveId() && view instanceof View;
+ final boolean resolveId = property.resolveId() && context != null;
final int valuesCount = array.length;
for (int j = 0; j < valuesCount; j++) {
@@ -1140,16 +1148,16 @@ public class ViewDebug {
}
if (resolveId) {
- value = (String) resolveId(view, intValue);
+ value = (String) resolveId(context, intValue);
}
writeEntry(out, prefix, name, suffix, value);
}
}
- private static Object resolveId(Object view, int id) {
+ private static Object resolveId(Context context, int id) {
Object fieldValue;
- final Resources resources = ((View) view).getContext().getResources();
+ final Resources resources = context.getResources();
if (id >= 0) {
try {
fieldValue = resources.getResourceTypeName(id) + '/' +
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index dd2b154c7fbef..fbb4d42b18fb8 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -470,11 +470,20 @@ public final class ViewRoot extends Handler implements ViewParent,
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
+ int oldSoftInputMode = mWindowAttributes.softInputMode;
mWindowAttributes.copyFrom(attrs);
if (newView) {
mSoftInputMode = attrs.softInputMode;
requestLayout();
}
+ // Don't lose the mode we last auto-computed.
+ if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
+ mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
+ & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ | (oldSoftInputMode
+ & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
+ }
mWindowAttributesChanged = true;
scheduleTraversals();
}
@@ -1485,7 +1494,7 @@ public final class ViewRoot extends Handler implements ViewParent,
+ msg.obj + " to " + mView);
deliverKeyEvent((KeyEvent)msg.obj, true);
break;
- case DISPATCH_POINTER:
+ case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent)msg.obj;
boolean didFinish;
@@ -1571,7 +1580,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// Let the exception fall through -- the looper will catch
// it and take care of the bad app for us.
}
- break;
+ } break;
case DISPATCH_TRACKBALL:
deliverTrackballEvent((MotionEvent)msg.obj);
break;
@@ -1657,12 +1666,19 @@ public final class ViewRoot extends Handler implements ViewParent,
case DIE:
dispatchDetachedFromWindow();
break;
- case DISPATCH_KEY_FROM_IME:
+ case DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
"ViewRoot", "Dispatching key "
+ msg.obj + " from IME to " + mView);
+ KeyEvent event = (KeyEvent)msg.obj;
+ if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
+ // The IME is trying to say this event is from the
+ // system! Bad bad bad!
+ event = KeyEvent.changeFlags(event,
+ event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
+ }
deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
- break;
+ } break;
case FINISH_INPUT_CONNECTION: {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 47b52e4a9ad7e..4230afad7993c 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -18,7 +18,7 @@ package android.view;
import android.graphics.Rect;
-import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* A view tree observer is used to register listeners that can be notified of global
@@ -30,12 +30,12 @@ import java.util.ArrayList;
* for more information.
*/
public final class ViewTreeObserver {
- private ArrayList mOnGlobalFocusListeners;
- private ArrayList mOnGlobalLayoutListeners;
- private ArrayList mOnPreDrawListeners;
- private ArrayList mOnTouchModeChangeListeners;
- private ArrayList mOnComputeInternalInsetsListeners;
- private ArrayList mOnScrollChangedListeners;
+ private CopyOnWriteArrayList mOnGlobalFocusListeners;
+ private CopyOnWriteArrayList mOnGlobalLayoutListeners;
+ private CopyOnWriteArrayList mOnPreDrawListeners;
+ private CopyOnWriteArrayList mOnTouchModeChangeListeners;
+ private CopyOnWriteArrayList mOnComputeInternalInsetsListeners;
+ private CopyOnWriteArrayList mOnScrollChangedListeners;
private boolean mAlive = true;
@@ -283,7 +283,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalFocusListeners == null) {
- mOnGlobalFocusListeners = new ArrayList();
+ mOnGlobalFocusListeners = new CopyOnWriteArrayList();
}
mOnGlobalFocusListeners.add(listener);
@@ -318,7 +318,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalLayoutListeners == null) {
- mOnGlobalLayoutListeners = new ArrayList();
+ mOnGlobalLayoutListeners = new CopyOnWriteArrayList();
}
mOnGlobalLayoutListeners.add(listener);
@@ -352,7 +352,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnPreDrawListeners == null) {
- mOnPreDrawListeners = new ArrayList();
+ mOnPreDrawListeners = new CopyOnWriteArrayList();
}
mOnPreDrawListeners.add(listener);
@@ -388,7 +388,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnScrollChangedListeners == null) {
- mOnScrollChangedListeners = new ArrayList();
+ mOnScrollChangedListeners = new CopyOnWriteArrayList();
}
mOnScrollChangedListeners.add(listener);
@@ -424,7 +424,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnTouchModeChangeListeners == null) {
- mOnTouchModeChangeListeners = new ArrayList();
+ mOnTouchModeChangeListeners = new CopyOnWriteArrayList();
}
mOnTouchModeChangeListeners.add(listener);
@@ -460,7 +460,8 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnComputeInternalInsetsListeners == null) {
- mOnComputeInternalInsetsListeners = new ArrayList();
+ mOnComputeInternalInsetsListeners =
+ new CopyOnWriteArrayList();
}
mOnComputeInternalInsetsListeners.add(listener);
@@ -518,11 +519,14 @@ public final class ViewTreeObserver {
* Notifies registered listeners that focus has changed.
*/
final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
- final ArrayList globaFocusListeners = mOnGlobalFocusListeners;
- if (globaFocusListeners != null) {
- final int count = globaFocusListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- globaFocusListeners.get(i).onGlobalFocusChanged(oldFocus, newFocus);
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList listeners = mOnGlobalFocusListeners;
+ if (listeners != null) {
+ for (OnGlobalFocusChangeListener listener : listeners) {
+ listener.onGlobalFocusChanged(oldFocus, newFocus);
}
}
}
@@ -533,11 +537,14 @@ public final class ViewTreeObserver {
* not attached to a Window or in the GONE state.
*/
public final void dispatchOnGlobalLayout() {
- final ArrayList globaLayoutListeners = mOnGlobalLayoutListeners;
- if (globaLayoutListeners != null) {
- final int count = globaLayoutListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- globaLayoutListeners.get(i).onGlobalLayout();
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList listeners = mOnGlobalLayoutListeners;
+ if (listeners != null) {
+ for (OnGlobalLayoutListener listener : listeners) {
+ listener.onGlobalLayout();
}
}
}
@@ -551,12 +558,15 @@ public final class ViewTreeObserver {
* @return True if the current draw should be canceled and resceduled, false otherwise.
*/
public final boolean dispatchOnPreDraw() {
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
boolean cancelDraw = false;
- final ArrayList preDrawListeners = mOnPreDrawListeners;
- if (preDrawListeners != null) {
- final int count = preDrawListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- cancelDraw |= !preDrawListeners.get(i).onPreDraw();
+ final CopyOnWriteArrayList listeners = mOnPreDrawListeners;
+ if (listeners != null) {
+ for (OnPreDrawListener listener : listeners) {
+ cancelDraw |= !listener.onPreDraw();
}
}
return cancelDraw;
@@ -568,11 +578,15 @@ public final class ViewTreeObserver {
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
*/
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
- final ArrayList touchModeListeners = mOnTouchModeChangeListeners;
- if (touchModeListeners != null) {
- final int count = touchModeListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- touchModeListeners.get(i).onTouchModeChanged(inTouchMode);
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList listeners =
+ mOnTouchModeChangeListeners;
+ if (listeners != null) {
+ for (OnTouchModeChangeListener listener : listeners) {
+ listener.onTouchModeChanged(inTouchMode);
}
}
}
@@ -581,11 +595,14 @@ public final class ViewTreeObserver {
* Notifies registered listeners that something has scrolled.
*/
final void dispatchOnScrollChanged() {
- final ArrayList listeners = mOnScrollChangedListeners;
-
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList listeners = mOnScrollChangedListeners;
if (listeners != null) {
- for (OnScrollChangedListener scl : mOnScrollChangedListeners) {
- scl.onScrollChanged();
+ for (OnScrollChangedListener listener : listeners) {
+ listener.onScrollChanged();
}
}
}
@@ -594,7 +611,8 @@ public final class ViewTreeObserver {
* Returns whether there are listeners for computing internal insets.
*/
final boolean hasComputeInternalInsetsListeners() {
- final ArrayList listeners = mOnComputeInternalInsetsListeners;
+ final CopyOnWriteArrayList listeners =
+ mOnComputeInternalInsetsListeners;
return (listeners != null && listeners.size() > 0);
}
@@ -602,11 +620,15 @@ public final class ViewTreeObserver {
* Calls all listeners to compute the current insets.
*/
final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
- final ArrayList listeners = mOnComputeInternalInsetsListeners;
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList listeners =
+ mOnComputeInternalInsetsListeners;
if (listeners != null) {
- final int count = listeners.size();
- for (int i = count - 1; i >= 0; i--) {
- listeners.get(i).onComputeInternalInsets(inoutInfo);
+ for (OnComputeInternalInsetsListener listener : listeners) {
+ listener.onComputeInternalInsets(inoutInfo);
}
}
}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index b00e565956175..c718bac297761 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -77,13 +77,38 @@ public class EditorInfo implements InputType, Parcelable {
*/
public static final int IME_ACTION_DONE = 0x00000006;
+ /**
+ * Flag of {@link #imeOptions}: used to specify that the IME does not need
+ * to show its extracted text UI. For input methods that may be fullscreen,
+ * often when in landscape mode, this allows them to be smaller and let part
+ * of the application be shown behind. Though there will likely be limited
+ * access to the application available from the user, it can make the
+ * experience of a (mostly) fullscreen IME less jarring. Note that when
+ * this flag is specified the IME may not be set up to be able
+ * to display text, so it should only be used in situations where this is
+ * not needed.
+ */
+ public static final int IME_FLAG_NO_EXTRACT_UI = 0x10000000;
+
/**
* Flag of {@link #imeOptions}: used in conjunction with
* {@link #IME_MASK_ACTION}, this indicates that the action should not
- * be available in-line as the same as a "enter" key. Typically this is
+ * be available as an accessory button when the input method is full-screen.
+ * Note that by setting this flag, there can be cases where the action
+ * is simply never available to the user. Setting this generally means
+ * that you think showing text being edited is more important than the
+ * action you have supplied.
+ */
+ public static final int IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000;
+
+ /**
+ * Flag of {@link #imeOptions}: used in conjunction with
+ * {@link #IME_MASK_ACTION}, this indicates that the action should not
+ * be available in-line as a replacement for "enter" key. Typically this is
* because the action has such a significant impact or is not recoverable
* enough that accidentally hitting it should be avoided, such as sending
- * a message.
+ * a message. Note that {@link android.widget.TextView} will automatically set this
+ * flag for you on multi-line text views.
*/
public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index dcf68cd9353f3..4528b73aa7889 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -282,9 +282,7 @@ public final class CacheManager {
CacheResult result = mDataBase.getCache(url);
if (result != null) {
if (result.contentLength == 0) {
- if (result.httpStatusCode != 301
- && result.httpStatusCode != 302
- && result.httpStatusCode != 307) {
+ if (!checkCacheRedirect(result.httpStatusCode)) {
// this should not happen. If it does, remove it.
mDataBase.removeCache(url);
return null;
@@ -350,6 +348,17 @@ public final class CacheManager {
return null;
}
+ // according to the rfc 2616, the 303 response MUST NOT be cached.
+ if (statusCode == 303) {
+ return null;
+ }
+
+ // like the other browsers, do not cache redirects containing a cookie
+ // header.
+ if (checkCacheRedirect(statusCode) && !headers.getSetCookie().isEmpty()) {
+ return null;
+ }
+
CacheResult ret = parseHeaders(statusCode, headers, mimeType);
if (ret != null) {
setupFiles(url, ret);
@@ -395,9 +404,7 @@ public final class CacheManager {
}
cacheRet.contentLength = cacheRet.outFile.length();
- if (cacheRet.httpStatusCode == 301
- || cacheRet.httpStatusCode == 302
- || cacheRet.httpStatusCode == 307) {
+ if (checkCacheRedirect(cacheRet.httpStatusCode)) {
// location is in database, no need to keep the file
cacheRet.contentLength = 0;
cacheRet.localPath = new String();
@@ -471,6 +478,15 @@ public final class CacheManager {
}
}
+ private static boolean checkCacheRedirect(int statusCode) {
+ if (statusCode == 301 || statusCode == 302 || statusCode == 307) {
+ // as 303 can't be cached, we do not return true
+ return true;
+ } else {
+ return false;
+ }
+ }
+
@SuppressWarnings("deprecation")
private static void setupFiles(String url, CacheResult cacheRet) {
if (true) {
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index 48b9eec2818c2..84dc9f0ae0e81 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -80,8 +80,7 @@ public class HttpAuthHandler extends Handler {
break;
case AUTH_CANCEL:
-
- mNetwork.resetHandlersAndStopLoading(loader.getFrame());
+ loader.handleAuthResponse(null, null);
break;
}
@@ -125,24 +124,6 @@ public class HttpAuthHandler extends Handler {
return false;
}
- /**
- * Resets the HTTP-authentication request handler, removes
- * all loaders that share the same BrowserFrame
- *
- * @param frame The browser frame
- */
- /* package */ void reset(BrowserFrame frame) {
- synchronized (mLoaderQueue) {
- ListIterator i = mLoaderQueue.listIterator(0);
- while (i.hasNext()) {
- LoadListener loader = i.next();
- if (frame == loader.getFrame()) {
- i.remove();
- }
- }
- }
- }
-
/**
* Enqueues the loader, if the loader is the only element
* in the queue, starts processing the loader
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index f9fb0b0fccaae..c64200cd5b2a1 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -377,10 +377,6 @@ class LoadListener extends Handler implements EventHandler {
}
}
- // if there is buffered data, commit them in the end
- boolean needToCommit = mAuthHeader != null && !mustAuthenticate
- && mNativeLoader != 0 && !mDataBuilder.isEmpty();
-
// it is only here that we can reset the last mAuthHeader object
// (if existed) and start a new one!!!
mAuthHeader = null;
@@ -415,10 +411,6 @@ class LoadListener extends Handler implements EventHandler {
}
}
commitHeadersCheckRedirect();
-
- if (needToCommit) {
- commitLoad();
- }
}
/**
@@ -452,6 +444,8 @@ class LoadListener extends Handler implements EventHandler {
status.put("minor", minorVersion);
status.put("code", code);
status.put("reason", reasonPhrase);
+ // New status means new data. Clear the old.
+ mDataBuilder.clear();
sendMessageInternal(obtainMessage(MSG_STATUS, status));
}
@@ -613,7 +607,6 @@ class LoadListener extends Handler implements EventHandler {
// ask for it, so make sure we have a valid CacheLoader
// before calling it.
if (mCacheLoader != null) {
- detachRequestHandle();
mCacheLoader.load();
if (Config.LOGV) {
Log.v(LOGTAG, "LoadListener cache load url=" + url());
@@ -738,10 +731,16 @@ class LoadListener extends Handler implements EventHandler {
if (mRequestHandle != null) {
mRequestHandle.handleSslErrorResponse(proceed);
}
+ if (!proceed) {
+ // Commit whatever data we have and tear down the loader.
+ commitLoad();
+ tearDown();
+ }
}
/**
- * Uses user-supplied credentials to restar a request.
+ * Uses user-supplied credentials to restart a request. If the credentials
+ * are null, cancel the request.
*/
void handleAuthResponse(String username, String password) {
if (Config.LOGV) {
@@ -780,6 +779,10 @@ class LoadListener extends Handler implements EventHandler {
}
}
}
+ } else {
+ // Commit whatever data we have and tear down the loader.
+ commitLoad();
+ tearDown();
}
}
@@ -944,13 +947,12 @@ class LoadListener extends Handler implements EventHandler {
* @return native response pointer
*/
private int createNativeResponse() {
- // The reason we change HTTP_NOT_MODIFIED to HTTP_OK is because we know
- // that WebCore never sends the if-modified-since header. Our
- // CacheManager does it for us. If the server responds with a 304, then
- // we treat it like it was a 200 code and proceed with loading the file
- // from the cache.
- int statusCode = mStatusCode == HTTP_NOT_MODIFIED
- ? HTTP_OK : mStatusCode;
+ // If WebCore sends if-modified-since, mCacheLoader is null. If
+ // CacheManager sends it, mCacheLoader is not null. In this case, if the
+ // server responds with a 304, then we treat it like it was a 200 code
+ // and proceed with loading the file from the cache.
+ int statusCode = (mStatusCode == HTTP_NOT_MODIFIED &&
+ mCacheLoader != null) ? HTTP_OK : mStatusCode;
// pass content-type content-length and content-encoding
final int nativeResponse = nativeCreateResponse(
mUrl, statusCode, mStatusText,
@@ -1181,8 +1183,6 @@ class LoadListener extends Handler implements EventHandler {
// sync. Add 1 to account for the current redirect.
mCacheRedirectCount = mRequestHandle.getRedirectCount() + 1;
}
- // Clear the buffered data since the redirect is valid.
- mDataBuilder.clear();
} else {
commitHeaders();
commitLoad();
@@ -1197,9 +1197,10 @@ class LoadListener extends Handler implements EventHandler {
/**
* Parses the content-type header.
+ * The first part only allows '-' if it follows x or X.
*/
private static final Pattern CONTENT_TYPE_PATTERN =
- Pattern.compile("^([a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
+ Pattern.compile("^((?:[xX]-)?[a-zA-Z\\*]+/[\\w\\+\\*-]+[\\.[\\w\\+-]+]*)$");
private void parseContentTypeHeader(String contentType) {
if (Config.LOGV) {
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index c9cc20817c4fd..85c2275df9916 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -496,6 +496,7 @@ public /* package */ class MimeTypeMap {
sMimeTypeMap.loadEntry("video/x-msvideo", "avi", false);
sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie", false);
sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice", false);
+ sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx", false);
}
return sMimeTypeMap;
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 74622b3b3883e..6fa07753dea33 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -260,24 +260,6 @@ class Network {
mProxyPassword = proxyPassword;
}
- /**
- * If we need to stop loading done in a handler (here, browser frame), we
- * send a message to the handler to stop loading, and remove all loaders
- * that share the same CallbackProxy in question from all local
- * handlers (such as ssl-error and http-authentication handler).
- * @param proxy The CallbackProxy responsible for cancelling the current
- * load.
- */
- public void resetHandlersAndStopLoading(BrowserFrame frame) {
- if (Config.LOGV) {
- Log.v(LOGTAG, "Network.resetHandlersAndStopLoading()");
- }
-
- frame.stopLoading();
- mSslErrorHandler.reset(frame);
- mHttpAuthHandler.reset(frame);
- }
-
/**
* Saves the state of network handlers (user SSL and HTTP-authentication
* preferences).
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 115434a98d032..2e2fa12052abb 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -117,20 +117,6 @@ public class SslErrorHandler extends Handler {
mSslPrefTable.clear();
}
- /**
- * Resets the SSL error handler, removes all loaders that
- * share the same BrowserFrame.
- */
- /* package */ synchronized void reset(BrowserFrame frame) {
- ListIterator i = mLoaderQueue.listIterator(0);
- while (i.hasNext()) {
- LoadListener loader = i.next();
- if (frame == loader.getFrame()) {
- i.remove();
- }
- }
- }
-
/**
* Handles SSL error(s) on the way up to the user.
*/
@@ -244,12 +230,8 @@ public class SslErrorHandler extends Handler {
primary > mSslPrefTable.getInt(host)) {
mSslPrefTable.putInt(host, new Integer(primary));
}
-
- loader.handleSslErrorResponse(proceed);
- } else {
- loader.handleSslErrorResponse(proceed);
- mNetwork.resetHandlersAndStopLoading(loader.getFrame());
}
+ loader.handleSslErrorResponse(proceed);
}
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 65544d450f368..025e6bb819cca 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -153,6 +153,7 @@ public class WebSettings {
private boolean mNeedInitialFocus = true;
private boolean mNavDump = false;
private boolean mSupportZoom = true;
+ private boolean mBuiltInZoomControls = false;
private boolean mAllowFileAccess = true;
// Class to handle messages before WebCore is ready.
@@ -363,6 +364,20 @@ public class WebSettings {
return mSupportZoom;
}
+ /**
+ * Sets whether the zoom mechanism built into WebView is used.
+ */
+ public void setBuiltInZoomControls(boolean enabled) {
+ mBuiltInZoomControls = enabled;
+ }
+
+ /**
+ * Returns true if the zoom mechanism built into WebView is being used.
+ */
+ public boolean getBuiltInZoomControls() {
+ return mBuiltInZoomControls;
+ }
+
/**
* Enable or disable file access within WebView. File access is enabled by
* default.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 753267fd737a9..3205820361c3d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -56,17 +56,20 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
+import android.view.animation.AlphaAnimation;
import android.view.inputmethod.InputMethodManager;
import android.webkit.TextDialog.AutoCompleteAdapter;
import android.webkit.WebViewCore.EventHub;
import android.widget.AbsoluteLayout;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Scroller;
import android.widget.Toast;
import android.widget.ZoomButtonsController;
+import android.widget.ZoomControls;
import android.widget.AdapterView.OnItemClickListener;
import java.io.File;
@@ -85,6 +88,9 @@ import java.util.List;
* It uses the WebKit rendering engine to display
* web pages and includes methods to navigate forward and backward
* through a history, zoom in and out, perform text searches and more.
+ * To enable the built-in zoom, set
+ * {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
+ * (introduced in API version 3).
*
Note that, in order for your Activity to access the Internet and load web pages
* in a WebView, you must add the INTERNET permissions to your
* Android Manifest file:
@@ -106,6 +112,57 @@ public class WebView extends AbsoluteLayout
static final boolean DEBUG = false;
static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
+ private class ExtendedZoomControls extends FrameLayout {
+ public ExtendedZoomControls(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ LayoutInflater inflater = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
+ mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls);
+ mZoomMagnify = (ImageView) findViewById(com.android.internal.R.id.zoomMagnify);
+ }
+
+ public void show(boolean showZoom, boolean canZoomOut) {
+ mZoomControls.setVisibility(showZoom ? View.VISIBLE : View.GONE);
+ mZoomMagnify.setVisibility(canZoomOut ? View.VISIBLE : View.GONE);
+ fade(View.VISIBLE, 0.0f, 1.0f);
+ }
+
+ public void hide() {
+ fade(View.GONE, 1.0f, 0.0f);
+ }
+
+ private void fade(int visibility, float startAlpha, float endAlpha) {
+ AlphaAnimation anim = new AlphaAnimation(startAlpha, endAlpha);
+ anim.setDuration(500);
+ startAnimation(anim);
+ setVisibility(visibility);
+ }
+
+ public void setIsZoomMagnifyEnabled(boolean isEnabled) {
+ mZoomMagnify.setEnabled(isEnabled);
+ }
+
+ public boolean hasFocus() {
+ return mZoomControls.hasFocus() || mZoomMagnify.hasFocus();
+ }
+
+ public void setOnZoomInClickListener(OnClickListener listener) {
+ mZoomControls.setOnZoomInClickListener(listener);
+ }
+
+ public void setOnZoomOutClickListener(OnClickListener listener) {
+ mZoomControls.setOnZoomOutClickListener(listener);
+ }
+
+ public void setOnZoomMagnifyClickListener(OnClickListener listener) {
+ mZoomMagnify.setOnClickListener(listener);
+ }
+
+ ZoomControls mZoomControls;
+ ImageView mZoomMagnify;
+ }
+
/**
* Transportation object for returning WebView across thread boundaries.
*/
@@ -232,6 +289,9 @@ public class WebView extends AbsoluteLayout
private static final int LONG_PRESS_TIMEOUT = 1000;
// needed to avoid flinging after a pause of no movement
private static final int MIN_FLING_TIME = 250;
+ // The time that the Zoom Controls are visible before fading away
+ private static final long ZOOM_CONTROLS_TIMEOUT =
+ ViewConfiguration.getZoomControlsTimeout();
// The amount of content to overlap between two screens when going through
// pages with the space bar, in pixels.
private static final int PAGE_SCROLL_OVERLAP = 24;
@@ -472,6 +532,10 @@ public class WebView extends AbsoluteLayout
}
}
+ // The View containing the zoom controls
+ private ExtendedZoomControls mZoomControls;
+ private Runnable mZoomControlRunnable;
+
private ZoomButtonsController mZoomButtonsController;
private ImageView mZoomOverviewButton;
private ImageView mZoomFitPageButton;
@@ -484,11 +548,6 @@ public class WebView extends AbsoluteLayout
private ZoomButtonsController.OnZoomListener mZoomListener =
new ZoomButtonsController.OnZoomListener() {
- public void onCenter(int x, int y) {
- // Don't translate when the control is invoked, hence we do nothing
- // in this callback
- }
-
public void onVisibilityChanged(boolean visible) {
if (visible) {
switchOutDrawHistory();
@@ -582,10 +641,26 @@ public class WebView extends AbsoluteLayout
}
private void updateZoomButtonsEnabled() {
- mZoomButtonsController.setZoomInEnabled(mActualScale < mMaxZoomScale);
- mZoomButtonsController.setZoomOutEnabled(mActualScale > mMinZoomScale);
- mZoomFitPageButton.setEnabled(mActualScale != 1);
- mZoomOverviewButton.setEnabled(canZoomScrollOut());
+ boolean canZoomIn = mActualScale < mMaxZoomScale;
+ boolean canZoomOut = mActualScale > mMinZoomScale;
+ if (!canZoomIn && !canZoomOut) {
+ // Hide the zoom in and out buttons, as well as the fit to page
+ // button, if the page cannot zoom
+ mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
+ mZoomFitPageButton.setVisibility(View.GONE);
+ } else {
+ // Bring back the hidden zoom controls.
+ mZoomButtonsController.getZoomControls()
+ .setVisibility(View.VISIBLE);
+ mZoomFitPageButton.setVisibility(View.VISIBLE);
+ // Set each one individually, as a page may be able to zoom in
+ // or out.
+ mZoomButtonsController.setZoomInEnabled(canZoomIn);
+ mZoomButtonsController.setZoomOutEnabled(canZoomOut);
+ mZoomFitPageButton.setEnabled(mActualScale != 1);
+ }
+ mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE:
+ View.GONE);
}
private void init() {
@@ -1332,7 +1407,13 @@ public class WebView extends AbsoluteLayout
return;
}
clearTextEntry();
- mZoomButtonsController.setVisible(true);
+ if (getSettings().getBuiltInZoomControls()) {
+ mZoomButtonsController.setVisible(true);
+ } else {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ }
}
/**
@@ -2535,8 +2616,17 @@ public class WebView extends AbsoluteLayout
private void startZoomScrollOut() {
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
- if (mZoomButtonsController.isVisible()) {
- mZoomButtonsController.setVisible(false);
+ if (getSettings().getBuiltInZoomControls()) {
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
+ }
+ } else {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
}
int width = getViewWidth();
int height = getViewHeight();
@@ -3206,7 +3296,6 @@ public class WebView extends AbsoluteLayout
// Clean up the zoom controller
mZoomButtonsController.setVisible(false);
- ZoomButtonsController.finishZoomTutorial(mContext, false);
}
// Implementation for OnHierarchyChangeListener
@@ -3255,7 +3344,7 @@ public class WebView extends AbsoluteLayout
// false for the first parameter
}
} else {
- if (!mZoomButtonsController.isVisible()) {
+ if (getSettings().getBuiltInZoomControls() && !mZoomButtonsController.isVisible()) {
/*
* The zoom controls come in their own window, so our window
* loses focus. Our policy is to not draw the focus ring if
@@ -3527,7 +3616,9 @@ public class WebView extends AbsoluteLayout
mWebViewCore
.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
}
- if (getSettings().supportZoom()
+ WebSettings settings = getSettings();
+ if (settings.supportZoom()
+ && settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
&& (canZoomScrollOut() ||
mMinZoomScale < mMaxZoomScale)) {
@@ -3594,6 +3685,21 @@ public class WebView extends AbsoluteLayout
mLastTouchTime = eventTime;
mUserScroll = true;
}
+
+ if (!getSettings().getBuiltInZoomControls()) {
+ boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
+ boolean showMagnify = canZoomScrollOut();
+ if (mZoomControls != null && (showPlusMinus || showMagnify)) {
+ if (mZoomControls.getVisibility() == View.VISIBLE) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ } else {
+ mZoomControls.show(showPlusMinus, showMagnify);
+ }
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ }
+ }
+
if (done) {
// return false to indicate that we can't pan out of the
// view space
@@ -4050,18 +4156,83 @@ public class WebView extends AbsoluteLayout
}
}
- // TODO: deprecate
/**
* Returns a view containing zoom controls i.e. +/- buttons. The caller is
* in charge of installing this view to the view hierarchy. This view will
* become visible when the user starts scrolling via touch and fade away if
* the user does not interact with it.
*
- * From 1.5, WebView change to use ZoomButtonsController. This will return
- * an invisible dummy view for backwards compatibility.
+ * API version 3 introduces a built-in zoom mechanism that is shown
+ * automatically by the MapView. This is the preferred approach for
+ * showing the zoom UI.
+ *
+ * @deprecated The built-in zoom mechanism is preferred, see
+ * {@link WebSettings#setBuiltInZoomControls(boolean)}.
*/
+ @Deprecated
public View getZoomControls() {
- return mZoomButtonsController.getDummyZoomControls();
+ if (!getSettings().supportZoom()) {
+ Log.w(LOGTAG, "This WebView doesn't support zoom.");
+ return null;
+ }
+ if (mZoomControls == null) {
+ mZoomControls = createZoomControls();
+
+ /*
+ * need to be set to VISIBLE first so that getMeasuredHeight() in
+ * {@link #onSizeChanged()} can return the measured value for proper
+ * layout.
+ */
+ mZoomControls.setVisibility(View.VISIBLE);
+ mZoomControlRunnable = new Runnable() {
+ public void run() {
+
+ /* Don't dismiss the controls if the user has
+ * focus on them. Wait and check again later.
+ */
+ if (!mZoomControls.hasFocus()) {
+ mZoomControls.hide();
+ } else {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ }
+ }
+ };
+ }
+ return mZoomControls;
+ }
+
+ private ExtendedZoomControls createZoomControls() {
+ ExtendedZoomControls zoomControls = new ExtendedZoomControls(mContext
+ , null);
+ zoomControls.setOnZoomInClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ // reset time out
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ zoomIn();
+ }
+ });
+ zoomControls.setOnZoomOutClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ // reset time out
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ zoomOut();
+ }
+ });
+ zoomControls.setOnZoomMagnifyClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ mPrivateHandler.postDelayed(mZoomControlRunnable,
+ ZOOM_CONTROLS_TIMEOUT);
+ zoomScrollOut();
+ }
+ });
+ return zoomControls;
}
/**
@@ -4070,7 +4241,7 @@ public class WebView extends AbsoluteLayout
*
* @return The instance of {@link ZoomButtonsController} used by this class,
* or null if it is unavailable.
- * @hide pending API council
+ * @hide
*/
public ZoomButtonsController getZoomButtonsController() {
return mZoomButtonsController;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index bd4bba8f57bff..965d900f32ac6 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -905,10 +905,7 @@ public abstract class AbsListView extends AdapterView implements Te
((Filterable) getAdapter()).getFilter() == null) {
return false;
}
- final Context context = mContext;
- final InputMethodManager inputManager = (InputMethodManager)
- context.getSystemService(Context.INPUT_METHOD_SERVICE);
- return !inputManager.isFullscreenMode();
+ return true;
}
/**
@@ -2904,7 +2901,7 @@ public abstract class AbsListView extends AdapterView implements Te
KeyEvent forwardEvent = event;
if (forwardEvent.getRepeatCount() > 0) {
- forwardEvent = new KeyEvent(event, event.getEventTime(), 0);
+ forwardEvent = KeyEvent.changeTimeRepeat(event, event.getEventTime(), 0);
}
int action = event.getAction();
@@ -2967,6 +2964,7 @@ public abstract class AbsListView extends AdapterView implements Te
// want to figure out why this is.
mTextFilter.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_VARIATION_FILTER);
+ mTextFilter.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
mTextFilter.addTextChangedListener(this);
p.setFocusable(false);
p.setTouchable(false);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 1d553f1d2b297..04cb8a0159442 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -164,7 +164,7 @@ public abstract class AbsSeekBar extends ProgressBar {
void onProgressRefresh(float scale, boolean fromUser) {
Drawable thumb = mThumb;
if (thumb != null) {
- setThumbPos(getWidth(), getHeight(), thumb, scale, Integer.MIN_VALUE);
+ setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
/*
* Since we draw translated, the drawable's bounds that it signals
* for invalidation won't be the actual bounds we want invalidated,
@@ -189,7 +189,7 @@ public abstract class AbsSeekBar extends ProgressBar {
if (thumbHeight > trackHeight) {
if (thumb != null) {
- setThumbPos(w, h, thumb, scale, 0);
+ setThumbPos(w, thumb, scale, 0);
}
int gapForCenteringTrack = (thumbHeight - trackHeight) / 2;
if (d != null) {
@@ -206,16 +206,15 @@ public abstract class AbsSeekBar extends ProgressBar {
}
int gap = (trackHeight - thumbHeight) / 2;
if (thumb != null) {
- setThumbPos(w, h, thumb, scale, gap);
+ setThumbPos(w, thumb, scale, gap);
}
}
}
/**
* @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and
- * the old vertical bounds will be used.
*/
- private void setThumbPos(int w, int h, Drawable thumb, float scale, int gap) {
+ private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
int available = w - mPaddingLeft - mPaddingRight;
int thumbWidth = thumb.getIntrinsicWidth();
int thumbHeight = thumb.getIntrinsicHeight();
@@ -353,6 +352,12 @@ public abstract class AbsSeekBar extends ProgressBar {
void onStopTrackingTouch() {
}
+ /**
+ * Called when the user changes the seekbar's progress by using a key event.
+ */
+ void onKeyChange() {
+ }
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
int progress = getProgress();
@@ -361,11 +366,13 @@ public abstract class AbsSeekBar extends ProgressBar {
case KeyEvent.KEYCODE_DPAD_LEFT:
if (progress <= 0) break;
setProgress(progress - mKeyProgressIncrement, true);
+ onKeyChange();
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (progress >= getMax()) break;
setProgress(progress + mKeyProgressIncrement, true);
+ onKeyChange();
return true;
}
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 8aafee2118f9c..2bb716cbf1510 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -56,6 +56,7 @@ public class FrameLayout extends ViewGroup {
private final Rect mSelfBounds = new Rect();
private final Rect mOverlayBounds = new Rect();
private int mForegroundGravity = Gravity.FILL;
+ private boolean mForegroundInPadding = true;
public FrameLayout(Context context) {
super(context);
@@ -71,6 +72,9 @@ public class FrameLayout extends ViewGroup {
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout,
defStyle, 0);
+ mForegroundGravity = a.getInt(
+ com.android.internal.R.styleable.FrameLayout_foregroundGravity, mForegroundGravity);
+
final Drawable d = a.getDrawable(com.android.internal.R.styleable.FrameLayout_foreground);
if (d != null) {
setForeground(d);
@@ -80,8 +84,8 @@ public class FrameLayout extends ViewGroup {
setMeasureAllChildren(true);
}
- mForegroundGravity = a.getInt(com.android.internal.R.styleable.FrameLayout_foregroundGravity,
- mForegroundGravity);
+ mForegroundInPadding = a.getBoolean(
+ com.android.internal.R.styleable.FrameLayout_foregroundInsidePadding, true);
a.recycle();
}
@@ -105,6 +109,23 @@ public class FrameLayout extends ViewGroup {
}
mForegroundGravity = foregroundGravity;
+
+
+ if (mForegroundGravity == Gravity.FILL && mForeground != null) {
+ Rect padding = new Rect();
+ if (mForeground.getPadding(padding)) {
+ mForegroundPaddingLeft = padding.left;
+ mForegroundPaddingTop = padding.top;
+ mForegroundPaddingRight = padding.right;
+ mForegroundPaddingBottom = padding.bottom;
+ }
+ } else {
+ mForegroundPaddingLeft = 0;
+ mForegroundPaddingTop = 0;
+ mForegroundPaddingRight = 0;
+ mForegroundPaddingBottom = 0;
+ }
+
requestLayout();
}
}
@@ -167,12 +188,14 @@ public class FrameLayout extends ViewGroup {
if (drawable.isStateful()) {
drawable.setState(getDrawableState());
}
- Rect padding = new Rect();
- if (drawable.getPadding(padding)) {
- mForegroundPaddingLeft = padding.left;
- mForegroundPaddingTop = padding.top;
- mForegroundPaddingRight = padding.right;
- mForegroundPaddingBottom = padding.bottom;
+ if (mForegroundGravity == Gravity.FILL) {
+ Rect padding = new Rect();
+ if (drawable.getPadding(padding)) {
+ mForegroundPaddingLeft = padding.left;
+ mForegroundPaddingTop = padding.top;
+ mForegroundPaddingRight = padding.right;
+ mForegroundPaddingBottom = padding.bottom;
+ }
}
} else {
setWillNotDraw(true);
@@ -309,10 +332,14 @@ public class FrameLayout extends ViewGroup {
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
- selfBounds.set(0, 0, w, h);
+ if (mForegroundInPadding) {
+ selfBounds.set(0, 0, w, h);
+ } else {
+ selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
+ }
+
Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
-
foreground.setBounds(overlayBounds);
}
}
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 227fb9571d2f7..a2ec83fb49341 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -405,6 +405,8 @@ public class MediaController extends FrameLayout {
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
hide();
+
+ return true;
} else {
show(sDefaultTimeout);
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index a4f729f6f6eb4..f864690b60f82 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1125,17 +1125,16 @@ public class PopupWindow {
}
/**
- * Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.
+ * Updates the position and the dimension of the popup window. Calling this
+ * function also updates the window with the current popup state as described
+ * for {@link #update()}.
*
* @param anchor the popup's anchor view
* @param width the new width, can be -1 to ignore
* @param height the new height, can be -1 to ignore
*/
public void update(View anchor, int width, int height) {
- update(anchor, 0, 0, width, height);
+ update(anchor, false, 0, 0, true, width, height);
}
/**
@@ -1153,31 +1152,44 @@ public class PopupWindow {
* @param height the new height, can be -1 to ignore
*/
public void update(View anchor, int xoff, int yoff, int width, int height) {
+ update(anchor, true, xoff, yoff, true, width, height);
+ }
+
+ private void update(View anchor, boolean updateLocation, int xoff, int yoff,
+ boolean updateDimension, int width, int height) {
+
if (!isShowing() || mContentView == null) {
return;
}
WeakReference oldAnchor = mAnchor;
if (oldAnchor == null || oldAnchor.get() != anchor ||
- mAnchorXoff != xoff || mAnchorYoff != yoff) {
+ (updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff))) {
registerForScrollChanged(anchor, xoff, yoff);
}
WindowManager.LayoutParams p = (WindowManager.LayoutParams)
mPopupView.getLayoutParams();
- if (width == -1) {
- width = mPopupWidth;
- } else {
- mPopupWidth = width;
+ if (updateDimension) {
+ if (width == -1) {
+ width = mPopupWidth;
+ } else {
+ mPopupWidth = width;
+ }
+ if (height == -1) {
+ height = mPopupHeight;
+ } else {
+ mPopupHeight = height;
+ }
}
- if (height == -1) {
- height = mPopupHeight;
+
+ if (updateLocation) {
+ mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
} else {
- mPopupHeight = height;
+ mAboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff);
}
-
- mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
+
update(p.x, p.y, width, height);
}
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index ad5ca07125a45..1800c5a01b9a8 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -296,7 +296,13 @@ public class RatingBar extends AbsSeekBar {
dispatchRatingChange(true);
}
}
-
+
+ @Override
+ void onKeyChange() {
+ super.onKeyChange();
+ dispatchRatingChange(true);
+ }
+
void dispatchRatingChange(boolean fromUser) {
if (mOnRatingBarChangeListener != null) {
mOnRatingBarChangeListener.onRatingChanged(this, getRating(),
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 52c421c7dd945..c4f0abdd85a6e 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -821,7 +821,10 @@ public class RelativeLayout extends ViewGroup {
@ViewDebug.IntToString(from = CENTER_VERTICAL, to = "centerVertical"),
@ViewDebug.IntToString(from = LEFT_OF, to = "leftOf"),
@ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf")
- }, mapping = { @ViewDebug.IntToString(from = TRUE, to = "true") })
+ }, mapping = {
+ @ViewDebug.IntToString(from = TRUE, to = "true"),
+ @ViewDebug.IntToString(from = 0, to = "NO_ID")
+ })
private int[] mRules = new int[VERB_COUNT];
private int mLeft, mTop, mRight, mBottom;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7b62b50ce31f8..136752b9f3a2f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -224,7 +224,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private CharSequence mError;
private boolean mErrorWasChanged;
- private PopupWindow mPopup;
+ private ErrorPopup mPopup;
/**
* This flag is set if the TextView tries to display an error before it
* is attached to the window (so its position is still unknown).
@@ -3039,12 +3039,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
}
- }
- if (ict != null || !shouldAdvanceFocusOnEnter()) {
+
// This is the handling for some default action.
// Note that for backwards compatibility we don't do this
// default handling if explicit ime options have not been given,
- // to instead turn this into the normal enter key codes that an
+ // instead turning this into the normal enter key codes that an
// app may be expecting.
if (actionCode == EditorInfo.IME_ACTION_NEXT) {
View v = focusSearch(FOCUS_DOWN);
@@ -3066,15 +3065,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
Handler h = getHandler();
- long eventTime = SystemClock.uptimeMillis();
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
- new KeyEvent(eventTime, eventTime,
- KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
- new KeyEvent(SystemClock.uptimeMillis(), eventTime,
- KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
+ if (h != null) {
+ long eventTime = SystemClock.uptimeMillis();
+ h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ new KeyEvent(eventTime, eventTime,
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
+ | KeyEvent.FLAG_EDITOR_ACTION)));
+ h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ new KeyEvent(SystemClock.uptimeMillis(), eventTime,
+ KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
+ | KeyEvent.FLAG_EDITOR_ACTION)));
+ }
}
/**
@@ -3222,25 +3225,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final TextView err = (TextView) inflater.inflate(com.android.internal.R.layout.textview_hint,
null);
- mPopup = new PopupWindow(err, 200, 50) {
- private boolean mAbove = false;
-
- @Override
- public void update(int x, int y, int w, int h, boolean force) {
- super.update(x, y, w, h, force);
-
- boolean above = isAboveAnchor();
- if (above != mAbove) {
- mAbove = above;
-
- if (above) {
- err.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error_above);
- } else {
- err.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error);
- }
- }
- }
- };
+ mPopup = new ErrorPopup(err, 200, 50);
mPopup.setFocusable(false);
// The user is entering text, so the input method is needed. We
// don't want the popup to be displayed on top of it.
@@ -3252,6 +3237,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
tv.setText(mError);
mPopup.showAsDropDown(this, getErrorX(), getErrorY());
+ mPopup.fixDirection(mPopup.isAboveAnchor());
+ }
+
+ private static class ErrorPopup extends PopupWindow {
+ private boolean mAbove = false;
+ private TextView mView;
+
+ ErrorPopup(TextView v, int width, int height) {
+ super(v, width, height);
+ mView = v;
+ }
+
+ void fixDirection(boolean above) {
+ mAbove = above;
+
+ if (above) {
+ mView.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error_above);
+ } else {
+ mView.setBackgroundResource(com.android.internal.R.drawable.popup_inline_error);
+ }
+ }
+
+ @Override
+ public void update(int x, int y, int w, int h, boolean force) {
+ super.update(x, y, w, h, force);
+
+ boolean above = isAboveAnchor();
+ if (above != mAbove) {
+ fixDirection(above);
+ }
+ }
}
/**
@@ -4001,7 +4017,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
- KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
+ KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
int which = doKeyDown(keyCode, down, event);
if (which == 0) {
@@ -4020,7 +4036,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// of down and up events until we have done the complete repeatCount.
// It would be nice if those interfaces had an onKeyMultiple() method,
// but adding that is a more complicated change.
- KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
+ KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
if (which == 1) {
mInput.onKeyUp(this, (Editable)mText, keyCode, up);
while (--repeatCount > 0) {
@@ -4069,19 +4085,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- private boolean isInterestingEnter(KeyEvent event) {
- if ((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 &&
- mInputContentType != null &&
- (mInputContentType.imeOptions &
- EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
- // If this enter key came from a soft keyboard, and the
- // text editor has been configured to not do a default
- // action for software enter keys, then we aren't interested.
- return false;
- }
- return true;
- }
-
private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) {
if (!isEnabled()) {
return 0;
@@ -4089,18 +4092,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
- if (!isInterestingEnter(event)) {
- // Ignore enter key we aren't interested in.
- return -1;
+ // If ALT modifier is held, then we always insert a
+ // newline character.
+ if ((event.getMetaState()&KeyEvent.META_ALT_ON) == 0) {
+
+ // When mInputContentType is set, we know that we are
+ // running in a "modern" cupcake environment, so don't need
+ // to worry about the application trying to capture
+ // enter key events.
+ if (mInputContentType != null) {
+
+ // If there is an action listener, given them a
+ // chance to consume the event.
+ if (mInputContentType.onEditorActionListener != null &&
+ mInputContentType.onEditorActionListener.onEditorAction(
+ this, EditorInfo.IME_NULL, event)) {
+ mInputContentType.enterDown = true;
+ // We are consuming the enter key for them.
+ return -1;
+ }
+ }
+
+ // If our editor should move focus when enter is pressed, or
+ // this is a generated event from an IME action button, then
+ // don't let it be inserted into the text.
+ if ((event.getFlags()&KeyEvent.FLAG_EDITOR_ACTION) != 0
+ || shouldAdvanceFocusOnEnter()) {
+ return -1;
+ }
}
- if ((event.getMetaState()&KeyEvent.META_ALT_ON) == 0
- && mInputContentType != null
- && mInputContentType.onEditorActionListener != null) {
- mInputContentType.enterDown = true;
- // We are consuming the enter key for them.
- return -1;
- }
- // fall through...
+ break;
+
case KeyEvent.KEYCODE_DPAD_CENTER:
if (shouldAdvanceFocusOnEnter()) {
return 0;
@@ -4215,7 +4237,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- if (shouldAdvanceFocusOnEnter()) {
+ if ((event.getFlags()&KeyEvent.FLAG_EDITOR_ACTION) != 0
+ || shouldAdvanceFocusOnEnter()) {
/*
* If there is a click listener, just call through to
* super, which will invoke it.
@@ -4243,7 +4266,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
super.onKeyUp(keyCode, event);
return true;
} else if ((event.getFlags()
- & KeyEvent.FLAG_SOFT_KEYBOARD) != 0) {
+ & KeyEvent.FLAG_EDITOR_ACTION) != 0) {
// No target for next focus, but make sure the IME
// if this came from it.
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -4302,6 +4325,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
}
}
+ if ((outAttrs.inputType & (InputType.TYPE_MASK_CLASS
+ | InputType.TYPE_TEXT_FLAG_MULTI_LINE))
+ == (InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_FLAG_MULTI_LINE)) {
+ // Multi-line text editors should always show an enter key.
+ outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ }
outAttrs.hintText = mHint;
if (mText instanceof Editable) {
InputConnection ic = new EditableInputConnection(this);
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index 0df919d02a5f3..c5fa18c95f059 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -19,15 +19,11 @@ package android.widget;
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;
-import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.View.OnLongClickListener;
-
public class ZoomButton extends ImageButton implements OnLongClickListener {
private final Handler mHandler;
@@ -39,7 +35,6 @@ public class ZoomButton extends ImageButton implements OnLongClickListener {
}
}
};
- private final GestureDetector mGestureDetector;
private long mZoomSpeed = 1000;
private boolean mIsInLongpress;
@@ -55,19 +50,11 @@ public class ZoomButton extends ImageButton implements OnLongClickListener {
public ZoomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mHandler = new Handler();
- mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
- @Override
- public void onLongPress(MotionEvent e) {
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- onLongClick(ZoomButton.this);
- }
- });
setOnLongClickListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- mGestureDetector.onTouchEvent(event);
if ((event.getAction() == MotionEvent.ACTION_CANCEL)
|| (event.getAction() == MotionEvent.ACTION_UP)) {
mIsInLongpress = false;
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 4daa41949330b..d9fb78b81d385 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -16,23 +16,15 @@
package android.widget;
-import android.app.AlertDialog;
-import android.app.Dialog;
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.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Settings;
import android.util.Log;
-import android.view.GestureDetector;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -42,7 +34,6 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewRoot;
-import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
@@ -51,29 +42,33 @@ import android.view.WindowManager.LayoutParams;
* Implementation notes:
* - The zoom controls are displayed in their own window.
* (Easier for the client and better performance)
- * - This window is not touchable, and by default is not focusable.
- * - To make the buttons clickable, it attaches a OnTouchListener to the owner
- * view and does the hit detection locally.
+ * - This window is never touchable, and by default is not focusable.
+ * Its rect is quite big (fills horizontally) but has empty space between the
+ * edges and center. Touches there should be given to the owner. Instead of
+ * having the window touchable and dispatching these empty touch events to the
+ * owner, we set the window to not touchable and steal events from owner
+ * via onTouchListener.
+ * - To make the buttons clickable, it attaches an OnTouchListener to the owner
+ * view and does the hit detection locally (attaches when visible, detaches when invisible).
* - When it is focusable, it forwards uninteresting events to the owner view's
* view hierarchy.
*/
/**
* The {@link ZoomButtonsController} handles showing and hiding the zoom
- * controls relative to an owner view. It also gives the client access to the
- * zoom controls container, allowing for additional accessory buttons to be
- * shown in the zoom controls window.
+ * controls and positioning it relative to an owner view. It also gives the
+ * client access to the zoom controls container, allowing for additional
+ * accessory buttons to be shown in the zoom controls window.
*
- * Typical usage involves the client using the {@link GestureDetector} to
- * forward events from
- * {@link GestureDetector.OnDoubleTapListener#onDoubleTapEvent(MotionEvent)} to
- * {@link #handleDoubleTapEvent(MotionEvent)}. Also, whenever the owner cannot
- * be zoomed further, the client should update
+ * Typically, clients should call {@link #setVisible(boolean) setVisible(true)}
+ * on a touch down or move (no need to call {@link #setVisible(boolean)
+ * setVisible(false)} since it will time out on its own). Also, whenever the
+ * owner cannot be zoomed further, the client should update
* {@link #setZoomInEnabled(boolean)} and {@link #setZoomOutEnabled(boolean)}.
*
* If you are using this with a custom View, please call
* {@link #setVisible(boolean) setVisible(false)} from the
* {@link View#onDetachedFromWindow}.
- *
+ *
* @hide
*/
public class ZoomButtonsController implements View.OnTouchListener {
@@ -88,6 +83,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
private Context mContext;
private WindowManager mWindowManager;
+ private boolean mAutoDismissControls = true;
/**
* The view that is being zoomed by this zoom controller.
@@ -118,34 +114,25 @@ public class ZoomButtonsController implements View.OnTouchListener {
* The {@link #mTouchTargetView}'s location in window, set on touch down.
*/
private int[] mTouchTargetWindowLocation = new int[2];
+
/**
* If the zoom controller is dismissed but the user is still in a touch
* interaction, we set this to true. This will ignore all touch events until
* up/cancel, and then set the owner's touch listener to null.
+ *
+ * Otherwise, the owner view would get mismatched events (i.e., touch move
+ * even though it never got the touch down.)
*/
private boolean mReleaseTouchListenerOnUp;
- /**
- * Whether we are currently in the double-tap gesture, with the second tap
- * still being performed (i.e., we're waiting for the second tap's touch up).
- */
- private boolean mIsSecondTapDown;
-
/** Whether the container has been added to the window manager. */
private boolean mIsVisible;
private Rect mTempRect = new Rect();
private int[] mTempIntArray = new int[2];
-
+
private OnZoomListener mCallback;
- /**
- * In 1.0, the ZoomControls were to be added to the UI by the client of
- * WebView, MapView, etc. We didn't want apps to break, so we return a dummy
- * view in place now.
- */
- private InvisibleView mDummyZoomControls;
-
/**
* When showing the zoom, we add the view as a new window. However, there is
* logic that needs to know the size of the zoom which is determined after
@@ -170,12 +157,6 @@ public class ZoomButtonsController implements View.OnTouchListener {
}
};
- /**
- * The setting name that tracks whether we've shown the zoom tutorial.
- */
- private static final String SETTING_NAME_SHOWN_TUTORIAL = "shown_zoom_tutorial";
- private static Dialog sTutorialDialog;
-
/** When configuration changes, this is called after the UI thread is idle. */
private static final int MSG_POST_CONFIGURATION_CHANGED = 2;
/** Used to delay the zoom controller dismissal. */
@@ -215,7 +196,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
/**
* Constructor for the {@link ZoomButtonsController}.
- *
+ *
* @param ownerView The view that is being zoomed by the zoom controls. The
* zoom controls will be displayed aligned with this view.
*/
@@ -227,13 +208,13 @@ public class ZoomButtonsController implements View.OnTouchListener {
mTouchPaddingScaledSq = (int)
(ZOOM_CONTROLS_TOUCH_PADDING * mContext.getResources().getDisplayMetrics().density);
mTouchPaddingScaledSq *= mTouchPaddingScaledSq;
-
+
mContainer = createContainer();
}
/**
* Whether to enable the zoom in control.
- *
+ *
* @param enabled Whether to enable the zoom in control.
*/
public void setZoomInEnabled(boolean enabled) {
@@ -242,7 +223,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
/**
* Whether to enable the zoom out control.
- *
+ *
* @param enabled Whether to enable the zoom out control.
*/
public void setZoomOutEnabled(boolean enabled) {
@@ -251,7 +232,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
/**
* Sets the delay between zoom callbacks as the user holds a zoom button.
- *
+ *
* @param speed The delay in milliseconds between zoom callbacks.
*/
public void setZoomSpeed(long speed) {
@@ -264,7 +245,8 @@ public class ZoomButtonsController implements View.OnTouchListener {
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE |
LayoutParams.FLAG_NOT_FOCUSABLE |
- LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ LayoutParams.FLAG_LAYOUT_NO_LIMITS |
+ LayoutParams.FLAG_ALT_FOCUSABLE_IM;
lp.height = LayoutParams.WRAP_CONTENT;
lp.width = LayoutParams.FILL_PARENT;
lp.type = LayoutParams.TYPE_APPLICATION_PANEL;
@@ -299,7 +281,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
/**
* Sets the {@link OnZoomListener} listener that receives callbacks to zoom.
- *
+ *
* @param listener The listener that will be told to zoom.
*/
public void setOnZoomListener(OnZoomListener listener) {
@@ -310,7 +292,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
* Sets whether the zoom controls should be focusable. If the controls are
* focusable, then trackball and arrow key interactions are possible.
* Otherwise, only touch interactions are possible.
- *
+ *
* @param focusable Whether the zoom controls should be focusable.
*/
public void setFocusable(boolean focusable) {
@@ -326,9 +308,27 @@ public class ZoomButtonsController implements View.OnTouchListener {
}
}
+ /**
+ * Whether the zoom controls will be automatically dismissed after showing.
+ *
+ * @return Whether the zoom controls will be auto dismissed after showing.
+ */
+ public boolean isAutoDismissed() {
+ return mAutoDismissControls;
+ }
+
+ /**
+ * Sets whether the zoom controls will be automatically dismissed after
+ * showing.
+ */
+ public void setAutoDismissed(boolean autoDismiss) {
+ if (mAutoDismissControls == autoDismiss) return;
+ mAutoDismissControls = autoDismiss;
+ }
+
/**
* Whether the zoom controls are visible to the user.
- *
+ *
* @return Whether the zoom controls are visible to the user.
*/
public boolean isVisible() {
@@ -337,7 +337,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
/**
* Sets whether the zoom controls should be visible to the user.
- *
+ *
* @param visible Whether the zoom controls should be visible to the user.
*/
public void setVisible(boolean visible) {
@@ -419,7 +419,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
*
* The client can add other views to this container to link them with the
* zoom controls.
- *
+ *
* @return The container of the zoom controls. It will be a layout that
* respects the gravity of a child's layout parameters.
*/
@@ -427,43 +427,20 @@ public class ZoomButtonsController implements View.OnTouchListener {
return mContainer;
}
- private void dismissControlsDelayed(int delay) {
- mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS);
- mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay);
+ /**
+ * Gets the view for the zoom controls.
+ *
+ * @return The zoom controls view.
+ */
+ public View getZoomControls() {
+ return mControls;
}
- /**
- * Should be called by the client for each event belonging to the second tap
- * (the down, move, up, and/or cancel events).
- *
- * @param event The event belonging to the second tap.
- * @return Whether the event was consumed.
- */
- public boolean handleDoubleTapEvent(MotionEvent event) {
- int action = event.getAction();
-
- if (action == MotionEvent.ACTION_DOWN) {
- int x = (int) event.getX();
- int y = (int) event.getY();
-
- /*
- * This class will consume all events in the second tap (down,
- * move(s), up). But, the owner already got the second tap's down,
- * so cancel that. Do this before setVisible, since that call
- * will set us as a touch listener.
- */
- MotionEvent cancelEvent = MotionEvent.obtain(event.getDownTime(),
- SystemClock.elapsedRealtime(),
- MotionEvent.ACTION_CANCEL, 0, 0, 0);
- mOwnerView.dispatchTouchEvent(cancelEvent);
- cancelEvent.recycle();
-
- setVisible(true);
- centerPoint(x, y);
- mIsSecondTapDown = true;
+ private void dismissControlsDelayed(int delay) {
+ if (mAutoDismissControls) {
+ mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS);
+ mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay);
}
-
- return true;
}
private void refreshPositioningVariables() {
@@ -477,7 +454,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
mOwnerView.getLocationOnScreen(mOwnerViewRawLocation);
mContainerRawLocation[0] = mOwnerViewRawLocation[0];
mContainerRawLocation[1] = mOwnerViewRawLocation[1] + containerOwnerYOffset;
-
+
int[] ownerViewWindowLoc = mTempIntArray;
mOwnerView.getLocationInWindow(ownerViewWindowLoc);
@@ -488,39 +465,30 @@ public class ZoomButtonsController implements View.OnTouchListener {
if (mIsVisible) {
mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
}
-
- }
- /**
- * Centers the point (in owner view's coordinates).
- */
- private void centerPoint(int x, int y) {
- if (mCallback != null) {
- mCallback.onCenter(x, y);
- }
}
/* This will only be called when the container has focus. */
private boolean onContainerKey(KeyEvent event) {
int keyCode = event.getKeyCode();
if (isInterestingKey(keyCode)) {
-
+
if (keyCode == KeyEvent.KEYCODE_BACK) {
setVisible(false);
} else {
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
}
-
+
// Let the container handle the key
return false;
-
+
} else {
-
+
ViewRoot viewRoot = getOwnerViewRoot();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
}
-
+
// We gave the key to the owner, don't let the container handle this key
return true;
}
@@ -540,13 +508,13 @@ public class ZoomButtonsController implements View.OnTouchListener {
return false;
}
}
-
+
private ViewRoot getOwnerViewRoot() {
View rootViewOfOwner = mOwnerView.getRootView();
if (rootViewOfOwner == null) {
return null;
}
-
+
ViewParent parentOfRootView = rootViewOfOwner.getParent();
if (parentOfRootView instanceof ViewRoot) {
return (ViewRoot) parentOfRootView;
@@ -562,13 +530,6 @@ public class ZoomButtonsController implements View.OnTouchListener {
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
- // Consume all events during the second-tap interaction (down, move, up/cancel)
- boolean consumeEvent = mIsSecondTapDown;
- if ((action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL)) {
- // The second tap can no longer be down
- mIsSecondTapDown = false;
- }
-
if (mReleaseTouchListenerOnUp) {
// The controls were dismissed but we need to throw away all events until the up
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
@@ -609,18 +570,21 @@ public class ZoomButtonsController implements View.OnTouchListener {
mOwnerViewRawLocation[1] - targetViewRawY);
/* Disallow negative coordinates (which can occur due to
* ZOOM_CONTROLS_TOUCH_PADDING) */
- if (containerEvent.getX() < 0) {
- containerEvent.offsetLocation(-containerEvent.getX(), 0);
+ // These are floats because we need to potentially offset away this exact amount
+ float containerX = containerEvent.getX();
+ float containerY = containerEvent.getY();
+ if (containerX < 0 && containerX > -ZOOM_CONTROLS_TOUCH_PADDING) {
+ containerEvent.offsetLocation(-containerX, 0);
}
- if (containerEvent.getY() < 0) {
- containerEvent.offsetLocation(0, -containerEvent.getY());
+ if (containerY < 0 && containerY > -ZOOM_CONTROLS_TOUCH_PADDING) {
+ containerEvent.offsetLocation(0, -containerY);
}
boolean retValue = targetView.dispatchTouchEvent(containerEvent);
containerEvent.recycle();
- return retValue || consumeEvent;
+ return retValue;
} else {
- return consumeEvent;
+ return false;
}
}
@@ -646,7 +610,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
View closestChild = null;
int closestChildDistanceSq = Integer.MAX_VALUE;
-
+
for (int i = mContainer.getChildCount() - 1; i >= 0; i--) {
View child = mContainer.getChildAt(i);
if (child.getVisibility() != View.VISIBLE) {
@@ -657,13 +621,23 @@ public class ZoomButtonsController implements View.OnTouchListener {
if (frame.contains(containerCoordsX, containerCoordsY)) {
return child;
}
-
- int distanceX = Math.min(Math.abs(frame.left - containerCoordsX),
+
+ int distanceX;
+ if (containerCoordsX >= frame.left && containerCoordsX <= frame.right) {
+ distanceX = 0;
+ } else {
+ distanceX = Math.min(Math.abs(frame.left - containerCoordsX),
Math.abs(containerCoordsX - frame.right));
- int distanceY = Math.min(Math.abs(frame.top - containerCoordsY),
- Math.abs(containerCoordsY - frame.bottom));
+ }
+ int distanceY;
+ if (containerCoordsY >= frame.top && containerCoordsY <= frame.bottom) {
+ distanceY = 0;
+ } else {
+ distanceY = Math.min(Math.abs(frame.top - containerCoordsY),
+ Math.abs(containerCoordsY - frame.bottom));
+ }
int distanceSq = distanceX * distanceX + distanceY * distanceY;
-
+
if ((distanceSq < mTouchPaddingScaledSq) &&
(distanceSq < closestChildDistanceSq)) {
closestChild = child;
@@ -679,130 +653,27 @@ public class ZoomButtonsController implements View.OnTouchListener {
refreshPositioningVariables();
}
- /*
- * This is static so Activities can call this instead of the Views
- * (Activities usually do not have a reference to the ZoomButtonsController
- * instance.)
- */
- /**
- * Shows a "tutorial" (some text) to the user teaching her the new zoom
- * invocation method. Must call from the main thread.
- *
- * 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) {
-
- // TODO: remove this code, but to hit the weekend build, just never show
- if (true) return;
-
- ContentResolver cr = context.getContentResolver();
- if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) {
- return;
- }
-
- SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
- if (sp.getInt(SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) {
- return;
- }
-
- if (sTutorialDialog != null && sTutorialDialog.isShowing()) {
- sTutorialDialog.dismiss();
- }
-
- LayoutInflater layoutInflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- TextView textView = (TextView) layoutInflater.inflate(
- com.android.internal.R.layout.alert_dialog_simple_text, null)
- .findViewById(android.R.id.text1);
- textView.setText(com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short);
-
- sTutorialDialog = new AlertDialog.Builder(context)
- .setView(textView)
- .setIcon(0)
- .create();
-
- Window window = sTutorialDialog.getWindow();
- window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND |
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
-
- sTutorialDialog.show();
- }
-
- /** @hide Should only be used by Android platform apps */
- public static void finishZoomTutorial(Context context, boolean userNotified) {
- if (sTutorialDialog == null) return;
-
- sTutorialDialog.dismiss();
- sTutorialDialog = null;
-
- // Record that they have seen the tutorial
- if (userNotified) {
- try {
- Settings.System.putInt(context.getContentResolver(), SETTING_NAME_SHOWN_TUTORIAL,
- 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.
- */
- SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE);
- sp.edit().putInt(SETTING_NAME_SHOWN_TUTORIAL, 1).commit();
- }
- }
- }
-
- /** @hide Should only be used by Android platform apps */
- public void finishZoomTutorial() {
- finishZoomTutorial(mContext, true);
- }
-
- /** @hide Should only be used only be WebView and MapView */
- public View getDummyZoomControls() {
- if (mDummyZoomControls == null) {
- mDummyZoomControls = new InvisibleView(mContext);
- }
- return mDummyZoomControls;
- }
-
/**
* Interface that will be called when the user performs an interaction that
* triggers some action, for example zooming.
*/
public interface OnZoomListener {
- /**
- * Called when the given point should be centered. The point will be in
- * owner view coordinates.
- *
- * @param x The x of the point.
- * @param y The y of the point.
- */
- void onCenter(int x, int y);
-
+
/**
* Called when the zoom controls' visibility changes.
- *
+ *
* @param visible Whether the zoom controls are visible.
*/
void onVisibilityChanged(boolean visible);
-
+
/**
* Called when the owner view needs to be zoomed.
- *
+ *
* @param zoomIn The direction of the zoom: true to zoom in, false to zoom out.
*/
void onZoom(boolean zoomIn);
}
-
+
private class Container extends FrameLayout {
public Container(Context context) {
super(context);
@@ -820,29 +691,4 @@ public class ZoomButtonsController implements View.OnTouchListener {
}
}
- /**
- * An InvisibleView is an invisible, zero-sized View for backwards
- * compatibility
- */
- private final class InvisibleView extends View {
-
- private InvisibleView(Context context) {
- super(context);
- setVisibility(GONE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(0, 0);
- }
-
- @Override
- public void draw(Canvas canvas) {
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- }
- }
-
}
diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java
index 84d8f0e015b39..a12aee5d4bb3a 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -30,11 +30,6 @@ import com.android.internal.R;
/**
* The {@code ZoomControls} class displays a simple set of controls used for zooming and
* provides callbacks to register for events. */
-// TODO: pending API council
-// *
-// * Instead of using this directly, consider using the {@link ZoomButtonsController} which
-// * handles displaying the zoom controls.
-// */
@Widget
public class ZoomControls extends LinearLayout {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 5c44b2df661d5..b330a1862174c 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -361,11 +361,14 @@ public class AlertController {
if (mView != null) {
customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
- custom.addView(mView, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
+ custom.addView(mView, new LayoutParams(FILL_PARENT, FILL_PARENT));
if (mViewSpacingSpecified) {
custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
mViewSpacingBottom);
}
+ if (mListView != null) {
+ ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
+ }
} else {
mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE);
}
@@ -456,7 +459,9 @@ public class AlertController {
if (mListView != null) {
contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
- contentPanel.addView(mListView, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT));
+ contentPanel.addView(mListView,
+ new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT));
+ contentPanel.setLayoutParams(new LinearLayout.LayoutParams(FILL_PARENT, 0, 1.0f));
} else {
contentPanel.setVisibility(View.GONE);
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index edda1d9230059..d259756530654 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -30,7 +30,15 @@ interface IBatteryStats {
void noteScreenOff();
void notePhoneOn();
void notePhoneOff();
- void setOnBattery(boolean onBattery);
+ void noteWifiOn();
+ void noteWifiOff();
+ void noteBluetoothOn();
+ void noteBluetoothOff();
+ void noteFullWifiLockAcquired(int uid);
+ void noteFullWifiLockReleased(int uid);
+ void noteScanWifiLockAcquired(int uid);
+ void noteScanWifiLockReleased(int uid);
+ void setOnBattery(boolean onBattery, int level);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
}
diff --git a/core/java/com/android/internal/app/RingtonePickerActivity.java b/core/java/com/android/internal/app/RingtonePickerActivity.java
index 1f8e6f02f9817..5a0fea383d846 100644
--- a/core/java/com/android/internal/app/RingtonePickerActivity.java
+++ b/core/java/com/android/internal/app/RingtonePickerActivity.java
@@ -247,9 +247,13 @@ public final class RingtonePickerActivity extends AlertActivity implements
} else {
setResult(RESULT_CANCELED);
}
-
- mCursor.deactivate();
-
+
+ getWindow().getDecorView().post(new Runnable() {
+ public void run() {
+ mCursor.deactivate();
+ }
+ });
+
finish();
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7eea8b73da0d4..b3ae0d6adaa75 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -47,7 +47,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 25;
+ private static final int VERSION = 27;
private final File mFile;
private final File mBackupFile;
@@ -92,6 +92,12 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mPhoneOn;
Timer mPhoneOnTimer;
+ boolean mWifiOn;
+ Timer mWifiOnTimer;
+
+ boolean mBluetoothOn;
+ Timer mBluetoothOnTimer;
+
/**
* These provide time bases that discount the time the device is plugged
* in to power.
@@ -106,6 +112,12 @@ public final class BatteryStatsImpl extends BatteryStats {
long mUnpluggedBatteryUptime;
long mUnpluggedBatteryRealtime;
+ /*
+ * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
+ */
+ int mUnpluggedStartLevel;
+ int mPluggedStartLevel;
+
long mLastWriteTime = 0; // Milliseconds
// For debugging
@@ -471,6 +483,62 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteWifiOnLocked() {
+ if (!mWifiOn) {
+ mWifiOn = true;
+ mWifiOnTimer.startRunningLocked(this);
+ }
+ }
+
+ public void noteWifiOffLocked() {
+ if (mWifiOn) {
+ mWifiOn = false;
+ mWifiOnTimer.stopRunningLocked(this);
+ }
+ }
+
+ public void noteBluetoothOnLocked() {
+ if (!mBluetoothOn) {
+ mBluetoothOn = true;
+ mBluetoothOnTimer.startRunningLocked(this);
+ }
+ }
+
+ public void noteBluetoothOffLocked() {
+ if (mBluetoothOn) {
+ mBluetoothOn = false;
+ mBluetoothOnTimer.stopRunningLocked(this);
+ }
+ }
+
+ public void noteFullWifiLockAcquiredLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteFullWifiLockAcquiredLocked();
+ }
+ }
+
+ public void noteFullWifiLockReleasedLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteFullWifiLockReleasedLocked();
+ }
+ }
+
+ public void noteScanWifiLockAcquiredLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteScanWifiLockAcquiredLocked();
+ }
+ }
+
+ public void noteScanWifiLockReleasedLocked(int uid) {
+ Uid u = mUidStats.get(uid);
+ if (u != null) {
+ u.noteScanWifiLockReleasedLocked();
+ }
+ }
+
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTime(batteryRealtime, which);
}
@@ -479,6 +547,14 @@ public final class BatteryStatsImpl extends BatteryStats {
return mPhoneOnTimer.getTotalTime(batteryRealtime, which);
}
+ @Override public long getWifiOnTime(long batteryRealtime, int which) {
+ return mWifiOnTimer.getTotalTime(batteryRealtime, which);
+ }
+
+ @Override public long getBluetoothOnTime(long batteryRealtime, int which) {
+ return mBluetoothOnTimer.getTotalTime(batteryRealtime, which);
+ }
+
@Override public boolean getIsOnBattery() {
return mOnBattery;
}
@@ -505,6 +581,12 @@ public final class BatteryStatsImpl extends BatteryStats {
long mStartedTcpBytesReceived = -1;
long mStartedTcpBytesSent = -1;
+ boolean mFullWifiLockOut;
+ Timer mFullWifiLockTimer;
+
+ boolean mScanWifiLockOut;
+ Timer mScanWifiLockTimer;
+
/**
* The statistics we have collected for this uid's wake locks.
*/
@@ -527,6 +609,8 @@ public final class BatteryStatsImpl extends BatteryStats {
public Uid(int uid) {
mUid = uid;
+ mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables);
+ mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables);
}
@Override
@@ -586,6 +670,47 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ @Override
+ public void noteFullWifiLockAcquiredLocked() {
+ if (!mFullWifiLockOut) {
+ mFullWifiLockOut = true;
+ mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ @Override
+ public void noteFullWifiLockReleasedLocked() {
+ if (mFullWifiLockOut) {
+ mFullWifiLockOut = false;
+ mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ @Override
+ public void noteScanWifiLockAcquiredLocked() {
+ if (!mScanWifiLockOut) {
+ mScanWifiLockOut = true;
+ mScanWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ @Override
+ public void noteScanWifiLockReleasedLocked() {
+ if (mScanWifiLockOut) {
+ mScanWifiLockOut = false;
+ mScanWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+ @Override
+ public long getFullWifiLockTime(long batteryRealtime, int which) {
+ return mFullWifiLockTimer.getTotalTime(batteryRealtime, which);
+ }
+
+ @Override
+ public long getScanWifiLockTime(long batteryRealtime, int which) {
+ return mScanWifiLockTimer.getTotalTime(batteryRealtime, which);
+ }
+
public long computeCurrentTcpBytesSent() {
return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
@@ -626,6 +751,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(computeCurrentTcpBytesSent());
out.writeLong(mTcpBytesReceivedAtLastUnplug);
out.writeLong(mTcpBytesSentAtLastUnplug);
+ mFullWifiLockTimer.writeToParcel(out, batteryRealtime);
+ mScanWifiLockTimer.writeToParcel(out, batteryRealtime);
}
void readFromParcelLocked(ArrayList unpluggables, Parcel in) {
@@ -671,6 +798,10 @@ public final class BatteryStatsImpl extends BatteryStats {
mCurrentTcpBytesSent = in.readLong();
mTcpBytesReceivedAtLastUnplug = in.readLong();
mTcpBytesSentAtLastUnplug = in.readLong();
+ mFullWifiLockOut = false;
+ mFullWifiLockTimer = new Timer(FULL_WIFI_LOCK, null, mUnpluggables, in);
+ mScanWifiLockOut = false;
+ mScanWifiLockTimer = new Timer(SCAN_WIFI_LOCK, null, mUnpluggables, in);
}
/**
@@ -852,6 +983,9 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void writeToParcelLocked(Parcel out) {
+ final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
+
out.writeLong(mUserTime);
out.writeLong(mSystemTime);
out.writeInt(mStarts);
@@ -1462,6 +1596,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mStartCount++;
mScreenOnTimer = new Timer(-1, null, mUnpluggables);
mPhoneOnTimer = new Timer(-2, null, mUnpluggables);
+ mWifiOnTimer = new Timer(-3, null, mUnpluggables);
+ mBluetoothOnTimer = new Timer(-4, null, mUnpluggables);
mOnBattery = mOnBatteryInternal = false;
mTrackBatteryPastUptime = 0;
mTrackBatteryPastRealtime = 0;
@@ -1469,6 +1605,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
+ mUnpluggedStartLevel = 0;
+ mPluggedStartLevel = 0;
}
public BatteryStatsImpl(Parcel p) {
@@ -1485,7 +1623,7 @@ public final class BatteryStatsImpl extends BatteryStats {
return mOnBattery;
}
- public void setOnBattery(boolean onBattery) {
+ public void setOnBattery(boolean onBattery, int level) {
synchronized(this) {
if (mOnBattery != onBattery) {
mOnBattery = mOnBatteryInternal = onBattery;
@@ -1498,10 +1636,12 @@ public final class BatteryStatsImpl extends BatteryStats {
mTrackBatteryRealtimeStart = realtime;
mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+ mUnpluggedStartLevel = level;
doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
} else {
mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
+ mPluggedStartLevel = level;
doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
}
if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
@@ -1602,6 +1742,28 @@ public final class BatteryStatsImpl extends BatteryStats {
public long getBatteryRealtime(long curTime) {
return getBatteryRealtimeLocked(curTime);
}
+
+ @Override
+ public int getUnpluggedStartLevel() {
+ synchronized(this) {
+ return getUnluggedStartLevelLocked();
+ }
+ }
+
+ public int getUnluggedStartLevelLocked() {
+ return mUnpluggedStartLevel;
+ }
+
+ @Override
+ public int getPluggedStartLevel() {
+ synchronized(this) {
+ return getPluggedStartLevelLocked();
+ }
+ }
+
+ public int getPluggedStartLevelLocked() {
+ return mPluggedStartLevel;
+ }
/**
* Retrieve the statistics object for a particular uid, creating if needed.
@@ -1762,12 +1924,19 @@ public final class BatteryStatsImpl extends BatteryStats {
mLastUptime = in.readLong();
mRealtime = in.readLong();
mLastRealtime = in.readLong();
+ mUnpluggedStartLevel = in.readInt();
+ mPluggedStartLevel = in.readInt();
+
mStartCount++;
mScreenOn = false;
mScreenOnTimer.readSummaryFromParcelLocked(in);
mPhoneOn = false;
mPhoneOnTimer.readSummaryFromParcelLocked(in);
+ mWifiOn = false;
+ mWifiOnTimer.readSummaryFromParcelLocked(in);
+ mBluetoothOn = false;
+ mBluetoothOnTimer.readSummaryFromParcelLocked(in);
final int NU = in.readInt();
for (int iu = 0; iu < NU; iu++) {
@@ -1775,6 +1944,11 @@ public final class BatteryStatsImpl extends BatteryStats {
Uid u = new Uid(uid);
mUidStats.put(uid, u);
+ u.mFullWifiLockOut = false;
+ u.mFullWifiLockTimer.readSummaryFromParcelLocked(in);
+ u.mScanWifiLockOut = false;
+ u.mScanWifiLockTimer.readSummaryFromParcelLocked(in);
+
int NW = in.readInt();
for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
@@ -1857,15 +2031,23 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
+ out.writeInt(mUnpluggedStartLevel);
+ out.writeInt(mPluggedStartLevel);
+
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
final int NU = mUidStats.size();
out.writeInt(NU);
for (int iu = 0; iu < NU; iu++) {
out.writeInt(mUidStats.keyAt(iu));
Uid u = mUidStats.valueAt(iu);
+
+ u.mFullWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ u.mScanWifiLockTimer.writeSummaryFromParcelLocked(out, NOWREAL);
int NW = u.mWakelockStats.size();
out.writeInt(NW);
@@ -1979,6 +2161,10 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenOnTimer = new Timer(-1, null, mUnpluggables, in);
mPhoneOn = false;
mPhoneOnTimer = new Timer(-2, null, mUnpluggables, in);
+ mWifiOn = false;
+ mWifiOnTimer = new Timer(-2, null, mUnpluggables, in);
+ mBluetoothOn = false;
+ mBluetoothOnTimer = new Timer(-2, null, mUnpluggables, in);
mUptime = in.readLong();
mUptimeStart = in.readLong();
mLastUptime = in.readLong();
@@ -1993,6 +2179,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mTrackBatteryRealtimeStart = in.readLong();
mUnpluggedBatteryUptime = in.readLong();
mUnpluggedBatteryRealtime = in.readLong();
+ mUnpluggedStartLevel = in.readInt();
+ mPluggedStartLevel = in.readInt();
mLastWriteTime = in.readLong();
mPartialTimers.clear();
@@ -2028,6 +2216,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mBatteryLastRealtime);
mScreenOnTimer.writeToParcel(out, batteryRealtime);
mPhoneOnTimer.writeToParcel(out, batteryRealtime);
+ mWifiOnTimer.writeToParcel(out, batteryRealtime);
+ mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mLastUptime);
@@ -2041,6 +2231,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mTrackBatteryRealtimeStart);
out.writeLong(mUnpluggedBatteryUptime);
out.writeLong(mUnpluggedBatteryRealtime);
+ out.writeInt(mUnpluggedStartLevel);
+ out.writeInt(mPluggedStartLevel);
out.writeLong(mLastWriteTime);
int size = mUidStats.size();
@@ -2070,6 +2262,10 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenOnTimer.logState();
Log.i(TAG, "*** Phone timer:");
mPhoneOnTimer.logState();
+ Log.i(TAG, "*** Wifi timer:");
+ mWifiOnTimer.logState();
+ Log.i(TAG, "*** Bluetooth timer:");
+ mBluetoothOnTimer.logState();
}
super.dumpLocked(pw);
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index 9e1f2aedca475..66e15c1c28b97 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -28,6 +28,7 @@ import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewDebug;
import android.widget.TextView;
+import android.text.Layout;
/**
* The item view for each item in the {@link IconMenuView}.
@@ -236,6 +237,32 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
positionIcon();
}
+ @Override
+ protected void onTextChanged(CharSequence text, int start, int before, int after) {
+ super.onTextChanged(text, start, before, after);
+
+ // our layout params depend on the length of the text
+ setLayoutParams(getTextAppropriateLayoutParams());
+ }
+
+ /**
+ * @return layout params appropriate for this view. If layout params already exist, it will
+ * augment them to be appropriate to the current text size.
+ */
+ IconMenuView.LayoutParams getTextAppropriateLayoutParams() {
+ IconMenuView.LayoutParams lp = (IconMenuView.LayoutParams) getLayoutParams();
+ if (lp == null) {
+ // Default layout parameters
+ lp = new IconMenuView.LayoutParams(
+ IconMenuView.LayoutParams.FILL_PARENT, IconMenuView.LayoutParams.FILL_PARENT);
+ }
+
+ // Set the desired width of item
+ lp.desiredWidth = (int) Layout.getDesiredWidth(getText(), getPaint());
+
+ return lp;
+ }
+
/**
* Positions the icon vertically (horizontal centering is taken care of by
* the TextView's gravity).
@@ -280,5 +307,5 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
public boolean showsIcon() {
return true;
}
-
+
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index 781c608aaebb7..6034a1e6e82d2 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -26,7 +26,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.Layout;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
@@ -278,14 +277,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi
* Adds an IconMenuItemView to this icon menu view.
* @param itemView The item's view to add
*/
- private void addItemView(IconMenuItemView itemView) {
- LayoutParams lp = (LayoutParams) itemView.getLayoutParams();
-
- if (lp == null) {
- // Default layout parameters
- lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
- }
-
+ private void addItemView(IconMenuItemView itemView) {
// Set ourselves on the item view
itemView.setIconMenuView(this);
@@ -295,10 +287,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi
// This class is the invoker for all its item views
itemView.setItemInvoker(this);
- // Set the desired width of item
- lp.desiredWidth = (int) Layout.getDesiredWidth(itemView.getText(), itemView.getPaint());
-
- addView(itemView, lp);
+ addView(itemView, itemView.getTextAppropriateLayoutParams());
}
/**
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index dee3fdd97f691..f0b35e977ef1c 100644
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -35,6 +35,7 @@ static jmethodID method_xtraDownloadRequest;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
+static const GpsSuplInterface* sGpsSuplInterface = NULL;
// data written to by GPS callbacks
static GpsLocation sGpsLocation;
@@ -144,9 +145,10 @@ static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject ob
sGpsInterface->cleanup();
}
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jboolean singleFix, jint fixFrequency)
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
+ jboolean singleFix, jint fixFrequency)
{
- int result = sGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE, (singleFix ? 0 : fixFrequency));
+ int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
if (result) {
return result;
}
@@ -267,6 +269,33 @@ static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, j
env->ReleaseByteArrayElements(data, bytes, 0);
}
+static void android_location_GpsLocationProvider_set_supl_server(JNIEnv* env, jobject obj,
+ jint addr, jint port)
+{
+ if (!sGpsSuplInterface) {
+ sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
+ }
+ if (sGpsSuplInterface) {
+ sGpsSuplInterface->set_server(addr, port);
+ }
+}
+
+static void android_location_GpsLocationProvider_set_supl_apn(JNIEnv* env, jobject obj, jstring apn)
+{
+ if (!sGpsSuplInterface) {
+ sGpsSuplInterface = (const GpsSuplInterface*)sGpsInterface->get_extension(GPS_SUPL_INTERFACE);
+ }
+ if (sGpsSuplInterface) {
+ if (apn == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ const char *apnStr = env->GetStringUTFChars(apn, NULL);
+ sGpsSuplInterface->set_apn(apnStr);
+ env->ReleaseStringUTFChars(apn, apnStr);
+ }
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -274,7 +303,7 @@ static JNINativeMethod sMethods[] = {
{"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
{"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
{"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
- {"native_start", "(ZI)Z", (void*)android_location_GpsLocationProvider_start},
+ {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start},
{"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
{"native_set_fix_frequency", "(I)V", (void*)android_location_GpsLocationProvider_set_fix_frequency},
{"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
@@ -283,6 +312,8 @@ static JNINativeMethod sMethods[] = {
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
{"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
+ {"native_set_supl_server", "(II)V", (void*)android_location_GpsLocationProvider_set_supl_server},
+ {"native_set_supl_apn", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_set_supl_apn},
};
int register_android_location_GpsLocationProvider(JNIEnv* env)
diff --git a/core/jni/android_os_Hardware.cpp b/core/jni/android_os_Hardware.cpp
index bc8af7801707a..8007662a9fe1a 100644
--- a/core/jni/android_os_Hardware.cpp
+++ b/core/jni/android_os_Hardware.cpp
@@ -15,7 +15,6 @@
*/
#include
-#include
#include
#include
@@ -24,12 +23,6 @@
namespace android {
-static jboolean
-setLedState(JNIEnv *env, jobject clazz, jint colorARGB, jint onMS, jint offMS)
-{
- return set_led_state(colorARGB, onMS, offMS);
-}
-
static jint
getFlashlightEnabled(JNIEnv *env, jobject clazz)
{
@@ -48,24 +41,6 @@ enableCameraFlash(JNIEnv *env, jobject clazz, jint milliseconds)
enable_camera_flash(milliseconds);
}
-static void
-setScreenBacklight(JNIEnv *env, jobject clazz, jint brightness)
-{
- set_light_brightness(SCREEN_LIGHT, brightness);
-}
-
-static void
-setKeyboardBacklight(JNIEnv *env, jobject clazz, jboolean on)
-{
- set_light_brightness(KEYBOARD_LIGHT, (on ? 255 : 0));
-}
-
-static void
-setButtonBacklight(JNIEnv *env, jobject clazz, jboolean on)
-{
- set_light_brightness(BUTTON_LIGHT, (on ? 255 : 0));
-}
-
// ============================================================================
/*
* JNI registration.
@@ -73,13 +48,9 @@ setButtonBacklight(JNIEnv *env, jobject clazz, jboolean on)
static JNINativeMethod g_methods[] = {
/* name, signature, funcPtr */
- { "setLedState", "(III)I", (void*)setLedState },
{ "getFlashlightEnabled", "()Z", (void*)getFlashlightEnabled },
{ "setFlashlightEnabled", "(Z)V", (void*)setFlashlightEnabled },
{ "enableCameraFlash", "(I)V", (void*)enableCameraFlash },
- { "setScreenBacklight", "(I)V", (void*)setScreenBacklight },
- { "setKeyboardBacklight", "(Z)V", (void*)setKeyboardBacklight },
- { "setButtonBacklight", "(Z)V", (void*)setButtonBacklight },
};
int register_android_os_Hardware(JNIEnv* env)
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index c2d75b1fe3e69..df5edba4eb766 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -69,12 +69,6 @@ setLastUserActivityTimeout(JNIEnv *env, jobject clazz, jlong timeMS)
return set_last_user_activity_timeout(timeMS/1000);
}
-static int
-setLightBrightness(JNIEnv *env, jobject clazz, jint mask, jint brightness)
-{
- return set_light_brightness(mask, brightness);
-}
-
static int
setScreenState(JNIEnv *env, jobject clazz, jboolean on)
{
@@ -109,7 +103,6 @@ static JNINativeMethod method_table[] = {
{ "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },
{ "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },
{ "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
- { "setLightBrightness", "(II)I", (void*)setLightBrightness },
{ "setScreenState", "(Z)I", (void*)setScreenState },
{ "shutdown", "()V", (void*)android_os_Power_shutdown },
{ "reboot", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
diff --git a/core/res/assets/webkit/youtube.html b/core/res/assets/webkit/youtube.html
index 5a40c1e71f08b..2aaaa15b29ada 100644
--- a/core/res/assets/webkit/youtube.html
+++ b/core/res/assets/webkit/youtube.html
@@ -43,7 +43,7 @@
-
+
|
diff --git a/core/res/res/anim/input_method_extract_enter.xml b/core/res/res/anim/input_method_extract_enter.xml
new file mode 100644
index 0000000000000..96b049f361778
--- /dev/null
+++ b/core/res/res/anim/input_method_extract_enter.xml
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/core/res/res/anim/input_method_extract_exit.xml b/core/res/res/anim/input_method_extract_exit.xml
new file mode 100644
index 0000000000000..26db13f48dedb
--- /dev/null
+++ b/core/res/res/anim/input_method_extract_exit.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/core/res/res/drawable-land/statusbar_background.png b/core/res/res/drawable-land/statusbar_background.png
index 2a351a5f96e6b..ef61e5273cf36 100644
Binary files a/core/res/res/drawable-land/statusbar_background.png and b/core/res/res/drawable-land/statusbar_background.png differ
diff --git a/core/res/res/drawable/code_lock_left.9.png b/core/res/res/drawable/code_lock_left.9.png
index a53264a8464bf..215dcc83b3549 100644
Binary files a/core/res/res/drawable/code_lock_left.9.png and b/core/res/res/drawable/code_lock_left.9.png differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml
new file mode 100644
index 0000000000000..2db3203200d2c
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png
new file mode 100644
index 0000000000000..859900a89bfd0
Binary files /dev/null and b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.png b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_normal.png
similarity index 100%
rename from core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.png
rename to core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_normal.png
diff --git a/core/res/res/drawable/status_bar_background.9.png b/core/res/res/drawable/status_bar_background.9.png
deleted file mode 100644
index fd754a8850808..0000000000000
Binary files a/core/res/res/drawable/status_bar_background.9.png and /dev/null differ
diff --git a/core/res/res/drawable/status_bar_background.png b/core/res/res/drawable/status_bar_background.png
new file mode 100644
index 0000000000000..cd111664d3044
Binary files /dev/null and b/core/res/res/drawable/status_bar_background.png differ
diff --git a/core/res/res/drawable/status_bar_close_on.9.png b/core/res/res/drawable/status_bar_close_on.9.png
index e91e4fa9eb6bc..9cbd9fe5036b5 100644
Binary files a/core/res/res/drawable/status_bar_close_on.9.png and b/core/res/res/drawable/status_bar_close_on.9.png differ
diff --git a/core/res/res/drawable/status_bar_divider_shadow.9.png b/core/res/res/drawable/status_bar_header_background.9.png
similarity index 93%
rename from core/res/res/drawable/status_bar_divider_shadow.9.png
rename to core/res/res/drawable/status_bar_header_background.9.png
index ad58dbede5c0c..fa9a90c1ee450 100644
Binary files a/core/res/res/drawable/status_bar_divider_shadow.9.png and b/core/res/res/drawable/status_bar_header_background.9.png differ
diff --git a/core/res/res/drawable/status_bar_item_background_normal.9.png b/core/res/res/drawable/status_bar_item_background_normal.9.png
index 6b7674048ee9c..b8e399d9d514a 100644
Binary files a/core/res/res/drawable/status_bar_item_background_normal.9.png and b/core/res/res/drawable/status_bar_item_background_normal.9.png differ
diff --git a/core/res/res/drawable/statusbar_background.png b/core/res/res/drawable/statusbar_background.png
index 2d8aa7af26909..204d76a26bb43 100644
Binary files a/core/res/res/drawable/statusbar_background.png and b/core/res/res/drawable/statusbar_background.png differ
diff --git a/core/res/res/drawable/title_bar_portrait.9.png b/core/res/res/drawable/title_bar_portrait.9.png
new file mode 100644
index 0000000000000..482d82e2f81dc
Binary files /dev/null and b/core/res/res/drawable/title_bar_portrait.9.png differ
diff --git a/core/res/res/layout/always_use_checkbox.xml b/core/res/res/layout/always_use_checkbox.xml
index 20fc4030b5944..5e6e3886facb6 100644
--- a/core/res/res/layout/always_use_checkbox.xml
+++ b/core/res/res/layout/always_use_checkbox.xml
@@ -16,7 +16,7 @@
-
@@ -38,6 +37,5 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingLeft="36dip"
android:visibility="gone"
- android:layout_below="@id/alwaysUse"
android:text="@string/clearDefaultHintMsg" />
-
+
diff --git a/core/res/res/layout/input_method.xml b/core/res/res/layout/input_method.xml
index a21bbe899c574..1a701e9cc09a9 100644
--- a/core/res/res/layout/input_method.xml
+++ b/core/res/res/layout/input_method.xml
@@ -25,19 +25,28 @@
android:orientation="vertical"
>
-
-
-
-
-
-
+ android:orientation="vertical"
+ >
+
+
+
+
+
+
+
+
+
-
+ android:layout_height="fill_parent" />
-
+ android:layout_height="2dip" />
-
+ android:layout_height="8dip" />
-
-
+ android:id="@android:id/content"
+ android:fitsSystemWindows="true"
+ android:foregroundInsidePadding="false"
+ android:foregroundGravity="fill_horizontal|top"
+ android:foreground="?android:attr/windowContentOverlay" />
\ No newline at end of file
diff --git a/core/res/res/layout/status_bar.xml b/core/res/res/layout/status_bar.xml
index 9a6b7e8b2676b..0bc0dac42644c 100644
--- a/core/res/res/layout/status_bar.xml
+++ b/core/res/res/layout/status_bar.xml
@@ -97,7 +97,7 @@
android:gravity="center_vertical|left"
android:paddingLeft="6px"
android:paddingRight="6px"
- android:textColor="#ff000000"
+ android:textColor="?android:attr/textColorPrimaryInverse"
android:background="@drawable/statusbar_background"
/>
diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml
index a6a188e275c01..fd9d26e6eb163 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/core/res/res/layout/status_bar_expanded.xml
@@ -31,12 +31,13 @@
android:paddingTop="3dp"
android:paddingBottom="5dp"
android:paddingRight="3dp"
- android:background="@drawable/status_bar_divider_shadow"
+ android:background="@drawable/status_bar_header_background"
>
-
-
-
-
-
-
-
-
-
+ >
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/layout/status_bar_tracking.xml b/core/res/res/layout/status_bar_tracking.xml
index 661ce86e2a9d6..aa3b733bdabd6 100644
--- a/core/res/res/layout/status_bar_tracking.xml
+++ b/core/res/res/layout/status_bar_tracking.xml
@@ -20,13 +20,12 @@
android:visibility="gone"
android:focusable="true"
android:descendantFocusability="afterDescendants"
- android:background="@drawable/status_bar_background"
android:paddingBottom="0px"
android:paddingLeft="0px"
android:paddingRight="0px"
>
-
-
-
"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"
"Služba není zřízena."
"Nelze změnit nastavení identifikace volajícího."
+
+
+
+
+
+
+
+
+
+
"Hlas"
"Data"
"FAX"
@@ -286,8 +296,10 @@
"Umožňuje povolit či zakázat aktualizace polohy prostřednictvím bezdrátového připojení. Aplikace toto nastavení obvykle nepoužívají."
"přístup k vlastnostem Checkin"
"Umožňuje čtení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají."
- "zvolit gadgety"
- "Umožňuje aplikaci sdělit systému, které aplikace mohou použít které gadgety. Aplikace s tímto oprávněním mohou zpřístupnit osobní údaje jiným aplikacím. Není určeno pro normální aplikace."
+
+
+
+
"změny stavu telefonu"
"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním může přepínat sítě nebo zapnout či vypnout bezdrátové připojení telefonu bez vašeho svolení."
"zjistit stav telefonu"
@@ -405,7 +417,8 @@
"Prosím vložte kartu SIM."
"Síť je blokována"
"Karta SIM je zablokována pomocí kódu PUK."
- "Prosím kontaktujte podporu zákazníků."
+
+
"Karta SIM je zablokována."
"Odblokování karty SIM..."
"%dkrát jste nakreslili nesprávné bezpečnostní gesto. "\n\n"Opakujte prosím akci za %d s."
@@ -413,7 +426,8 @@
"Sekundy zbývající do dalšího pokusu: %d."
"Zapomněli jste gesto?"
"Gesta: Příliš mnoho pokusů"
- "Chcete-li telefon odemknout,"\n"přihlaste se pomocí svého účtu Google"
+
+
"Uživatelské jméno (e-mail)"
"Heslo"
"Přihlásit se"
@@ -552,6 +566,8 @@
"Měsíčně"
"Ročně"
"Video nelze přehrát"
+
+
"Toto video bohužel nelze přehrát."
"OK"
"dop."
@@ -573,14 +589,14 @@
"d'. 'MMM' 'yyyy"
"d'. 'MMM' 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"poledne"
"Poledne"
"půlnoc"
"Půlnoc"
-
+
"%B %-d, %Y"
@@ -616,7 +632,7 @@
-
+
"neděle"
"pondělí"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index cda8cbcd501d7..8619084493f0b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -54,6 +54,16 @@
"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"
"Dienst nicht eingerichtet."
"Die Einstellung für die Anrufer-ID kann nicht geändert werden."
+
+
+
+
+
+
+
+
+
+
"Sprachnotiz"
"Daten"
"FAX"
@@ -286,8 +296,10 @@
"Ermöglicht die Aktivierung/Deaktivierung der Radio-Benachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."
"Auf Check-In-Eigenschaften zugreifen"
"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."
- "Gadgets auswählen"
- "Bei dieser Option meldet die Anwendung dem System, welche Gadgets von welcher Anwendung verwendet werden können. Mit dieser Genehmigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten geben. Nicht für normale Anwendungen vorgesehen."
+
+
+
+
"Telefonstatus ändern"
"Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."
"Telefonstatus lesen"
@@ -405,7 +417,8 @@
"Bitte legen Sie eine SIM-Karte ein."
"Netzwerk gesperrt"
"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."
- "Wenden Sie sich an den Kunden-Support."
+
+
"SIM-Karte ist gesperrt."
"SIM-Karte wird entsperrt..."
"Sie haben Ihr Entsperrungsmuster %d-mal falsch gezeichnet. "\n\n"Versuchen Sie es in %d Sekunden erneut."
@@ -413,7 +426,8 @@
"Versuchen Sie es in %d Sekunden erneut."
"Muster vergessen?"
"Zu viele Versuche!"
- "Melden Sie sich zum Entsperren"\n"mit Ihrem Google-Konto an."
+
+
"Nutzername (E-Mail)"
"Passwort"
"Anmelden"
@@ -552,6 +566,8 @@
"Monatlich"
"Jährlich"
"Video kann nicht wiedergegeben werden."
+
+
"Dieses Video kann leider nicht abgespielt werden."
"OK"
"AM"
@@ -573,14 +589,14 @@
"d'. 'MMM' 'yyyy"
"d'. 'MMM' 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"Mittag"
"Mittag"
"Mitternacht"
"Mitternacht"
-
+
"%-d. %B %Y"
@@ -616,7 +632,7 @@
-
+
"Sonntag"
"Montag"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 495f8aa10c8a9..30061e2d768fb 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -54,6 +54,16 @@
"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"
"El servicio no se suministra."
"El ID del emisor no se puede modificar."
+
+
+
+
+
+
+
+
+
+
"Voz"
"Datos"
"FAX"
@@ -286,8 +296,10 @@
"Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales."
"acceder a propiedades de registro"
"Permite el acceso de lectura/escritura a las propiedades cargadas por el servicio de registro. No está destinado al uso por parte de aplicaciones normales."
- "seleccionar gadgets"
- "Permite a la aplicación indicar al sistema qué gadgets puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden permitir a otras aplicaciones acceder a datos personales. No está destinado al uso por parte de aplicaciones normales."
+
+
+
+
"modificar estado del teléfono"
"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario."
"leer el estado del teléfono"
@@ -405,7 +417,8 @@
"Inserta una tarjeta SIM."
"Bloqueada para la red"
"La tarjeta SIM está bloqueada con el código PUK."
- "Ponte en contacto con el servicio de atención al cliente."
+
+
"La tarjeta SIM está bloqueada."
"Desbloqueando tarjeta SIM..."
"Has realizado %d intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de %d segundos."
@@ -413,7 +426,8 @@
"Espera %d segundos y vuelve a intentarlo."
"¿Has olvidado el patrón?"
"Se han realizado demasiados intentos incorrectos de creación del patrón."
- "Para desbloquear el teléfono,"\n"accede a tu cuenta de Google"
+
+
"Nombre de usuario (correo electrónico)"
"Contraseña"
"Acceder"
@@ -552,6 +566,8 @@
"Mensualmente"
"Anualmente"
"No se puede reproducir el vídeo."
+
+
"Este vídeo no se puede reproducir."
"Aceptar"
"a.m."
@@ -573,14 +589,14 @@
"d' de 'MMM' de 'yyyy"
"d' 'MMM', 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"mediodía"
"Mediodía"
"medianoche"
"Medianoche"
-
+
"%-d %B, %Y"
@@ -616,7 +632,7 @@
-
+
"Domingo"
"Lunes"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8bd064d8b1d4f..b4b9318bef28a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -54,6 +54,16 @@
"Par défaut, les identifiants d\'appelant ne sont pas restreints. Appel suivant : non restreint"
"Ce service n\'est pas pris en charge."
"Le paramètre Identifiant d\'appelant ne peut pas être modifié."
+
+
+
+
+
+
+
+
+
+
"Voix"
"Données"
"Télécopie"
@@ -286,8 +296,10 @@
"Permet l\'activation/la désactivation des notifications de mises à jour de la position géographique provenant de la radio. Les applications normales n\'utilisent pas cette fonctionnalité."
"Accès aux propriétés d\'enregistrement"
"Permet un accès en lecture/écriture à des propriétés envoyées par le service d\'inscription. Les applications normales n\'utilisent pas cette fonctionnalité."
- "choisir les gadgets"
- "Permet à l\'application de signaler au système quels gadgets peuvent être utilisés pour quelle application. Cette autorisation permet aux applications de fournir l\'accès à des données personnelles à d\'autres applications. Cette option n\'est pas utilisée par les applications standard."
+
+
+
+
"Modification de l\'état du téléphone"
"Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer la radio du téléphone, etc., sans vous en avertir."
"Lecture de l\'état du téléphone"
@@ -403,17 +415,19 @@
"Aucune carte SIM n\'a été trouvée."
"Aucune carte SIM n\'est insérée dans le téléphone."
"Insérez une carte SIM."
- "Réseau bloqué"
+ "Réseau verrouillé"
"La carte SIM est verrouillée par code PUK."
- "Veuillez contacter l\'assistance clientèle."
- "La carte SIM est bloquée."
+
+
+ "Téléphone verrouillé"
"Déblocage de la carte SIM..."
"Vous avez mal reproduit le motif de déverrouillage %d fois. "\n\n"Veuillez réessayer dans %d secondes."
"Vous avez mal saisi le motif de déverrouillage %d fois. Au bout de %d tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans %d secondes."
"Réessayez dans %d secondes."
"Motif oublié ?"
"Trop de tentatives de motif !"
- "Pour débloquer votre téléphone,"\n"connectez-vous à l\'aide de votre compte Google"
+
+
"Nom d\'utilisateur (e-mail)"
"Mot de passe"
"Se connecter"
@@ -551,6 +565,8 @@
"Tous les mois"
"Tous les ans"
"Échec de la lecture de la vidéo"
+
+
"Désolé, impossible de lire cette vidéo."
"OK"
"AM"
@@ -572,13 +588,13 @@
"d' 'MMM' 'yyyy"
"d' 'MMM' 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"midi"
"Midi"
"minuit"
"Minuit"
"%-d %B"
-
+
"%-d %B %Y"
@@ -613,7 +629,7 @@
"%-d %b"
-
+
"dimanche"
"lundi"
@@ -806,6 +822,8 @@
+
+
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b4cf458f28a88..f987ae2d586c5 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -54,6 +54,16 @@
"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"
"Servizio non fornito."
"Impossibile modificare l\'impostazione dell\'ID del chiamante."
+
+
+
+
+
+
+
+
+
+
"Voce"
"Dati"
"FAX"
@@ -286,8 +296,10 @@
"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni."
"accesso a proprietà di archiviazione"
"Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni."
- "scegliere gadget"
- "Consente all\'applicazione di indicare al sistema quali gadget possono essere utilizzati e da quale applicazione. Con questa autorizzazione, le applicazioni possono consentire ad altre applicazioni di accedere a dati personali. Da non usare per normali applicazioni."
+
+
+
+
"modifica stato del telefono"
"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare e disattivare il segnale cellulare e così via, senza alcuna notifica."
"lettura stato del telefono"
@@ -405,7 +417,8 @@
"Inserisci una SIM."
"Rete bloccata"
"La SIM è bloccata tramite PUK."
- "Contatta il servizio clienti."
+
+
"La SIM è bloccata."
"Sblocco SIM..."
"%d tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra %d secondi."
@@ -413,7 +426,8 @@
"Riprova fra %d secondi."
"Hai dimenticato la sequenza?"
"Troppi tentativi di inserimento della sequenza."
- "Per sbloccare,"\n"accedi tramite il tuo account Google"
+
+
"Nome utente (email)"
"Password"
"Accedi"
@@ -552,6 +566,8 @@
"Mensilmente"
"Annualmente"
"Impossibile riprodurre il video"
+
+
"Spiacenti. Impossibile riprodurre il video."
"OK"
"AM"
@@ -573,14 +589,14 @@
"MMM' 'd', 'yyyy"
"d' 'MMM' 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"mezzogiorno"
"Mezzogiorno"
"mezzanotte"
"Mezzanotte"
-
+
"%B %-d, %Y"
@@ -616,7 +632,7 @@
-
+
"Domenica"
"Lunedì"
@@ -725,7 +741,7 @@
"L\'attività %1$s (nel processo %2$s) non risponde."
"L\'applicazione %1$s (nel processo %2$s) non risponde."
"Il processo %1$s non risponde."
- "Forza chiusura"
+ "Termina"
"Attendi"
"Debug"
"Seleziona un\'azione per il testo"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2a21bd3fdbaff..25d906f17a57b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -54,6 +54,16 @@
"既定: 発信者番号通知、次の発信: 通知"
"提供可能なサービスがありません。"
"発信者番号の設定は変更できません。"
+
+
+
+
+
+
+
+
+
+
"音声"
"データ"
"FAX"
@@ -69,7 +79,7 @@
"{0}:転送できません"
"OK"
"ウェブページにエラーがあります。"
- "URLが見つかりませんでした。"
+ "URLが見つかりません。"
"このサイトの認証方式には対応していません。"
"認証できませんでした。"
"プロキシサーバーを使用した認証に失敗しました。"
@@ -279,15 +289,17 @@
"ハードウェアのテスト"
"ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。"
"電話番号発信"
- "アプリケーションが電話を自動発信することを許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急呼への発信は許可しません。"
+ "電話番号の自動発信をアプリケーションに許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急通報への発信は許可しません。"
"電話番号発信"
- "緊急呼を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。"
+ "緊急通報を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。"
"位置情報の更新通知"
"無線通信からの位置更新通知を有効/無効にすることを許可します。通常のアプリケーションでは使用しません。"
"チェックインプロパティへのアクセス"
"チェックインサービスがアップロードしたプロパティへの読み書きを許可します。通常のアプリケーションでは使用しません。"
- "ガジェットの選択"
- "特定のアプリケーションで使用可能なガジェットをシステムに指定することをアプリケーションに許可します。この許可を受けたアプリケーションは、他のアプリケーションに個人データへのアクセスを許可することができます。通常のアプリケーションでは使用しません。"
+
+
+
+
"端末ステータスの変更"
"端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"
"端末ステータスの読み取り"
@@ -316,7 +328,7 @@
"APNのプロキシやポートなどのAPN設定の変更をアプリケーションに許可します。"
"ネットワーク接続の変更"
"ネットワークの接続状態の変更をアプリケーションに許可します。"
- "バックグラウンドデータ使用の設定の変更"
+ "バックグラウンドデータ使用設定の変更"
"バックグラウンドデータ使用の設定の変更をアプリケーションに許可します。"
"Wi-Fi状態の表示"
"Wi-Fi状態に関する情報の表示をアプリケーションに許可します。"
@@ -388,13 +400,13 @@
"PINコードを入力"
"PINコードが正しくありません。"
"ロックを解除するにはMENU、0キーの順に押します。"
- "緊急呼番号"
+ "緊急通報番号"
"(サービス登録なし)"
"画面ロック中"
- "MENUキーでロック解除(または緊急呼)"
+ "MENUキーでロック解除(または緊急通報)"
"MENUキーでロック解除"
"ロックを解除するパターンを入力"
- "緊急呼"
+ "緊急通報"
"一致しました"
"やり直してください"
@@ -405,7 +417,8 @@
"SIMカードを挿入してください。"
"ネットワークがロックされました"
"SIMカードはPUKでロックされています。"
- "お客様サポートにお問い合わせください。"
+
+
"SIMカードはロックされています。"
"SIMカードのロック解除中..."
"ロック解除のパターンは%d回とも正しく指定されていません。"\n\n"%d秒後にもう一度指定してください。"
@@ -413,7 +426,8 @@
"%d秒後にやり直してください。"
"パターンを忘れた場合"
"パターンのエラーが多すぎます"
- "ロックを解除するには、"\n"Googleアカウントでログインしてください。"
+
+
"ユーザー名 (メール)"
"パスワード"
"ログイン"
@@ -427,7 +441,7 @@
"通知を消去"
"通知なし"
- "継続中"
+ "操作中"
"通知"
@@ -441,7 +455,7 @@
"再起動"
"ページ「%s」の記述:"
"JavaScript"
- "このページから移動しますか?"\n\n"%s"\n\n"続行する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。"
+ "このページから移動しますか?"\n\n"%s"\n\n"移動する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。"
"確認"
"このパスワードをブラウザで保存しますか?"
"今は保存しない"
@@ -498,7 +512,7 @@
- "1分前"
- - "%d分後"
+ - "%d分前"
- "1時間前"
@@ -552,6 +566,8 @@
"毎月"
"毎年"
"動画を再生できません"
+
+
"この動画は再生できません。"
"OK"
"AM"
@@ -565,22 +581,22 @@
"%3$s%2$s%1$s"
"%3$s%2$s"
"%3$s、%1$s"
- "%1$s、%2$s"
- "%1$s、%2$s"
+ "%1$s %2$s"
+ "%1$s %2$s"
"%2$s、%1$s"
"yyyy'/'MMMM'/'d"
"yyyy'年'MMMM'月'd'日'"
"MMM'/'d' 'yyyy'年'"
"d'/'MMM'/'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"正午"
"正午"
"午前0時"
"午前0時"
-
+
"%Y年%B%-d日"
@@ -616,7 +632,7 @@
-
+
"日曜日"
"月曜日"
@@ -632,20 +648,20 @@
"(木)"
"(金)"
"(土)"
- "(日)"
- "(月)"
- "(火)"
- "(水)"
- "(木)"
- "(金)"
- "(土)"
- "(日)"
+ "日"
+ "月"
+ "火"
+ "水"
+ "木"
+ "金"
+ "土"
+ "日"
"月"
- "(火)"
+ "火"
"水"
- "(木)"
+ "木"
"金"
- "(土)"
+ "土"
"日"
"月"
"火"
@@ -712,7 +728,7 @@
"注意"
"オン"
"オフ"
- "操作の完了に使用"
+ "アプリケーションを選択"
"常にこの操作で使用する"
"ホームの[設定]>[アプリケーション]>[アプリケーションの管理]でデフォルト設定をクリアします。"
"操作の選択"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8fc7d123931d8..faa1267cfb484 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -54,6 +54,16 @@
"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음"
"서비스가 준비되지 않았습니다."
"발신자 번호 설정을 변경할 수 없습니다."
+
+
+
+
+
+
+
+
+
+
"음성"
"데이터"
"팩스"
@@ -286,8 +296,10 @@
"무선의 위치 업데이트 알림을 활성화하거나 비활성화할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."
"체크인 속성 액세스"
"체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 액세스를 허용합니다. 일반 응용프로그램에서는 사용하지 않습니다."
- "가젯 선택"
- "어느 응용프로그램이 어느 가젯을 사용할 수 있는지 시스템에 알려 주는 권한을 본 응용프로그램에 부여합니다. 이 권한을 사용하면 응용프로그램이 개인 데이터에 대한 액세스 권한을 다른 응용프로그램에 제공할 수 있습니다. 일반 응용프로그램은 이 권한을 사용할 수 없습니다."
+
+
+
+
"전화기 상태 수정"
"응용프로그램이 장치의 전화 기능을 제어할 수 있습니다. 이 권한을 갖는 응용프로그램은 사용자에게 알리지 않고 네트워크를 전환하거나, 전화 무선 기능을 켜고 끌 수 있습니다."
"전화기 상태 읽기"
@@ -405,7 +417,8 @@
"SIM 카드를 삽입하세요."
"네트워크 잠김"
"SIM 카드의 PUK가 잠겨 있습니다."
- "고객지원팀에 문의하세요."
+
+
"SIM 카드가 잠겨 있습니다."
"SIM 카드 잠금해제 중..."
"잠금해제 패턴을 %d회 잘못 가져왔습니다. "\n\n"%d초 후에 다시 시도하세요."
@@ -413,7 +426,8 @@
"%d초 후에 다시 입력하세요."
"패턴을 잊으셨나요?"
"패턴을 너무 많이 시도했습니다."
- "잠금해제하려면"\n"Google 계정으로 로그인하세요."
+
+
"사용자 이름(이메일)"
"비밀번호"
"로그인"
@@ -552,6 +566,8 @@
"매월"
"매년"
"동영상 재생 안 됨"
+
+
"죄송합니다. 동영상을 재생할 수 없습니다."
"확인"
"AM"
@@ -573,14 +589,14 @@
"MMM' 'd', 'yyyy"
"d' 'MMM', 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"정오"
"정오"
"자정"
"자정"
-
+
"%Y, %B %-d"
@@ -616,7 +632,7 @@
-
+
"일요일"
"월요일"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c1944a45d3a03..61b89282a75e1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -54,6 +54,16 @@
"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"
"SIM-kortet er ikke tilrettelagt for tjenesten."
"Kunne ikke endre innstilling for nummervisning."
+
+
+
+
+
+
+
+
+
+
"Tale"
"Data"
"Fax"
@@ -286,8 +296,10 @@
"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"
@@ -405,7 +417,8 @@
"Sett inn et SIM-kort."
"Nettverk ikke tillatt"
"SIM-kortet er PUK-låst."
- "Vennligst ring kundeservice."
+
+
"SIM-kortet er låst."
"Låser opp SIM-kort…"
"You have incorrectly drawn your unlock pattern %d times. "\n\n"Please try again in %d seconds."
@@ -413,7 +426,8 @@
"Prøv igjen om %d sekunder."
"Glemt mønsteret?"
"Too many pattern attempts!"
- "To unlock,"\n"sign in with your Google account"
+
+
"Username (email)"
"Password"
"Sign in"
@@ -552,6 +566,8 @@
"En gang i måneden"
"En gang i året"
"Cannot play video"
+
+
"Sorry, this video cannot be played."
"OK"
"AM"
@@ -573,14 +589,14 @@
"MMM' 'd', 'yyyy"
"d'. 'MMM' 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"middag"
"Middag"
"midnatt"
"Midnatt"
-
+
"%-d. %B %Y"
@@ -616,7 +632,7 @@
-
+
"søndag"
"mandag"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 725e369c16f08..2a67cd174641d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -54,6 +54,16 @@
"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."
"Service niet voorzien."
"De instelling voor beller-id kan niet worden gewijzigd."
+
+
+
+
+
+
+
+
+
+
"Spraak"
"Gegevens"
"FAX"
@@ -286,8 +296,10 @@
"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."
"toegang tot checkin-eigenschappen"
"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."
- "gadgets kiezen"
- "Hiermee kan een toepassing het systeem melden welke gadgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."
+
+
+
+
"telefoonstatus wijzigen"
"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."
"telefoonstatus lezen"
@@ -405,7 +417,8 @@
"Plaats een SIM-kaart."
"Netwerk geblokkeerd"
"SIM-kaart is geblokkeerd met PUK-code."
- "Neem contact op met de klantenservice."
+
+
"SIM-kaart is geblokkeerd."
"SIM-kaart ontgrendelen..."
"U heeft uw deblokkeringspatroon %d keer onjuist getekend. "\n\n"Probeer het over %d seconden opnieuw."
@@ -413,7 +426,8 @@
"Probeer het over %d seconden opnieuw."
"Patroon vergeten?"
"Te veel patroonpogingen!"
- "U moet zich aanmelden bij uw Google-account"\n"om te ontgrendelen"
+
+
"Gebruikersnaam (e-mail)"
"Wachtwoord"
"Aanmelden"
@@ -552,6 +566,8 @@
"Maandelijks"
"Jaarlijks"
"Video kan niet worden afgespeeld"
+
+
"Deze video kan niet worden afgespeeld."
"OK"
"am"
@@ -573,14 +589,14 @@
"MMM' 'd', 'yyyy"
"d' 'MMM', 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"twaalf uur \'s middags"
"Twaalf uur \'s middags"
"middernacht"
"Middernacht"
-
+
"%B %-d, %Y"
@@ -616,7 +632,7 @@
-
+
"Zondag"
"Maandag"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 641d335d83346..8c1f61b4cf57b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -54,6 +54,16 @@
"Identyfikator dzwoniącego ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony"
"Usługa nie jest świadczona."
"Nie można zmienić ustawienia identyfikatora dzwoniącego."
+
+
+
+
+
+
+
+
+
+
"Głos"
"Dane"
"FAKS"
@@ -286,8 +296,10 @@
"Pozwala włączyć/wyłączyć powiadomienia o aktualizacji położenia przez radio. Nie wykorzystywane przez normalne aplikacje."
"dostęp do właściwości usługi rezerwacji"
"Pozwala na dostęp z uprawnieniami do odczytu/zapisu do właściwości przesłanych przez usługę rezerwacji. Nie wykorzystywane przez normalne aplikacje."
- "wybieranie gadżetów"
- "Zezwala aplikacjom na wskazywanie systemowi, które gadżety mogą być używane przez inne aplikacje. Z użyciem tego pozwolenia aplikacje mogą udzielać dostępu do danych osobistych innym aplikacjom. Nie jest ono przeznaczone dla zwykłych aplikacji."
+
+
+
+
"zmiana stanu telefonu"
"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może przełączać sieci, włączać i wyłączać radio itp. bez informowania użytkownika."
"czytanie stanu telefonu"
@@ -405,7 +417,8 @@
"Włóż kartę SIM."
"Sieć zablokowana"
"Karta SIM jest zablokowana kodem PUK."
- "Skontaktuj się z działem obsługi klienta."
+
+
"Karta SIM jest zablokowana."
"Odblokowywanie karty SIM..."
"Wzór odblokowania został nieprawidłowo narysowany %d razy. "\n\n"Spróbuj ponownie za %d sekund."
@@ -413,7 +426,8 @@
"Spróbuj ponownie za %d sekund."
"Zapomniałeś wzoru?"
"Zbyt wiele prób narysowania wzoru!"
- "Aby odblokować,"\n"zaloguj się na koncie Google"
+
+
"Nazwa użytkownika (e-mail)"
"Hasło"
"Zaloguj"
@@ -552,6 +566,8 @@
"Miesięcznie"
"Co roku"
"Nie można odtworzyć filmu wideo"
+
+
"Niestety, nie można odtworzyć tego filmu wideo."
"OK"
"rano"
@@ -573,14 +589,14 @@
"MMM' 'd', 'yyyy"
"d' 'MMM', 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"południe"
"Południe"
"północ"
"Północ"
-
+
"%B %-d, %Y"
@@ -616,7 +632,7 @@
-
+
"niedziela"
"poniedziałek"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ba886672130f5..4a99da51fc611 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -54,6 +54,16 @@
"Идентификатор звонящего по умолчанию не ограничен. Следующий вызов: не ограничен"
"Услуга не предоставляется."
"Нельзя изменить настройки идентификатора звонящего."
+
+
+
+
+
+
+
+
+
+
"Голос"
"Данные"
"ФАКС"
@@ -286,8 +296,10 @@
"Разрешает включение/отключение уведомлений о местоположении по радиосвязи. Не используется обычными приложениями."
"открывать свойства проверки"
"Разрешает доступ на чтение и запись к свойствам, загруженным службой проверки. Не используется обычными приложениями."
- "выбирать гаджеты"
- "Позволяет приложению сообщить системе, какие приложения могут использовать какие гаджеты. Это разрешение позволяет приложениям предоставлять другим приложениям доступ к личной информации. Не предназначено для использования обычными приложениями."
+
+
+
+
"изменять состояние телефона"
"Позволяет приложению управлять телефонными функциями устройства. Приложение с такими полномочиями может переключать сети, включать и выключать радиосвязь и т.д., не сообщая вам об этом."
"считывать состояние телефона"
@@ -405,7 +417,8 @@
"Вставьте SIM-карту."
"Заблокирована сетью"
"SIM-карта заблокирована PUK-кодом."
- "Свяжитесь со службой поддержки."
+
+
"SIM-карта заблокирована."
"Разблокировка SIM-карты..."
"Вы неправильно воспроизвели комбинацию разблокировки %d раз. "\n\n"Повторите попытку через %d сек."
@@ -413,7 +426,8 @@
"Повторите попытку через %d сек."
"Забыли комбинацию?"
"Слишком много попыток ввести комбинацию!"
- "Для разблокировки"\n"войдите с помощью своего аккаунта Google"
+
+
"Имя пользователя (адрес электронной почты)"
"Пароль"
"Войти"
@@ -552,6 +566,8 @@
"Ежемесячно"
"Ежегодно"
"Не удается воспроизвести видео"
+
+
"К сожалению, это видео нельзя воспроизвести."
"ОК"
"AM"
@@ -573,14 +589,14 @@
"d' 'MMM' 'yyyy"
"d' 'MMM' 'yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"полдень"
"Полдень"
"полночь"
"Полночь"
-
+
"%-d %B %Y"
@@ -616,7 +632,7 @@
-
+
"воскресенье"
"понедельник"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 346e254533f18..b31c4f42c7182 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -54,6 +54,16 @@
"呼叫者 ID 默认情况下不受限制。下一个呼叫:不受限制"
"未提供服务。"
"不能更改呼叫者 ID 设置。"
+
+
+
+
+
+
+
+
+
+
"语音"
"数据"
"传真"
@@ -286,8 +296,10 @@
"允许启用/禁用来自收音机的位置更新通知。普通应用程序不能使用此权限。"
"访问检入属性"
"允许对检入服务上传的属性进行读/写访问。普通应用程序不能使用此权限。"
- "选择小工具"
- "允许应用程序告诉系统哪些应用程序可以使用哪些小工具。应用程序可以借此授予其他应用程序访问个人数据的权限。普通应用程序不能使用此权限。"
+
+
+
+
"修改手机状态"
"允许应用程序控制设备的手机功能。具有此权限的应用程序可能会切换网络,打开和关闭手机收音机以及类似操作,而不会通知您。"
"读取手机状态"
@@ -405,7 +417,8 @@
"请插入 SIM 卡。"
"网络已锁定"
"已对 SIM 卡进行 PUK 码锁定。"
- "请联系客服部门。"
+
+
"SIM 卡已被锁定。"
"正在解锁 SIM 卡..."
"您 %d 次错误地绘制了您的解锁图案。"\n\n"请在 %d 秒后重试。"
@@ -413,7 +426,8 @@
"%d 秒后重试。"
"忘记了图案?"
"图案尝试次数太多!"
- "要解锁,"\n"请用您的 Google 帐户登录"
+
+
"用户名(电子邮件)"
"密码"
"登录"
@@ -552,6 +566,8 @@
"每月"
"每年"
"无法播放视频"
+
+
"很抱歉,此视频不能播放。"
"确定"
"上午"
@@ -573,14 +589,14 @@
"yyyy' 年 'MMM' 月 'd' 日'"
"yyyy' 年 'd' 月 'MMM' 日'"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"中午"
"中午"
"午夜"
"午夜"
-
+
"%Y 年 %B 月 %-d 日"
@@ -616,7 +632,7 @@
-
+
"周日"
"周一"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6d4b8214c6f06..d88ca653b9718 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -54,6 +54,16 @@
"預設顯示本機號碼,下一通也顯示。"
"服務未設定完成。"
"本機號碼設定無法變更。"
+
+
+
+
+
+
+
+
+
+
"語音"
"資料"
"傳真"
@@ -286,8 +296,10 @@
"允許啟用/停用無線通訊位置更新通知。一般應用程式不會使用此功能。"
"存取登機選項"
"允許讀寫登機服務上傳的資料。一般應用程式不會使用此功能。"
- "選擇小工具"
- "允許應用程式告知系統哪些應用程式可以使用哪些小工具。擁有此權限的應用程式可以讓其他應用程式使用個人資料。一般應用程式不會使用此功能。"
+
+
+
+
"修改手機狀態"
"允許應用程式控制電話功能。擁有此權限的程式可自行切換網路、開關無線通訊功能。"
"讀取手機狀態"
@@ -405,7 +417,8 @@
"請插入 SIM 卡。"
"網路已鎖定"
"SIM 的 PUK 已鎖定。"
- "請聯絡客服中心。"
+
+
"SIM 卡已鎖定。"
"解鎖 SIM 卡中..."
"畫出解鎖圖形已錯誤 %d 次。"\n\n" 請在 %d 秒後再嘗試。"
@@ -413,7 +426,8 @@
"%d 秒後再試一次。"
"忘記解鎖圖形?"
"解鎖圖形出錯次數過多!"
- "若要解鎖,"\n"請以您的 Google 帳戶登入"
+
+
"使用者名稱 (電子郵件)"
"密碼"
"登入"
@@ -552,6 +566,8 @@
"每月"
"每年"
"無法播放影片"
+
+
"抱歉,無法撥放此影片。"
"確定"
"上午"
@@ -573,14 +589,14 @@
"MMM' 'd','yyyy"
"d' 'MMM','yyyy"
"h':'mm' 'a"
- "H':'mm"
+ "HH':'mm"
"中午"
"中午"
"午夜"
"午夜"
-
+
"%B %-d,%Y"
@@ -616,7 +632,7 @@
-
+
"星期日"
"星期一"
@@ -810,6 +826,8 @@
+
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 899d109a3a877..485edca8ff6b1 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -620,12 +620,35 @@
Corresponds to
{@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}. -->
+
+
+
+
@@ -1372,7 +1395,8 @@
+ The foreground drawable participates in the padding of the content if the gravity
+ is set to fill. -->
@@ -1408,6 +1432,9 @@
edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+
+
@@ -3024,6 +3051,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 88c7b354d6fd0..c06c7c4d87b06 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1010,6 +1010,9 @@
+
+
+
The caller ID setting cannot be changed.
+
+ Restricted access changed
+
+ Data service is blocked.
+
+ Emergency service is blocked.
+
+ Voice/SMS service is blocked.
+
+ All voice/SMS services are blocked.
+
Voice
@@ -1148,7 +1159,7 @@
PUK locked (Pin Unlock Kode) -->
SIM card is PUK-locked.
- Please contact Customer Care.
+ Please see the User Guide or contact Customer Care.
SIM card is locked.
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a1524104d4021..fb357a2c2c8be 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -154,12 +154,11 @@
-
+
+
@@ -229,6 +231,7 @@
fills the entire screen -->
@@ -303,21 +309,26 @@
- @android:color/transparent
- @android:style/DialogWindowTitle
- true
- - @drawable/panel_separator
+ - @null
-
-
@@ -358,7 +369,7 @@
- @android:style/DialogWindowTitle
- @android:color/transparent
- true
- - @drawable/panel_separator
+ - @null
- @style/TextAppearance.Theme.Dialog.AppError
diff --git a/docs/html/sdk/OLD_RELEASENOTES.jd b/docs/html/sdk/OLD_RELEASENOTES.jd
new file mode 100644
index 0000000000000..77516818c047a
--- /dev/null
+++ b/docs/html/sdk/OLD_RELEASENOTES.jd
@@ -0,0 +1,527 @@
+page.title=Release Notes for Older SDK Versions
+@jd:body
+
+
+
Note: These are the release notes for the "early-look" SDK versions, released
+ before the full Android 1.0 release in September 2008.
+ Release notes for the Android 1.0 and later SDK versions are provided in the main
+ Release Notes document.
+
+
+
+
+
+Android 0.9 SDK Beta (r1)
+
+This beta SDK release contains a large number of bug fixes and improvements from the early-look SDKs.
+The sections below describe the highlights of the release.
+
+
New Features and Notable Changes
+
+Behavior and System Changes
+
+ - New Home screen and many user interface updates
+
+ - Minor changes to Activity lifecycle and task management
+
+ - New window option to request OpenGL acceleration for certain kinds of View structures
+
+
+
+
+ Significant API Changes
+
+
+ - onFreeze(Bundle) renamed to onSaveInstanceState(Bundle), to better reflect the fact that it does not represent an actual change in application lifecycle
+
+ - IntentReceivers are now known as BroadcastReceivers (but still operate on Intents.)
+
+ - Various parts of the API cleaned up to use Intents instead of Bundles; Intent itself improved to reduce the need for separate payload Bundles.
+ - ContentProvider Cursors have had significant changes to make them easier to create and remove certain data consistency bugs.
+
+ - Changes to menus to make them more flexible; also added context menus (similar to "right mouse button" menus)
+
+ - Changes to the Sensor API to make reading sensors more convenient and reduce the need to poll
+
+ - Improvements to the Camera API
+
+ - Significant changes to the Location API to make it easier to use and better self-documenting
+
+ - API cleanup on MapViews
+
+ - Performance-related changes to the MediaPlayer, as well as support for new types of ringtones
+
+ - Apache HTTPClient installation upgraded to 4.x of that API; 3.x version is removed
+
+ - HTTPClient 4.x removes multipart methods, include HttpMime which is an extension of Mime4j (http://james.apache.org/mime4j/index.html) in your project instead
+
+ - Improvements to WiFi and related networking
+
+ - New Preferences API to easily store small amounts of data
+
+ - Improvements to the Telephony API, including ability to obtain source number of incoming phone calls
+
+ - Variety of improvements to the View API
+
+ - Variety of improvements to component management, such as the ability to keep components private, better control over when processes are started, and ability to "alias" an Activity to more than one entry in AndroidManifest.xml
+
+ - Improvements to how the Browser and WebView, such as better control over content downloads
+
+ - A number of enhancements to XML layouts, such as the new <merge> tag
+
+ - Numerous improvements to the standard widgets
+
+ - Network access now requires that applications obtain a permission in their AndroidManifest.xml files.
+
+
+
+
+ Maps & Location
+
+
+ - The MapView will require an API key on final Android 1.0 devices. This key can be obtained at no cost from Google, and will allow access to the full MapView API. In this release, the API key must be provided but can be any dummy value. In the final 1.0-compatible SDKs, this will need to be a real key.
+
+ - The KML-based mock location provider supported in previous releases is no longer supported. In the current SDK, you can use the emulator console to send GPS fix updates to the emulator and applications running on it. Also, the DDMS tool provides an UI that you can use to easily upload GPX and KML files. DDMS handles playback of the KML or GPX tracks automatically.
+
+
+ ADT Plugin for Eclipse
+ The ADT Plugin that accompanies this SDK includes a preview of the Graphical Layout Editor. Files located in <project>/res/layout[-qualifiers]/ will be opened with the new layout editor. This is very much a work in progress, and provided here for preview purpose. The editor feature is subject to change.
+
+
+ - Dual page editor with a WYSIWYG page (the graphical editor) and an XML page with content assist.
+
+ - The interactivity in the editor itself is limited to selection at the moment. Actions on the layout elements can be done from the following standard Eclipse views: Outline (add/remove/up/down), and Properties (editing of all the element properties with a tooltip in the status bar).
+
+ - Top part of the editor allows you to display the layout in different configurations (language, orientation, size, etc...), and different themes.
+
+
+ - All referenced resources (strings, bitmaps, etc...) are resolved based on the selected configuration/theme.
+
+ - A green check mark next to a resource qualifier indicates that the opened file matches the value of the qualifier. A warning sign indicates that the opened file does not specifies any value for this qualifier.
+
+ - If a different version of the opened layout matches the new configuration selection (in a different res/layout-qualifier folder) then the editor automatically switches to that new file.
+
+
+
+ - Custom Views are supported, however if they do too much in their constructor/onDraw method, it may not work (the layout library used by the editor only includes a sub-part of the Android framework). Check the android console for errors/exceptions.
+
+
+
+Known issues/limitations for Graphical Layout Editor include:
+
+
+ - Font display is very close but not equals to on-device rendering since the font engine in Java slightly differs from the font engine in Android. This should not have any impact on your layouts.
+
+ - Creating new views in a relative layout automatically puts each new elements below each other using the layout_below attribute. However, until the layout file is saved, they will appear stacked on top of each other.
+
+ - Some XML based drawables don't draw. Fading in the scroll/list view appears as a white rectangle. Generally do not expect every single fancy drawing feature of the android framework to be supported in the layout editor (but we're working on it).
+
+ - Themes defined in the project are not added to the theme drop-down.
+
+ - No animation support!
+
+ - No support for WebView, MapView and SurfaceView.
+
+ - No UI support for <merge>, <include>, <ViewStub> elements. You can add these elements to your manifest using the xml editor only.
+
+ - If a layout fails to render in a way that prevents the whole editor from opening, you can:
+
+
+ - open that particular file in a different editor: right click the file in the package explorer and choose Open With... > XML editor
+
+ - completely disable the layout editor, by setting a system wide environment variable called ANDROID_DISABLE_LAYOUT to any value.
+
+
+ - If a layout fails to render, check the android console (in the standard Eclipse Console view). Errors/Exceptions will be displayed in there.
+
+
+
+
+Other ADT features/notes include:
+
+ - There is a new launch option for activity. You can choose to launch the default activity (finds an activity configured to show up in the home screen), or a specific activity, or none.
+ - Normal Java resources (non Java files placed in package folders) are now properly packaged in the final package, and can be accessed through normal java API such as ClassLoader.getResourceAsStream()
+ - Launch configuration now has an option to wipe emulator data on launch. This always asks for confirmation.
+ - Launch configuration now has an option to disable the boot animation. This will let the emulator start faster on older computers.
+ - Installation of application is now more robust and will notify of installation failure. Also installation is blocking, removing issues where ADT tried to launch the activity before the app was installed.
+
+
+
+Ant Build Tools
+
+
+ - External jar libraries are now directly supported by build.xml, just drop them in the libs directory.
+
+
+Emulator
+
+
+ - The console port number of a given emulator instance is now displayed in its window's title bar.
+ - You can define the console port number used by a given emulator instance.
+To do so, start the instance with the '-port <port>' option and
+specify which port the emulator should bind to for the console. <port> must be an *even* integer between 5554 and 5584 inclusive. The corresponding ADB port will be <port>+1.
+ - The
-adb-port command is deprecated. Please do not use it, as it will be removed soon and you cannot use both -port and -adb-port at the same time.
+ - Voice/sms are automatically forwarded to other emulator instances running on the same machine, as long as you use their console port number as the destination phone number. For example, if you have two emulators running, the first one will typically use console port 5554, and the second one will use port 5556, dialing 5556 on the first emulator will generate an incoming call on the second emulator. You can also hold/unhold calls. This also works when sending SMS messages from one emulator to the other.
+ - A new
-scale <fraction> option allows you to scale the emulator window.
+ - A new
-no-boot-anim option tells the emulator to disable the boot animation. On slower systems, this can significantly reduce the time to boot the system in the emulator.
+
+
+
+
+ Other Development Tools
+
+
+The SDK includes several new development tools, such as
+
+ - HierarchyViewer is a visual tool for inspecting and debugging your user interfaces and layout.
+ - Draw 9-patch allows you to easily create a NinePatch graphic using a WYSIWYG editor.
+ - The UI/Application Exerciser Monkey generates pseudo-random system and user events, for testing your application.
+
+
+ Application Signing
+
+
+ - Starting with this release, Android .apk files must be cryptographically signed, or the system will reject them upon installation. The purpose of this requirement is to securely and uniquely identify developers, so that the system can -- for example -- safely let multiple .apk files signed by the same developer share resources.
+
+ - There are no requirements on the key used to sign .apk files; locally-generated and self-signed keys are allowed. There is no PKI, and developers will not be required to purchase certificates, or similar. For developers who use the Eclipse/ADT plugin, application signing will be largely automatic. Developers who do not use Eclipse/ADT can use the standard Java jarsigner tool to sign .apk files.
+
+
+
+ Sample Code
+
+
+ - LunarLander has been converted to render into a SurfaceView via a background Thread, for better performance.
+
+ - New sample: the source code for the now-obsolete Home screen from M5 is included as an example of how to construct a Home screen replacement.
+
+
+
+
+ Removed Functionality
+
+
+ - Due to significant API changes in the upstream open-source project and due to the timeline of getting certain Bluetooth profile implementations certified, a comprehensive Bluetooth API will not be possible or present in Android 1.0.
+
+ - Due to the security risks inherent in accepting arbitrary data from "outside" the device, the data messaging facility of the GTalkService will not be present in Android 1.0. The GTalkService will provide connectivity to Google's servers for Google Talk instant messaging, but the API has been removed from this release while we improve the service. Note that this will be a Google-specific service and is not part of the core of Android.
+
+ - We know that these changes will affect many developers who have worked with the prior early looks at the SDK, and we are very sorry for the resulting inconvenience. We look forward to the possibilty of restoring some or all of this functionality in a later version of the Android platform.
+
+
+
+
+ Miscellaneous
+
+
+ - Many internal and non-public APIs have been removed from the documentation. Classes and methods that are not present in the documentation are non-public and should not be used, even though they may appear in tools such as IDEs. A future version of the SDK will ship with an android.jar file that contains only public classes, to help developers avoid accidentally using non-public APIs.
+
+ - A few extraneous APIs (such as unnecessary packages under java.awt) have been removed.
+
+ - Several additional tools are included, such as a utility for easily drawing 9-patch images.
+
+ - The DDMS utility has been refactored into library form. This is not of direct interest to application developers, but may be of interest to vendors interested in integrating the Android SDK into their products. Watch for more information about the ddmlib library soon.
+
+ - For performance and maintainability reasons, some APIs were moved into separate modules that must be explicitly included in the application via a directive in AndroidManifest.xml. Notable APIs that fall into this category are the MapView, and the java.awt.* classes, which each now reside in separate modules that must be imported. Developers who overlook this requirement will see ClassNotFoundExceptions that seem spurious.
+
+ - Developers who use 'adb push' to install applications must now use 'adb install', since the full package manager is now implemented. 'adb push' will no longer work to install .apk files.
+
+ - The emulator supports a variety of new options, and some existing options have been changed. Please consult the updated emulator documentation for details.
+
+
+
+
+ Resolved Issues
+
+
+ The list below is not comprehensive, but instead highlights the most interesting fixes since the last SDK release.
+
+
+ - More of the standard Android user applications are now included, such as the Music and Messaging applications.
+
+ - Many bug fixes to the Media Player
+
+ - Emulator performance is improved, especially for startup
+
+ - More internal APIs are removed from class documentation. (However, this work is not quite yet complete.)
+
+ - It's now much easier to add media content to the SD card and have the ContentProvider locate and expose it to other applications.
+
+
+
+
+ Known Issues
+
+
+ - The final set of Intent patterns honored by Android 1.0 has not yet been fully documented. Documentation will be provided in future releases.
+
+ - We regret to inform developers that Android 1.0 will not support 3.5" floppy disks.
+
+ - Unfortunately, the ability to play audio streams from memory (such as via an InputStream or Reader) will not be possible in Android 1.0. As a workaround, we recommend that developers save media content to SD card and use MediaPlayer to play from a file URI, or embed a small HTTP server and play from a URI on localhost (such as http://127.0.0.1:4242/something).
+
+ - Android now supports modules or libraries that can be optionally linked into applications; a good example is the MapView, which has been moved into such a library. However, Android 1.0 will not support the ability for third-party developers to create such libraries for sharing with other applications.
+
+ - We believe that we have eliminated the problem with very long emulator startups on Windows, but had some trouble reproducing the issue. We are interested in feedback from developers, if this issue persists.
+
+
+
+
+
+
+
+Version m5-rc15
+
+New Features
+m5-rc15 does not introduce any new features.
+
+Resolved Issues
+
+ - 1012640: Incorrect handling of BMP images.
+
+
+Known Issues
+Unless otherwise noted, Known Issues from m5-rc14 also apply to m5-rc15.
+
+
+
+
+
+Version m5-rc14
+
+New Features
+
+In addition to changes in the Android APIs, m5-rc14 also introduces changes to the Android Developer Tools:
+
+emulator
+
+ - The Android emulator now support SD card images up to 128 GB in size. The previous limit was 2 GB.
+
+
+DDMS
+
+ - Support for managing multiple devices has been integrated into DDMS. This should make it easier to debug applications that are run on multiple device scenarios.
+
+
+ADT
+
+ - ADT now attempts to connect a debugger to any application that shows up
+ in the wait-for-debugger state, even if this application was not launched
+ from Eclipse.
+
+ The connection is actually established only if there exists a project
+ in the Eclipse workspace that contains an AndroidManifest.xml
+ declaring a package matching the name of the process.
+ To force this connection from your code, use Debug.waitForDebugger(). Activities declaring that they require their own process through the
+ "process" attribute with a value like ":someProcess" will be
+ recognized and a debugger will be connected accordingly.
+ This should make it easier to debug intent receivers, services,
+ providers, and other activities not launched from the standard app
+ launcher.
+ - ADT has launch modes for device target selection. Automatic mode will: 1) launch an emulator if no device is present, 2) automatically target the device if only one is connected, and 3) prompt the user if 2 or more are connected. Manual mode will always prompt the user.
+ - ADT also contains the same support for multiple devices that has been introduced into DDMS.
+
+
+AIDL
+
+ - AIDL files that import and reuse types is now supported by activityCreator.py and ADT.
+
+
+traceview
+
+ - The traceview tool is now included in the SDK.
+
+
+Resolved Issues
+
+The following Known Issues from m3-rc20 have been resolved:
+
+ - 917572: The activityCreator created incorrect IntelliJ scripts
+ - 917465: Unanswered incoming calls placed from the emulator console will result in an unfinished call UI if you press the call back button
+ - 917247: dmtracedump and traceview tools are not available in the SDK
+ - 912168: Extremely rapid or prolonged scrolling in the Maps application or MapsView will result in application errors
+ - 905852: adb emits warnings about deprecated API use on Mac OS X 10.5
+ - 905242: The Run dialog sometimes failed to show the Android Launcher
+ - 901122: The focus ring in the browser is sometimes incorrect
+ - 896274: On Windows, the emulator sometimes starts off-screen
+ - 778432: Icons for newly installed applications do not display
+
+
+Known Issues
+
+The following are known issues in m5-rc14:
+
+
+ - 1017312: The emulator window size has been reduced slightly, to allow it to be fully visible on smaller screens. This causes a slight clipping of the HVGA emulator skin but does not affect its function.
+ - 1021777: Setting a power requirement in a
Criteria object passed to {@link android.location.LocationManager#getBestProvider getBestProvider()} will result in a value not being returned.
+ - 1025850: Emulator failing to launch from the Eclipse plugin due to wrong custom command line parameters do not report the error anywhere and silently fails.
+
+
+Unless otherwise noted, Known Issues from m3-rc20a also apply to m5-rc14.
+
+
+
+
+
+Version m3-rc37a
+
+Version m3-rc37a and ADT 0.3.3 were released on December 14, 2007.
+
+New Features
+
+Android Debug Bridge (ADB)
+
+- Now supports multiple emulators on one host computer. Please note that you need to use the
-data option when starting secondary emulators, to allow those instances to save their data across sessions. Also, DDMS does not yet support debugging on multiple emulators yet.
+
+
+ADT Plugin for Eclipse
+
+- Adds editor capabilities for working with Android manifest files, such as syntax highlighting and autocompletion. The editor capabilities require the Web Tools WST plugin for Eclipse, which is included in most Eclipse packages. Not having WST does not prevent the ADT plugin from working. If necessary, you can download and install WST from the Web Tools Project downloads page. To update directly from an Eclipse installation, you can add a remote update site with this URL: http://download.eclipse.org/webtools/updates . Note that installing WST on Eclipse 3.4 will require installing other packages, as detailed on the WTP downloads page.
+
+- Now retries to launch the app on the emulator if it fails due to timing issues when the emulator is booting.
+- Adds support for loading custom skins from the <SDK>/lib/images/skins/ directory. The Skin dropdown in the Emulator tab is now built from the content of the skins/ directory in order to support developer-made skins.
+- Adds an Emulator control panel. This is a UI on top of the emulator console that allows you to change the state of the network and gsm connection, and to initiate incoming voice call. (This is also present in standalone DDMS.)
+- Adds support for referenced projects. Android projects will add to the apk package any code from referenced projects.
+- Eclipse console now warns if an .apk that is pushed to the device declares the same package as another already installed package.
+- Java classes generated by the Eclipse plugin are now marked as derived automatically, so that Team plugins do not consider them as regular source.
+
+
+Emulator Console
+
+- Now provides support for emulating inbound SMS messages. The ADT plugin and DDMS provide integrated access to
+this capability. For more information about how to emulate inbound SMS from the console,
+see SMS Emulation.
+
+
+Emulator
+- The default emulator skin has been changed to HVGA-P from QVGA-L. For information
+about emulator skins and how to load a specific skin when starting the emulator, see
+Using Emulator Skins.
+
+
+Resolved Issues
+
+907947
+adb -version now returns a version number.
+
+917462
+Audio on Windows is fixed and is no longer 'choppy'.
+
+Removed Manifest File Locking on Mac OS X
+
+ADT plugin now uses a custom java editor for R.java/Manifest.java, to make those files non-editable. This is to replace the current locking mechanism which causes issues on Mac OS (preventing projects from being deleted). Note that your project must recompile at least once for the lock to be removed from the files.
+
+The following known issues noted in m3-rc20 are now fixed:
+
+
+- 890937: Emulator does not support non-qwerty keyboards.
+
- 894618:
adb shell may fail to connect when used the first time.
+ - 896274: On Windows, the emulator window may start off-screen.
+
- 899949: The emulator may fail to start with
-useaudio on some environments.
+ - 912619: Emulator console listens on non-local ports 5554-5584.
+
- 917399: On Windows, running multiple emulator consoles can result in unexpected behavior when simulating incoming telephone calls.
+
+
+
+Known Issues
+
+Unless otherwise noted, Known Issues from m3-rc22a also apply to m3-rc37a.
+
+
+
+
+
+Version m3-rc22a
+
+Version m3-rc22a and ADT 0.3.1 were released on November 16, 2007.
+
+Resolved Issues
+
+920067
+The New Android Project wizard provided by ADT 0.3.1 now properly displays error messages when used with Eclipse 3.2 on Windows.
+
+920045
+The AndroidManifest.xml files generated by ADT 0.3.1 now include the XML element required for displaying the associated app in the "Applications" menu. If you have applications created with ADT 0.3.0, simply ensure that your AndroidManifest.xml file contains the following highlighted line:
+
+...
+ <intent-filter>
+ <action android:value="android.intent.action.MAIN" />
+ <category android:value="android.intent.category.LAUNCHER" />
+ </intent-filter>
+...
+
+
+920098
+ADT 0.3.1 is now compatible with Eclipse 3.4.
+
+920282
+Fixes a NullPointerException that is thrown in certain situations with the DDMS perspective in Eclipse.
+
+918637
+Address a keyboard lock-up issue when using adb on Mac OS X 10.4 and 10.5.
+
+Known Issues
+
+Unless otherwise noted, known issues from m3-rc20a also apply to m3-rc22a.
+
+
+
+Version m3-rc20a
+Known Issues
+
+The following are known issues in m3-rc20a:
+
+778432 - Resolved in m5
+In certain circumstances, icons for newly installed applications do not display as expected.
+
+890937 - Resolved in m3-rc37a
+The emulator currently does not support non-QWERTY keyboards.
+
+894618 - Resolved in m3-rc37a
+The adb shell command may fail to connect when used for the first time.
+
+896274 - Resolved in m5
+On Windows, the emulator screen will sometimes show up off-screen when it is started. The workaround for this is to right-click on the emulator taskbar entry, select Move, and move the window using keyboard arrow keys
+
+899949 - Resolved in m3-rc37a
+The emulator may fail to start when using the -useaudio in some environments
+
+901122 - Resolved in m5
+The focus ring shown in the browser may sometimes not properly wrap links.
+
+905242 - Resolved in m5
+On Mac OS X 10.5, the Eclipse plugin's Run Dialog may sometimes fail to show the option to select the Android Launcher.
+
+905852 - Resolved in m5
+On Mac OS X 10.5, adb will emit warnings about deprecated API use when first used.
+
+912168 - Resolved in m5
+extremely rapid or prolonged scrolling in the Maps application or in a MapView will result in application errors.
+
+912619 - Resolved in m3-rc37a
+The emulator console listens for connections on ports 5554-5587. Future versions will only accept connections from localhost. It is recommend that you use a firewall to block external connections to those ports on your development machine.
+
+912849
+On Mac OS X 10.4, the emulator may hang if started in the background (i.e. ./emulator &).
+
+914692
+On Mac OS X 10.5, the emulator will emit warnings about deprecated API use when started from the command line.
+
+917247 - Resolved in m5
+The dmtracedump and traceview tools are not available in the SDK.
+
+917399 - Resolved in m3-rc37a
+On Windows, running multiple emulator consoles can result in unexpected behavior when simulating incoming telephone calls.
+
+917465 - Resolved in m5
+Unanswered incoming calls placed from the emulator console, will result in an unfinished call UI if you press the call back button.
+
+917572 - Resolved in m5
+Using activityCreator with the --ide intellij option creates IntelliJ scripts with incorrect documentation location specified. To correct, change value for the <JAVADOC> element in the generated .ipr file from file://.../docs/framework to file://.../docs/reference.
+
+917579
+On Ubuntu 7.10 (Gusty), the Eclipse package installed by the apt-get install eclipse command uses java-gcj by default. This configuration is not compatible with the Android Eclipse plugin (ADT) and will result in "Class not found" errors whenever you access an ADT feature.
+ The resolution for this issue is to install a Sun JDK
+ sudo update-java-alternatives --jre java-1.5.0-sun
+ and then configure Eclipse to use it by exporting the following environment variable:
+ export JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun
+ or by adding following to your .eclipse/eclipserc file:
+ JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun
+
diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd
new file mode 100644
index 0000000000000..ff57a36ec3922
--- /dev/null
+++ b/docs/html/sdk/older_releases.jd
@@ -0,0 +1,234 @@
+page.title=Older Releases
+@jd:body
+
+
+
NOTICE:
+
The SDKs listed on this page are "early-look" versions that were released in
+ the year preceding the full release of Android 1.0 in September 2008. Because
+ these early-look SDKs were released before the Android 1.0 API specification was
+ finalized, they do not provide a compliant Android execution environment.
+ Consequently, applications that you develop in these SDKs will not be able to
+ run on any Android-powered devices.
+
+
If you have an older application that you built in one of the early-look SDKs,
+ you must migrate it to the Android
+ 1.0 SDK (or later release) before you will be able to deploy it to
+ an Android-powered device. To help with this migration, each SDK package below
+ provides information about API changes from the previous version. You can find
+ the migration information in the documentation included in each SDK package.
+
+
If you are just getting started developing on Android, do not use one of these early-look
+ SDKs. Instead, develop using the most current
+ SDK release available, to ensure that your applications will be compatible
+ with Android-powered devices.
+
+
+
+
+
+ Android 0.9 SDK beta
+ August 18, 2008 - Release Notes
+
+
+
+
+
+Version m5-rc15
+ March 3, 2008 - Release Notes
+
+
+
+
+
+ Version m5-rc14
+ February 12, 2008 - Release Notes
+
+
+
+
+
+ Version m3-rc37a
+ December 14, 2007 - Release Notes
+
+
+
+
+
+ Version m3-rc22a
+ November 16, 2007 - Release Notes
+
+
+
+
+
+ Version m3-rc20a
+ November 12, 2007 - Release Notes
+
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 76c1c84ea07ba..9a5a18b39b30b 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -30,6 +30,7 @@
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 78d76219baf85..b9ea0c66e3010 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -104,7 +104,8 @@ enum media_recorder_error_type {
//
enum media_recorder_info_type {
MEDIA_RECORDER_INFO_UNKNOWN = 1,
- MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800
+ MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800,
+ MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801
};
// ----------------------------------------------------------------------------
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1991aa74c71bd..bda969ce83251 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -64,7 +64,8 @@ struct audio_track_cblk_t
uint16_t waitTimeMs; // Cumulated wait time
// Padding ensuring that data buffer starts on a cache line boundary (32 bytes).
// See AudioFlinger::TrackBase constructor
- int32_t Padding[3];
+ int32_t Padding[1];
+ // Cache line boundary
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 7d3fcf2a837d9..d01d83f831690 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -814,7 +814,7 @@ struct ResTable_config
ORIENTATION_ANY = 0x0000,
ORIENTATION_PORT = 0x0001,
ORIENTATION_LAND = 0x0002,
- ORIENTATION_SQUARE = 0x0002,
+ ORIENTATION_SQUARE = 0x0003,
};
enum {
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 5652b285ade08..9ba7f90f956e0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -58,6 +58,9 @@
namespace android {
+static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n";
+static const char* kHardwareLockedString = "Hardware lock is taken\n";
+
//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
static const unsigned long kBufferRecoveryInUsecs = 2000;
static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
@@ -195,7 +198,7 @@ AudioFlinger::~AudioFlinger()
#ifdef WITH_A2DP
// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
void AudioFlinger::setA2dpEnabled_l(bool enable)
-{
+{
SortedVector < sp > tracks;
SortedVector < wp > activeTracks;
@@ -243,12 +246,6 @@ bool AudioFlinger::streamForcedToSpeaker(int streamType)
streamType == AudioSystem::NOTIFICATION);
}
-bool AudioFlinger::streamDisablesA2dp(int streamType)
-{
- return (streamType == AudioSystem::VOICE_CALL ||
- streamType == AudioSystem::BLUETOOTH_SCO);
-}
-
status_t AudioFlinger::dumpClients(int fd, const Vector& args)
{
const size_t SIZE = 256;
@@ -301,18 +298,39 @@ status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector& args
return NO_ERROR;
}
+static bool tryLock(Mutex& mutex)
+{
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mutex.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
+ return locked;
+}
+
status_t AudioFlinger::dump(int fd, const Vector& args)
{
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
dumpPermissionDenial(fd, args);
} else {
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleep);
+ // get state of hardware lock
+ bool hardwareLocked = tryLock(mHardwareLock);
+ if (!hardwareLocked) {
+ String8 result(kHardwareLockedString);
+ write(fd, result.string(), result.size());
+ } else {
+ mHardwareLock.unlock();
+ }
+
+ bool locked = tryLock(mLock);
+
+ // failed to lock - AudioFlinger is probably deadlocked
+ if (!locked) {
+ String8 result(kDeadlockedString);
+ write(fd, result.string(), result.size());
}
dumpClients(fd, args);
@@ -496,6 +514,14 @@ status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
}
LOGV("setOutput done\n");
}
+ // setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when
+ // SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only
+ // in this case to avoid doing it several times.
+ if (mode == AudioSystem::MODE_IN_CALL &&
+ (mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) {
+ AutoMutex lock(&mLock);
+ handleRouteDisablesA2dp_l(routes);
+ }
#endif
// do nothing if only A2DP routing is affected
@@ -657,7 +683,7 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted)
if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
-
+
#ifdef WITH_A2DP
mA2dpMixerThread->setStreamMute(stream, muted);
#endif
@@ -672,8 +698,6 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted)
mHardwareMixerThread->setStreamMute(stream, muted);
}
-
-
return NO_ERROR;
}
@@ -837,36 +861,29 @@ void AudioFlinger::handleForcedSpeakerRoute(int command)
}
#ifdef WITH_A2DP
-// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::handleStreamDisablesA2dp_l(int command)
+// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::handleRouteDisablesA2dp_l(int routes)
{
- switch(command) {
- case ACTIVE_TRACK_ADDED:
- {
- if (mA2dpDisableCount++ == 0) {
- if (mA2dpEnabled) {
- setA2dpEnabled_l(false);
- mA2dpSuppressed = true;
- }
- }
- LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
- }
- break;
- case ACTIVE_TRACK_REMOVED:
- {
- if (mA2dpDisableCount > 0) {
- if (--mA2dpDisableCount == 0) {
- if (mA2dpSuppressed) {
- setA2dpEnabled_l(true);
- mA2dpSuppressed = false;
- }
- }
- LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
- } else {
- LOGE("mA2dpDisableCount is already zero");
+ if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) {
+ if (mA2dpDisableCount++ == 0) {
+ if (mA2dpEnabled) {
+ setA2dpEnabled_l(false);
+ mA2dpSuppressed = true;
}
}
- break;
+ LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
+ } else {
+ if (mA2dpDisableCount > 0) {
+ if (--mA2dpDisableCount == 0) {
+ if (mA2dpSuppressed) {
+ setA2dpEnabled_l(true);
+ mA2dpSuppressed = false;
+ }
+ }
+ LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
+ } else {
+ LOGE("mA2dpDisableCount is already zero");
+ }
}
}
#endif
@@ -1500,13 +1517,6 @@ void AudioFlinger::MixerThread::addActiveTrack_l(const wp