Merge "Avoid waking EGL in getInitCount"
diff --git a/Android.mk b/Android.mk
index d27dbab..9c51fc62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -118,6 +118,7 @@
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
core/java/android/net/INetworkStatsService.aidl \
+ core/java/android/net/INetworkStatsSession.aidl \
core/java/android/net/nsd/INsdManager.aidl \
core/java/android/nfc/INdefPushCallback.aidl \
core/java/android/nfc/INfcAdapter.aidl \
diff --git a/api/current.txt b/api/current.txt
index f00911b..180ac91 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -80,7 +80,7 @@
field public static final java.lang.String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
field public static final java.lang.String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
field public static final java.lang.String READ_HISTORY_BOOKMARKS = "com.android.browser.permission.READ_HISTORY_BOOKMARKS";
- field public static final java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
+ field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
field public static final java.lang.String READ_PROFILE = "android.permission.READ_PROFILE";
@@ -934,6 +934,7 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsRtl = 16843688; // 0x10103a8
+ field public static final int supportsSentenceSpellCheck = 16843698; // 0x10103b2
field public static final int supportsUploading = 16843419; // 0x101029b
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
@@ -16687,6 +16688,7 @@
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2";
field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String NORMALIZED_NUMBER = "data4";
field public static final java.lang.String NUMBER = "data1";
field public static final int TYPE_ASSISTANT = 19; // 0x13
field public static final int TYPE_CALLBACK = 8; // 0x8
@@ -17047,6 +17049,7 @@
protected static abstract interface ContactsContract.PhoneLookupColumns {
field public static final java.lang.String LABEL = "label";
+ field public static final java.lang.String NORMALIZED_NUMBER = "normalized_number";
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String TYPE = "type";
}
@@ -25280,11 +25283,13 @@
method public android.view.textservice.SpellCheckerInfo getSpellChecker();
method public void getSuggestions(android.view.textservice.TextInfo, int);
method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
+ method public boolean isSentenceSpellCheckSupported();
method public boolean isSessionDisconnected();
field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
}
public static abstract interface SpellCheckerSession.SpellCheckerSessionListener {
+ method public abstract void onGetSentenceSuggestions(android.view.textservice.SentenceSuggestionsInfo[]);
method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
}
@@ -25768,7 +25773,8 @@
method public deprecated void emulateShiftHeld();
method public static deprecated void enablePlatformNotifications();
method public static java.lang.String findAddress(java.lang.String);
- method public int findAll(java.lang.String);
+ method public deprecated int findAll(java.lang.String);
+ method public void findAllAsync(java.lang.String);
method public void findNext(boolean);
method public void flingScroll(int, int);
method public void freeMemory();
@@ -25819,6 +25825,7 @@
method public void saveWebArchive(java.lang.String, boolean, android.webkit.ValueCallback<java.lang.String>);
method public void setCertificate(android.net.http.SslCertificate);
method public void setDownloadListener(android.webkit.DownloadListener);
+ method public void setFindListener(android.webkit.WebView.FindListener);
method public void setHorizontalScrollbarOverlay(boolean);
method public void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
method public void setInitialScale(int);
@@ -25837,6 +25844,10 @@
field public static final java.lang.String SCHEME_TEL = "tel:";
}
+ public static abstract interface WebView.FindListener {
+ method public abstract void onFindResultReceived(int, int, boolean);
+ }
+
public static class WebView.HitTestResult {
method public java.lang.String getExtra();
method public int getType();
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 2391b72..b39c335 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -13,3 +13,29 @@
LOCAL_MODULE:= app_process
include $(BUILD_EXECUTABLE)
+
+
+# Build a variant of app_process binary linked with ASan runtime.
+# ARM-only at the moment.
+ifeq ($(TARGET_ARCH),arm)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ app_main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libbinder \
+ libandroid_runtime
+
+LOCAL_MODULE := app_process__asan
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
+LOCAL_MODULE_STEM := app_process
+LOCAL_ADDRESS_SANITIZER := true
+
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq($(TARGET_ARCH),arm)
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index c4c3b8a..3037881 100755
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -16,11 +16,12 @@
package com.android.commands.input;
+import android.hardware.input.InputManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
-import android.view.IWindowManager;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -33,8 +34,6 @@
public class Input {
private static final String TAG = "Input";
- private IWindowManager mWindowManager;
-
/**
* Command-line entry point.
*
@@ -44,13 +43,6 @@
(new Input()).run(args);
}
- private IWindowManager getWindowManager() {
- if (mWindowManager == null) {
- mWindowManager = (IWindowManager.Stub.asInterface(ServiceManager.getService("window")));
- }
- return mWindowManager;
- }
-
private void run(String[] args) {
if (args.length < 1) {
showUsage();
@@ -127,8 +119,10 @@
private void sendKeyEvent(int keyCode) {
long now = SystemClock.uptimeMillis();
- injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0));
- injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0));
+ injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+ injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
private void sendTap(float x, float y) {
@@ -150,23 +144,14 @@
}
private void injectKeyEvent(KeyEvent event) {
- try {
- Log.i(TAG, "InjectKeyEvent: " + event);
- getWindowManager().injectKeyEvent(event, true);
- } catch (RemoteException ex) {
- Log.i(TAG, "RemoteException", ex);
- }
+ Log.i(TAG, "InjectKeyEvent: " + event);
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
private void injectPointerEvent(MotionEvent event) {
- try {
- Log.i("Input", "InjectPointerEvent: " + event);
- getWindowManager().injectPointerEvent(event, true);
- } catch (RemoteException ex) {
- Log.i(TAG, "RemoteException", ex);
- } finally {
- event.recycle();
- }
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+ Log.i("Input", "InjectPointerEvent: " + event);
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
private static final float lerp(float a, float b, float alpha) {
@@ -174,7 +159,7 @@
}
private void showUsage() {
- System.err.println("usage: input [text|keyevent]");
+ System.err.println("usage: input ...");
System.err.println(" input text <string>");
System.err.println(" input keyevent <key code>");
System.err.println(" input tap <x> <y>");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3e123ba..7207e29 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2522,7 +2522,19 @@
if (onOptionsItemSelected(item)) {
return true;
}
- return mFragments.dispatchOptionsItemSelected(item);
+ if (mFragments.dispatchOptionsItemSelected(item)) {
+ return true;
+ }
+ if (item.getItemId() == android.R.id.home && mActionBar != null &&
+ (mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ if (mParent == null) {
+ onNavigateUp();
+ } else {
+ mParent.onNavigateUpFromChild(this);
+ }
+ return true;
+ }
+ return false;
case Window.FEATURE_CONTEXT_MENU:
EventLog.writeEvent(50000, 1, item.getTitleCondensed());
@@ -2654,15 +2666,6 @@
if (mParent != null) {
return mParent.onOptionsItemSelected(item);
}
- if (item.getItemId() == android.R.id.home && mActionBar != null &&
- (mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
- if (mParent == null) {
- onNavigateUp();
- } else {
- mParent.onNavigateUpFromChild(this);
- }
- return true;
- }
return false;
}
@@ -4865,11 +4868,19 @@
* Obtain an {@link Intent} that will launch an explicit target activity specified by
* this activity's logical parent. The logical parent is named in the application's manifest
* by the {@link android.R.attr#parentActivityName parentActivityName} attribute.
+ * Activity subclasses may override this method to modify the Intent returned by
+ * super.getParentActivityIntent() or to implement a different mechanism of retrieving
+ * the parent intent entirely.
*
- * @return a new Intent targeting the defined parent of this activity
+ * @return a new Intent targeting the defined parent of this activity or null if
+ * there is no valid parent.
*/
public Intent getParentActivityIntent() {
- return new Intent().setClassName(this, mActivityInfo.parentActivityName);
+ final String parentName = mActivityInfo.parentActivityName;
+ if (TextUtils.isEmpty(parentName)) {
+ return null;
+ }
+ return new Intent().setClassName(this, parentName);
}
// ------------------ Internal API ------------------
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 000abc5..a3fdf3e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -867,6 +867,16 @@
return true;
}
+ case GET_UID_FOR_INTENT_SENDER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IIntentSender r = IIntentSender.Stub.asInterface(
+ data.readStrongBinder());
+ int res = getUidForIntentSender(r);
+ reply.writeNoException();
+ reply.writeInt(res);
+ return true;
+ }
+
case SET_PROCESS_LIMIT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int max = data.readInt();
@@ -2714,6 +2724,18 @@
reply.recycle();
return res;
}
+ public int getUidForIntentSender(IIntentSender sender) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(sender.asBinder());
+ mRemote.transact(GET_UID_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public void setProcessLimit(int max) throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9dde51c..c5d7b91 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -45,6 +45,7 @@
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
import android.hardware.SerialManager;
+import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
@@ -325,9 +326,9 @@
}});
registerService(INPUT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new InputManager(ctx);
- }});
+ public Object createService(ContextImpl ctx) {
+ return new InputManager(ctx);
+ }});
registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 0f287c1..c71b186 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -175,6 +175,7 @@
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, int userId) throws RemoteException;
public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
+ public int getUidForIntentSender(IIntentSender sender) throws RemoteException;
public void setProcessLimit(int max) throws RemoteException;
public int getProcessLimit() throws RemoteException;
@@ -531,6 +532,7 @@
int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
+ int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e4f7950..f955713 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -23,6 +23,7 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -35,6 +36,7 @@
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.IWindowManager;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -859,11 +861,30 @@
*/
public void sendKeySync(KeyEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectKeyEvent(event, true);
- } catch (RemoteException e) {
+
+ long downTime = event.getDownTime();
+ long eventTime = event.getEventTime();
+ int action = event.getAction();
+ int code = event.getKeyCode();
+ int repeatCount = event.getRepeatCount();
+ int metaState = event.getMetaState();
+ int deviceId = event.getDeviceId();
+ int scancode = event.getScanCode();
+ int source = event.getSource();
+ int flags = event.getFlags();
+ if (source == InputDevice.SOURCE_UNKNOWN) {
+ source = InputDevice.SOURCE_KEYBOARD;
}
+ if (eventTime == 0) {
+ eventTime = SystemClock.uptimeMillis();
+ }
+ if (downTime == 0) {
+ downTime = eventTime;
+ }
+ KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
+ deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
+ InputManager.injectInputEvent(newEvent,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -902,11 +923,10 @@
*/
public void sendPointerSync(MotionEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectPointerEvent(event, true);
- } catch (RemoteException e) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
}
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -922,11 +942,10 @@
*/
public void sendTrackballEventSync(MotionEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectTrackballEvent(event, true);
- } catch (RemoteException e) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
+ event.setSource(InputDevice.SOURCE_TRACKBALL);
}
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2a9f1af..18d682d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2000,8 +2000,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_ANLG_HEADSET_PLUG =
- "android.intent.action.USB_ANLG_HEADSET_PLUG";
+ public static final String ACTION_ANALOG_AUDIO_DOCK_PLUG =
+ "android.intent.action.ANALOG_AUDIO_DOCK_PLUG";
/**
* Broadcast Action: A digital audio speaker/headset plugged in or unplugged.
@@ -2015,8 +2015,8 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_DGTL_HEADSET_PLUG =
- "android.intent.action.USB_DGTL_HEADSET_PLUG";
+ public static final String ACTION_DIGITAL_AUDIO_DOCK_PLUG =
+ "android.intent.action.DIGITAL_AUDIO_DOCK_PLUG";
/**
* Broadcast Action: A HMDI cable was plugged or unplugged
@@ -2034,6 +2034,38 @@
"android.intent.action.HDMI_AUDIO_PLUG";
/**
+ * Broadcast Action: A USB audio accessory was plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>card</em> - ALSA card number (integer) </li>
+ * <li><em>device</em> - ALSA device number (integer) </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG =
+ "android.intent.action.USB_AUDIO_ACCESSORY_PLUG";
+
+ /**
+ * Broadcast Action: A USB audio device was plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>card</em> - ALSA card number (integer) </li>
+ * <li><em>device</em> - ALSA device number (integer) </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
+ "android.intent.action.USB_AUDIO_DEVICE_PLUG";
+
+ /**
* <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
* <ul>
* <li><em>state</em> - A boolean value indicating whether the settings is on or off.</li>
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 15ccda3..7571993 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -94,10 +94,12 @@
public static class SplitPermissionInfo {
public final String rootPerm;
public final String[] newPerms;
+ public final int targetSdk;
- public SplitPermissionInfo(String rootPerm, String[] newPerms) {
+ public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
this.rootPerm = rootPerm;
this.newPerms = newPerms;
+ this.targetSdk = targetSdk;
}
}
@@ -126,7 +128,14 @@
public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
new PackageParser.SplitPermissionInfo[] {
new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
- new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE })
+ new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
+ android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
+ new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
+ new String[] { android.Manifest.permission.READ_CALL_LOG },
+ android.os.Build.VERSION_CODES.JELLY_BEAN),
+ new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
+ new String[] { android.Manifest.permission.WRITE_CALL_LOG },
+ android.os.Build.VERSION_CODES.JELLY_BEAN)
};
private String mArchiveSourcePath;
@@ -1293,8 +1302,9 @@
for (int is=0; is<NS; is++) {
final PackageParser.SplitPermissionInfo spi
= PackageParser.SPLIT_PERMISSIONS[is];
- if (!pkg.requestedPermissions.contains(spi.rootPerm)) {
- break;
+ if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
+ || !pkg.requestedPermissions.contains(spi.rootPerm)) {
+ continue;
}
for (int in=0; in<spi.newPerms.length; in++) {
final String perm = spi.newPerms[in];
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 85061bb..c2abce5 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,6 +16,22 @@
package android.hardware.input;
+import android.view.InputDevice;
+import android.view.InputEvent;
+
/** @hide */
interface IInputManager {
+ // Gets input device information.
+ InputDevice getInputDevice(int deviceId);
+ int[] getInputDeviceIds();
+
+ // Reports whether the hardware supports the given keys; returns true if successful
+ boolean hasKeys(int deviceId, int sourceMask, in int[] keyCodes, out boolean[] keyExists);
+
+ // Temporarily changes the pointer speed.
+ void tryPointerSpeed(int speed);
+
+ // Injects an input event into the system. To inject into windows owned by other
+ // applications, the caller must have the INJECT_EVENTS permission.
+ boolean injectInputEvent(in InputEvent ev, int mode);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6093404..5ead1f4 100755
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -31,9 +31,16 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
+import android.view.InputDevice;
+import android.view.InputEvent;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.UnavailableException;
@@ -53,6 +60,8 @@
public final class InputManager {
private static final String TAG = "InputManager";
+ private static final IInputManager sIm;
+
private final Context mContext;
// Used to simulate a persistent data store.
@@ -118,6 +127,53 @@
public static final String META_DATA_KEYBOARD_LAYOUTS =
"android.hardware.input.metadata.KEYBOARD_LAYOUTS";
+ /**
+ * Pointer Speed: The minimum (slowest) pointer speed (-7).
+ * @hide
+ */
+ public static final int MIN_POINTER_SPEED = -7;
+
+ /**
+ * Pointer Speed: The maximum (fastest) pointer speed (7).
+ * @hide
+ */
+ public static final int MAX_POINTER_SPEED = 7;
+
+ /**
+ * Pointer Speed: The default pointer speed (0).
+ * @hide
+ */
+ public static final int DEFAULT_POINTER_SPEED = 0;
+
+ /**
+ * Input Event Injection Synchronization Mode: None.
+ * Never blocks. Injection is asynchronous and is assumed always to be successful.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0; // see InputDispatcher.h
+
+ /**
+ * Input Event Injection Synchronization Mode: Wait for result.
+ * Waits for previous events to be dispatched so that the input dispatcher can
+ * determine whether input event injection will be permitted based on the current
+ * input focus. Does not wait for the input event to finish being handled
+ * by the application.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; // see InputDispatcher.h
+
+ /**
+ * Input Event Injection Synchronization Mode: Wait for finish.
+ * Waits for the event to be delivered to the application and handled.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; // see InputDispatcher.h
+
+ static {
+ IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
+ sIm = IInputManager.Stub.asInterface(b);
+ }
+
/** @hide */
public InputManager(Context context) {
mContext = context;
@@ -296,6 +352,160 @@
return null;
}
+ /**
+ * Gets the mouse pointer speed.
+ * <p>
+ * Only returns the permanent mouse pointer speed. Ignores any temporary pointer
+ * speed set by {@link #tryPointerSpeed}.
+ * </p>
+ *
+ * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public int getPointerSpeed() {
+ int speed = DEFAULT_POINTER_SPEED;
+ try {
+ speed = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED);
+ } catch (SettingNotFoundException snfe) {
+ }
+ return speed;
+ }
+
+ /**
+ * Sets the mouse pointer speed.
+ * <p>
+ * Requires {@link android.Manifest.permissions.WRITE_SETTINGS}.
+ * </p>
+ *
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public void setPointerSpeed(int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED, speed);
+ }
+
+ /**
+ * Changes the mouse pointer speed temporarily, but does not save the setting.
+ * <p>
+ * Requires {@link android.Manifest.permission.SET_POINTER_SPEED}.
+ * </p>
+ *
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public void tryPointerSpeed(int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ try {
+ sIm.tryPointerSpeed(speed);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not set temporary pointer speed.", ex);
+ }
+ }
+
+ /**
+ * Gets information about the input device with the specified id.
+ * @param id The device id.
+ * @return The input device or null if not found.
+ *
+ * @hide
+ */
+ public static InputDevice getInputDevice(int id) {
+ try {
+ return sIm.getInputDevice(id);
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not get input device information.", ex);
+ }
+ }
+
+ /**
+ * Gets the ids of all input devices in the system.
+ * @return The input device ids.
+ *
+ * @hide
+ */
+ public static int[] getInputDeviceIds() {
+ try {
+ return sIm.getInputDeviceIds();
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not get input device ids.", ex);
+ }
+ }
+
+ /**
+ * Queries the framework about whether any physical keys exist on the
+ * any keyboard attached to the device that are capable of producing the given
+ * array of key codes.
+ *
+ * @param keyCodes The array of key codes to query.
+ * @return A new array of the same size as the key codes array whose elements
+ * are set to true if at least one attached keyboard supports the corresponding key code
+ * at the same index in the key codes array.
+ *
+ * @hide
+ */
+ public static boolean[] deviceHasKeys(int[] keyCodes) {
+ boolean[] ret = new boolean[keyCodes.length];
+ try {
+ sIm.hasKeys(-1, InputDevice.SOURCE_ANY, keyCodes, ret);
+ } catch (RemoteException e) {
+ // no fallback; just return the empty array
+ }
+ return ret;
+ }
+
+ /**
+ * Injects an input event into the event system on behalf of an application.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
+ * <p>
+ * Requires {@link android.Manifest.permission.INJECT_EVENTS} to inject into
+ * windows that are owned by other applications.
+ * </p><p>
+ * Make sure you correctly set the event time and input source of the event
+ * before calling this method.
+ * </p>
+ *
+ * @param event The event to inject.
+ * @param mode The synchronization mode. One of:
+ * {@link #INJECT_INPUT_EVENT_MODE_ASYNC},
+ * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT}, or
+ * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH}.
+ * @return True if input event injection succeeded.
+ *
+ * @hide
+ */
+ public static boolean injectInputEvent(InputEvent event, int mode) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+ if (mode != INJECT_INPUT_EVENT_MODE_ASYNC
+ && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
+ && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
+ throw new IllegalArgumentException("mode is invalid");
+ }
+
+ try {
+ return sIm.injectInputEvent(event, mode);
+ } catch (RemoteException ex) {
+ return false;
+ }
+ }
+
private static String makeKeyboardLayoutDescriptor(String packageName,
String receiverName, String keyboardName) {
return packageName + "/" + receiverName + "/" + keyboardName;
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 93f93c7..c40504a7 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -66,6 +66,8 @@
* PTP function is enabled
* <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
* accessory function is enabled
+ * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
+ * audio source function is enabled
* </ul>
*
* {@hide}
@@ -178,6 +180,14 @@
public static final String USB_FUNCTION_PTP = "ptp";
/**
+ * Name of the audio source USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
+
+ /**
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 0e883cf..b4f6367 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -16,6 +16,7 @@
package android.net;
+import android.net.INetworkStatsSession;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
@@ -23,15 +24,11 @@
/** {@hide} */
interface INetworkStatsService {
- /** Return historical network layer stats for traffic that matches template. */
- NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
- /** Return historical network layer stats for specific UID traffic that matches template. */
- NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+ /** Start a statistics query session. */
+ INetworkStatsSession openSession();
- /** Return network layer usage summary for traffic that matches template. */
- NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
- /** Return network layer usage summary per UID for traffic that matches template. */
- NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+ /** Return network layer usage total for traffic that matches template. */
+ long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
/** Return data layer snapshot of UID network usage. */
NetworkStats getDataLayerSnapshotForUid(int uid);
diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl
new file mode 100644
index 0000000..1596fa2
--- /dev/null
+++ b/core/java/android/net/INetworkStatsSession.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+
+/** {@hide} */
+interface INetworkStatsSession {
+
+ /** Return network layer usage summary for traffic that matches template. */
+ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
+ /** Return historical network layer stats for traffic that matches template. */
+ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
+
+ /** Return network layer usage summary per UID for traffic that matches template. */
+ NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+ /** Return historical network layer stats for specific UID traffic that matches template. */
+ NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+
+ void close();
+
+}
diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java
index 6535256..1725ed7 100644
--- a/core/java/android/net/NetworkQuotaInfo.java
+++ b/core/java/android/net/NetworkQuotaInfo.java
@@ -57,12 +57,12 @@
return mHardLimitBytes;
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mEstimatedBytes);
out.writeLong(mSoftLimitBytes);
@@ -70,10 +70,12 @@
}
public static final Creator<NetworkQuotaInfo> CREATOR = new Creator<NetworkQuotaInfo>() {
+ @Override
public NetworkQuotaInfo createFromParcel(Parcel in) {
return new NetworkQuotaInfo(in);
}
+ @Override
public NetworkQuotaInfo[] newArray(int size) {
return new NetworkQuotaInfo[size];
}
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 704111b..2fc69ad 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -52,12 +52,12 @@
subscriberId = in.readString();
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(networkInfo, flags);
out.writeParcelable(linkProperties, flags);
@@ -66,10 +66,12 @@
}
public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
+ @Override
public NetworkState createFromParcel(Parcel in) {
return new NetworkState(in);
}
+ @Override
public NetworkState[] newArray(int size) {
return new NetworkState[size];
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 7a1ef66..844d055 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -155,7 +155,7 @@
operations = parcel.createLongArray();
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeInt(size);
@@ -352,10 +352,9 @@
* on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
* since operation counts are at data layer.
*/
- @Deprecated
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
- final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
+ final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]);
if (j == -1) {
operations[i] = 0;
} else {
@@ -663,16 +662,18 @@
return writer.toString();
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+ @Override
public NetworkStats createFromParcel(Parcel in) {
return new NetworkStats(in);
}
+ @Override
public NetworkStats[] newArray(int size) {
return new NetworkStats[size];
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index faf8a3f..0003c6e 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -130,7 +130,7 @@
totalBytes = in.readLong();
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
@@ -191,7 +191,7 @@
writeVarLongArray(out, operations, bucketCount);
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
@@ -586,10 +586,12 @@
}
public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
+ @Override
public NetworkStatsHistory createFromParcel(Parcel in) {
return new NetworkStatsHistory(in);
}
+ @Override
public NetworkStatsHistory[] newArray(int size) {
return new NetworkStatsHistory[size];
}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 973fac1..ee3e165 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -238,6 +238,19 @@
}
}
+ /** {@hide} */
+ public static void closeQuietly(INetworkStatsSession session) {
+ // TODO: move to NetworkStatsService once it exists
+ if (session != null) {
+ try {
+ session.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
/**
* Get the total number of packets transmitted through the mobile interface.
*
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d724d56..0e9306b 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4531,8 +4531,6 @@
/**
* The phone number's E164 representation.
* <P>Type: TEXT</P>
- *
- * @hide
*/
public static final String NORMALIZED_NUMBER = "normalized_number";
}
@@ -5408,10 +5406,10 @@
public static final String NUMBER = DATA;
/**
- * The phone number's E164 representation.
+ * The phone number's E164 representation. This value can be omitted in which
+ * case the provider will try to automatically infer it. If present, {@link #NUMBER}
+ * has to be set as well (it will be ignored otherwise).
* <P>Type: TEXT</P>
- *
- * @hide
*/
public static final String NORMALIZED_NUMBER = DATA4;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 371e2a1..2aaf548 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -37,6 +37,7 @@
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -2260,6 +2261,7 @@
private static ILockSettings sLockSettings = null;
+ private static boolean sIsSystemProcess;
private static final HashSet<String> MOVED_TO_LOCK_SETTINGS;
static {
MOVED_TO_LOCK_SETTINGS = new HashSet<String>(3);
@@ -2283,8 +2285,10 @@
if (sLockSettings == null) {
sLockSettings = ILockSettings.Stub.asInterface(
(IBinder) ServiceManager.getService("lock_settings"));
+ sIsSystemProcess = Process.myUid() == Process.SYSTEM_UID;
}
- if (sLockSettings != null && MOVED_TO_LOCK_SETTINGS.contains(name)) {
+ if (sLockSettings != null && !sIsSystemProcess
+ && MOVED_TO_LOCK_SETTINGS.contains(name)) {
try {
return sLockSettings.getString(name, "0", UserId.getCallingUserId());
} catch (RemoteException re) {
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index bb4b282..ae9042c 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -50,8 +50,6 @@
public SpannableStringBuilder(CharSequence text, int start, int end) {
int srclen = end - start;
- if (srclen < 0) throw new StringIndexOutOfBoundsException();
-
int len = ArrayUtils.idealCharArraySize(srclen + 1);
mText = new char[len];
mGapStart = srclen;
@@ -127,46 +125,38 @@
}
private void resizeFor(int size) {
- int newlen = ArrayUtils.idealCharArraySize(size + 1);
- char[] newtext = new char[newlen];
+ final int oldLength = mText.length;
+ final int newLength = ArrayUtils.idealCharArraySize(size + 1);
+ final int after = oldLength - (mGapStart + mGapLength);
- int after = mText.length - (mGapStart + mGapLength);
+ char[] newText = new char[newLength];
+ System.arraycopy(mText, 0, newText, 0, mGapStart);
+ System.arraycopy(mText, oldLength - after, newText, newLength - after, after);
+ mText = newText;
- System.arraycopy(mText, 0, newtext, 0, mGapStart);
- System.arraycopy(mText, mText.length - after,
- newtext, newlen - after, after);
-
- for (int i = 0; i < mSpanCount; i++) {
- if (mSpanStarts[i] > mGapStart)
- mSpanStarts[i] += newlen - mText.length;
- if (mSpanEnds[i] > mGapStart)
- mSpanEnds[i] += newlen - mText.length;
- }
-
- int oldlen = mText.length;
- mText = newtext;
- mGapLength += mText.length - oldlen;
-
+ final int delta = newLength - oldLength;
+ mGapLength += delta;
if (mGapLength < 1)
new Exception("mGapLength < 1").printStackTrace();
+
+ for (int i = 0; i < mSpanCount; i++) {
+ if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
+ if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+ }
}
private void moveGapTo(int where) {
if (where == mGapStart)
return;
- boolean atEnd = (where == length());
+ boolean atend = (where == length());
if (where < mGapStart) {
int overlap = mGapStart - where;
-
- System.arraycopy(mText, where,
- mText, mGapStart + mGapLength - overlap, overlap);
+ System.arraycopy(mText, where, mText, mGapStart + mGapLength - overlap, overlap);
} else /* where > mGapStart */ {
int overlap = where - mGapStart;
-
- System.arraycopy(mText, where + mGapLength - overlap,
- mText, mGapStart, overlap);
+ System.arraycopy(mText, where + mGapLength - overlap, mText, mGapStart, overlap);
}
// XXX be more clever
@@ -181,7 +171,7 @@
else if (start == where) {
int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
- if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ if (flag == POINT || (atend && flag == PARAGRAPH))
start += mGapLength;
}
@@ -192,7 +182,7 @@
else if (end == where) {
int flag = (mSpanFlags[i] & END_MASK);
- if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ if (flag == POINT || (atend && flag == PARAGRAPH))
end += mGapLength;
}
@@ -342,18 +332,17 @@
boolean atEnd = (mGapStart + mGapLength == mText.length);
for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpanStarts[i] >= start &&
- mSpanStarts[i] < mGapStart + mGapLength) {
+ if (mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength) {
int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
- if (flag == POINT || (flag == PARAGRAPH && atEnd))
- mSpanStarts[i] = mGapStart + mGapLength;
- else
- mSpanStarts[i] = start;
+ if (flag == POINT || (flag == PARAGRAPH && atEnd)) {
+ mSpanStarts[i] = mGapStart + mGapLength;
+ } else {
+ mSpanStarts[i] = start;
+ }
}
- if (mSpanEnds[i] >= start &&
- mSpanEnds[i] < mGapStart + mGapLength) {
+ if (mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength) {
int flag = (mSpanFlags[i] & END_MASK);
if (flag == POINT || (flag == PARAGRAPH && atEnd))
@@ -362,7 +351,8 @@
mSpanEnds[i] = start;
}
- // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
+ // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE, which are POINT_MARK and could
+ // get their boundaries swapped by the above code
if (mSpanEnds[i] < mSpanStarts[i]) {
removeSpan(i);
}
@@ -399,7 +389,7 @@
// Documentation from interface
public SpannableStringBuilder replace(final int start, final int end,
- CharSequence tb, int tbstart, int tbend) {
+ CharSequence tb, int tbstart, int tbend) {
int filtercount = mFilters.length;
for (int i = 0; i < filtercount; i++) {
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -421,26 +411,53 @@
TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
sendBeforeTextChanged(textWatchers, start, origLen, newLen);
- // Try to keep the cursor / selection at the same relative position during
- // a text replacement. If replaced or replacement text length is zero, this
- // is already taken care of.
- boolean adjustSelection = origLen != 0 && newLen != 0;
- int selstart = 0;
- int selend = 0;
- if (adjustSelection) {
- selstart = Selection.getSelectionStart(this);
- selend = Selection.getSelectionEnd(this);
- }
+ if (origLen == 0 || newLen == 0) {
+ change(start, end, tb, tbstart, tbend);
+ } else {
+ int selstart = Selection.getSelectionStart(this);
+ int selend = Selection.getSelectionEnd(this);
- checkRange("replace", start, end);
+ // XXX just make the span fixups in change() do the right thing
+ // instead of this madness!
- change(start, end, tb, tbstart, tbend);
+ checkRange("replace", start, end);
+ moveGapTo(end);
- if (adjustSelection) {
+ if (mGapLength < 2)
+ resizeFor(length() + 1);
+
+ for (int i = mSpanCount - 1; i >= 0; i--) {
+ if (mSpanStarts[i] == mGapStart)
+ mSpanStarts[i]++;
+
+ if (mSpanEnds[i] == mGapStart)
+ mSpanEnds[i]++;
+ }
+
+ mText[mGapStart] = ' ';
+ mGapStart++;
+ mGapLength--;
+
+ if (mGapLength < 1) {
+ new Exception("mGapLength < 1").printStackTrace();
+ }
+
+ change(start + 1, start + 1, tb, tbstart, tbend);
+ change(start, start + 1, "", 0, 0);
+ change(start + newLen, start + newLen + origLen, "", 0, 0);
+
+ /*
+ * Special case to keep the cursor in the same position
+ * if it was somewhere in the middle of the replaced region.
+ * If it was at the start or the end or crossing the whole
+ * replacement, it should already be where it belongs.
+ * TODO: Is there some more general mechanism that could
+ * accomplish this?
+ */
if (selstart > start && selstart < end) {
long off = selstart - start;
- off = off * newLen / origLen;
+ off = off * newLen / (end - start);
selstart = (int) off + start;
setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -449,7 +466,7 @@
if (selend > start && selend < end) {
long off = selend - start;
- off = off * newLen / origLen;
+ off = off * newLen / (end - start);
selend = (int) off + start;
setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
@@ -495,6 +512,11 @@
}
}
+ if (flags == Spanned.SPAN_EXCLUSIVE_EXCLUSIVE && start == end) {
+ throw new IllegalArgumentException(
+ "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+ }
+
if (start > mGapStart) {
start += mGapLength;
} else if (start == mGapStart) {
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index cbb908b..16a13cf 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -42,6 +42,12 @@
}
}
+ GLES20TextureLayer(SurfaceTexture surface, boolean isOpaque) {
+ this(isOpaque);
+ mSurface = surface;
+ mSurface.attachToGLContext(mTexture);
+ }
+
@Override
boolean isValid() {
return mLayer != 0 && mTexture != 0;
@@ -72,6 +78,14 @@
return mSurface;
}
+ void setSurfaceTexture(SurfaceTexture surfaceTexture) {
+ if (mSurface != null) {
+ mSurface.release();
+ }
+ mSurface = surfaceTexture;
+ mSurface.attachToGLContext(mTexture);
+ }
+
@Override
void update(int width, int height, boolean isOpaque) {
super.update(width, height, isOpaque);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 346a933..aa0ac74 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -391,9 +391,9 @@
* @param isOpaque Whether the layer should be opaque or not
*
* @return A hardware layer
- */
+ */
abstract HardwareLayer createHardwareLayer(boolean isOpaque);
-
+
/**
* Creates a new hardware layer.
*
@@ -417,6 +417,15 @@
abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
/**
+ * Sets the {@link android.graphics.SurfaceTexture} that will be used to
+ * render into the specified hardware layer.
+ *
+ * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
+ * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
+ */
+ abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
+
+ /**
* Initializes the hardware renderer for the specified surface and setup the
* renderer for drawing, if needed. This is invoked when the ViewAncestor has
* potentially lost the hardware renderer. The hardware renderer should be
@@ -517,7 +526,7 @@
static final int SURFACE_STATE_SUCCESS = 1;
static final int SURFACE_STATE_UPDATED = 2;
- static final int FUNCTOR_PROCESS_DELAY = 2;
+ static final int FUNCTOR_PROCESS_DELAY = 4;
static EGL10 sEgl;
static EGLDisplay sEglDisplay;
@@ -1345,6 +1354,11 @@
}
@Override
+ void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
+ ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
+ }
+
+ @Override
void destroyLayers(View view) {
if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) {
destroyHardwareLayer(view);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index eb030de..8fe8e40 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,15 +65,6 @@
// Is the device configured to have a full system bar for larger screens?
boolean hasSystemNavBar();
- // These can only be called when injecting events to your own window,
- // or by holding the INJECT_EVENTS permission. These methods may block
- // until pending input events are finished being dispatched even when 'sync' is false.
- // Avoid calling these methods on your UI thread or use the 'NoWait' version instead.
- boolean injectKeyEvent(in KeyEvent ev, boolean sync);
- boolean injectPointerEvent(in MotionEvent ev, boolean sync);
- boolean injectTrackballEvent(in MotionEvent ev, boolean sync);
- boolean injectInputEventNoWait(in InputEvent ev);
-
// These can only be called when holding the MANAGE_APP_TOKENS permission.
void pauseKeyDispatching(IBinder token);
void resumeKeyDispatching(IBinder token);
@@ -128,26 +119,6 @@
void setAnimationScale(int which, float scale);
void setAnimationScales(in float[] scales);
- // These require the READ_INPUT_STATE permission.
- int getSwitchState(int sw);
- int getSwitchStateForDevice(int devid, int sw);
- int getScancodeState(int sw);
- int getScancodeStateForDevice(int devid, int sw);
- int getTrackballScancodeState(int sw);
- int getDPadScancodeState(int sw);
- int getKeycodeState(int sw);
- int getKeycodeStateForDevice(int devid, int sw);
- int getTrackballKeycodeState(int sw);
- int getDPadKeycodeState(int sw);
- InputChannel monitorInput(String inputChannelName);
-
- // Report whether the hardware supports the given keys; returns true if successful
- boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
-
- // Get input device information.
- InputDevice getInputDevice(int deviceId);
- int[] getInputDeviceIds();
-
// For testing
void setInTouchMode(boolean showFocus);
@@ -220,11 +191,6 @@
void statusBarVisibilityChanged(int visibility);
/**
- * Called by the settings application to temporarily set the pointer speed.
- */
- void setPointerSpeed(int speed);
-
- /**
* Block until the given window has been drawn to the screen.
*/
void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 91e47e6..6f8d09b7 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,9 +16,9 @@
package android.view;
+import android.hardware.input.InputManager;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
@@ -41,6 +41,7 @@
public final class InputDevice implements Parcelable {
private int mId;
private String mName;
+ private String mDescriptor;
private int mSources;
private int mKeyboardType;
private String mKeyCharacterMapFile;
@@ -301,13 +302,7 @@
* @return The input device or null if not found.
*/
public static InputDevice getDevice(int id) {
- IWindowManager wm = Display.getWindowManager();
- try {
- return wm.getInputDevice(id);
- } catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get input device information from Window Manager.", ex);
- }
+ return InputManager.getInputDevice(id);
}
/**
@@ -315,13 +310,7 @@
* @return The input device ids.
*/
public static int[] getDeviceIds() {
- IWindowManager wm = Display.getWindowManager();
- try {
- return wm.getInputDeviceIds();
- } catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get input device ids from Window Manager.", ex);
- }
+ return InputManager.getInputDeviceIds();
}
/**
@@ -346,12 +335,24 @@
* An input device descriptor uniquely identifies an input device. Its value
* is intended to be persistent across system restarts, and should not change even
* if the input device is disconnected, reconnected or reconfigured at any time.
+ * </p><p>
+ * It is possible for there to be multiple {@link InputDevice} instances that have the
+ * same input device descriptor. This might happen in situations where a single
+ * human input device registers multiple {@link InputDevice} instances (HID collections)
+ * that describe separate features of the device, such as a keyboard that also
+ * has a trackpad. Alternately, it may be that the input devices are simply
+ * indistinguishable, such as two keyboards made by the same manufacturer.
+ * </p><p>
+ * The input device descriptor returned by {@link #getDescriptor} should only bt
+ * used when an application needs to remember settings associated with a particular
+ * input device. For all other purposes when referring to a logical
+ * {@link InputDevice} instance at runtime use the id returned by {@link #getId()}.
* </p>
*
* @return The input device descriptor.
*/
public String getDescriptor() {
- return "PLACEHOLDER"; // TODO: implement for real
+ return mDescriptor;
}
/**
@@ -560,6 +561,7 @@
private void readFromParcel(Parcel in) {
mId = in.readInt();
mName = in.readString();
+ mDescriptor = in.readString();
mSources = in.readInt();
mKeyboardType = in.readInt();
mKeyCharacterMapFile = in.readString();
@@ -578,6 +580,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mId);
out.writeString(mName);
+ out.writeString(mDescriptor);
out.writeInt(mSources);
out.writeInt(mKeyboardType);
out.writeString(mKeyCharacterMapFile);
@@ -604,7 +607,8 @@
public String toString() {
StringBuilder description = new StringBuilder();
description.append("Input Device ").append(mId).append(": ").append(mName).append("\n");
-
+ description.append(" Descriptor: ").append(mDescriptor).append("\n");
+
description.append(" Keyboard Type: ");
switch (mKeyboardType) {
case KEYBOARD_TYPE_NONE:
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 98cce5efe..b03f086 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -19,10 +19,9 @@
import android.text.method.MetaKeyKeyListener;
import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
-import android.os.RemoteException;
+import android.hardware.input.InputManager;
import android.util.SparseArray;
-import java.io.Reader;
import java.lang.Character;
/**
@@ -528,10 +527,7 @@
* @return True if at least one attached keyboard supports the specified key code.
*/
public static boolean deviceHasKey(int keyCode) {
- int[] codeArray = new int[1];
- codeArray[0] = keyCode;
- boolean[] ret = deviceHasKeys(codeArray);
- return ret[0];
+ return InputManager.deviceHasKeys(new int[] { keyCode })[0];
}
/**
@@ -545,14 +541,7 @@
* at the same index in the key codes array.
*/
public static boolean[] deviceHasKeys(int[] keyCodes) {
- boolean[] ret = new boolean[keyCodes.length];
- IWindowManager wm = Display.getWindowManager();
- try {
- wm.hasKeys(keyCodes, ret);
- } catch (RemoteException e) {
- // no fallback; just return the empty array
- }
- return ret;
+ return InputManager.deviceHasKeys(keyCodes);
}
/**
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 83999a1..3cd8b71 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -115,6 +115,7 @@
private final Object[] mLock = new Object[0];
private boolean mUpdateLayer;
+ private boolean mUpdateSurface;
private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
@@ -208,6 +209,8 @@
private void destroySurface() {
if (mLayer != null) {
+ mSurface.detachFromGLContext();
+
boolean shouldRelease = true;
if (mListener != null) {
shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
@@ -322,9 +325,13 @@
}
mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
- mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
+ if (!mUpdateSurface) {
+ // We already have a SurfaceTexture to use, and we will pass it
+ // to mLayer below.
+ mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
+ }
nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
- nCreateNativeWindow(mSurface);
+ nCreateNativeWindow(mSurface);
mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@Override
@@ -344,6 +351,15 @@
}
}
+ if (mUpdateSurface) {
+ // Someone has requested that we use a specific SurfaceTexture, so
+ // tell mLayer about it and set the SurfaceTexture to use the
+ // current view size.
+ mUpdateSurface = false;
+ mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
+ nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ }
+
applyUpdate();
applyTransformMatrix();
@@ -371,7 +387,7 @@
mUpdateLayer = true;
invalidate();
}
-
+
private void applyUpdate() {
if (mLayer == null) {
return;
@@ -636,6 +652,32 @@
}
/**
+ * Set the {@link SurfaceTexture} for this view to use. If a {@link
+ * SurfaceTexture} is already being used by this view, it is immediately
+ * released and not be usable any more. The {@link
+ * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
+ * called.
+ *
+ * The {@link SurfaceTexture} object must be detached from all OpenGL ES
+ * contexts prior to calling this method.
+ *
+ * @param surfaceTexture The {@link SurfaceTexture} that the view should use.
+ * @see SurfaceTexture#detachFromGLContext()
+ * @hide
+ */
+ public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
+ if (surfaceTexture == null) {
+ throw new NullPointerException("surfaceTexture must not be null");
+ }
+ if (mSurface != null) {
+ mSurface.release();
+ }
+ mSurface = surfaceTexture;
+ mUpdateSurface = true;
+ invalidateParentIfNeeded();
+ }
+
+ /**
* Returns the {@link SurfaceTextureListener} currently associated with this
* texture view.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3c4b866..d62e32f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14414,9 +14414,48 @@
}
/**
- * Request that the visibility of the status bar be changed.
- * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
+ * Request that the visibility of the status bar or other screen/window
+ * decorations be changed.
+ *
+ * <p>This method is used to put the over device UI into temporary modes
+ * where the user's attention is focused more on the application content,
+ * by dimming or hiding surrounding system affordances. This is typically
+ * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY
+ * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content
+ * to be placed behind the action bar (and with these flags other system
+ * affordances) so that smooth transitions between hiding and showing them
+ * can be done.
+ *
+ * <p>Two representative examples of the use of system UI visibility is
+ * implementing a content browsing application (like a magazine reader)
+ * and a video playing application.
+ *
+ * <p>The first code shows a typical implementation of a View in a content
+ * browsing application. In this implementation, the application goes
+ * into a content-oriented mode by hiding the status bar and action bar,
+ * and putting the navigation elements into lights out mode. The user can
+ * then interact with content while in this mode. Such an application should
+ * provide an easy way for the user to toggle out of the mode (such as to
+ * check information in the status bar or access notifications). In the
+ * implementation here, this is done simply by tapping on the content.
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java
+ * content}
+ *
+ * <p>This second code sample shows a typical implementation of a View
+ * in a video playing application. In this situation, while the video is
+ * playing the application would like to go into a complete full-screen mode,
+ * to use as much of the display as possible for the video. When in this state
+ * the user can not interact with the application; the system intercepts
+ * touching on the screen to pop the UI out of full screen mode.
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java
+ * content}
+ *
+ * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
+ * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
+ * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
*/
public void setSystemUiVisibility(int visibility) {
if (visibility != mSystemUiVisibility) {
@@ -14428,9 +14467,11 @@
}
/**
- * Returns the status bar visibility that this view has requested.
- * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
+ * Returns the last {@link #setSystemUiVisibility(int) that this view has requested.
+ * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
+ * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
+ * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
*/
public int getSystemUiVisibility() {
return mSystemUiVisibility;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index cf9cafc..491cd67 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -349,6 +349,10 @@
* between it and the policy.
*/
public interface WindowManagerFuncs {
+ public static final int LID_ABSENT = -1;
+ public static final int LID_CLOSED = 0;
+ public static final int LID_OPEN = 1;
+
/**
* Ask the window manager to re-evaluate the system UI flags.
*/
@@ -362,6 +366,16 @@
InputEventReceiver.Factory inputEventReceiverFactory,
String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
boolean hasFocus, boolean touchFullscreen);
+
+ /**
+ * Returns a code that describes the current state of the lid switch.
+ */
+ public int getLidState();
+
+ /**
+ * Creates an input channel that will receive all input from the input dispatcher.
+ */
+ public InputChannel monitorInput(String name);
}
/**
@@ -943,10 +957,10 @@
public void setRotationLw(int rotation);
/**
- * Called when the system is mostly done booting to determine whether
+ * Called when the system is mostly done booting to set whether
* the system should go into safe mode.
*/
- public boolean detectSafeMode();
+ public void setSafeMode(boolean safeMode);
/**
* Called when the system is mostly done booting.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 17dbde8..067be39 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -405,7 +405,9 @@
}
// Check focus again in case that "onWindowFocus" is called before
// handling this message.
- checkFocus(mHasBeenInactive);
+ if (mServedView != null && mServedView.hasWindowFocus()) {
+ checkFocus(mHasBeenInactive);
+ }
}
}
return;
@@ -1202,7 +1204,9 @@
}
if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
+ " next=" + mNextServedView
- + " forceNewFocus=" + forceNewFocus);
+ + " forceNewFocus=" + forceNewFocus
+ + " package="
+ + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>"));
if (mNextServedView == null) {
finishInputLocked();
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 137743a..d05c1af 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -45,6 +45,7 @@
private final ResolveInfo mService;
private final String mId;
private final int mLabel;
+ private final boolean mSupportsSentenceSpellCheck;
/**
* The spell checker setting activity's name, used by the system settings to
@@ -97,6 +98,9 @@
label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.SpellChecker_settingsActivity);
+ mSupportsSentenceSpellCheck = sa.getBoolean(
+ com.android.internal.R.styleable.SpellChecker_supportsSentenceSpellCheck,
+ false);
sa.recycle();
final int depth = parser.getDepth();
@@ -138,6 +142,7 @@
*/
public SpellCheckerInfo(Parcel source) {
mLabel = source.readInt();
+ mSupportsSentenceSpellCheck = source.readInt() != 0;
mId = source.readString();
mSettingsActivityName = source.readString();
mService = ResolveInfo.CREATOR.createFromParcel(source);
@@ -152,6 +157,12 @@
return mId;
}
+ /**
+ * @hide
+ */
+ public boolean isSentenceSpellCheckSupported() {
+ return mSupportsSentenceSpellCheck;
+ }
/**
* Return the component of the service that implements.
@@ -177,6 +188,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mLabel);
+ dest.writeInt(mSupportsSentenceSpellCheck ? 1 : 0);
dest.writeString(mId);
dest.writeString(mSettingsActivityName);
mService.writeToParcel(dest, flags);
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 35940ba..9dc05e4 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -436,15 +436,15 @@
*/
public interface SpellCheckerSessionListener {
/**
- * Callback for {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
+ * Callback for {@link SpellCheckerSession#getSuggestions(TextInfo, int)}
+ * and {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
* @param results an array of {@link SuggestionsInfo}s.
* These results are suggestions for {@link TextInfo}s queried by
- * {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}.
+ * {@link SpellCheckerSession#getSuggestions(TextInfo, int)} or
+ * {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
*/
public void onGetSuggestions(SuggestionsInfo[] results);
- // TODO: Remove @hide as soon as the sample spell checker client gets fixed.
/**
- * @hide
* Callback for {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)}
* @param results an array of {@link SentenceSuggestionsInfo}s.
* These results are suggestions for {@link TextInfo}s
@@ -494,7 +494,7 @@
}
/**
- * @hide
+ * @return true if the spell checker supports sentence level spell checking APIs
*/
public boolean isSentenceSpellCheckSupported() {
return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK);
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 6c331ac..6b7263c 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -148,8 +148,8 @@
mInput.showSoftInput(mEditText, 0);
}
- public void updateMatchCount(int matchIndex, int matchCount, boolean isNewFind) {
- if (!isNewFind) {
+ public void updateMatchCount(int matchIndex, int matchCount, boolean isEmptyFind) {
+ if (!isEmptyFind) {
mNumberOfMatches = matchCount;
mActiveMatchIndex = matchIndex;
updateMatchesString();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9492e38..84632c6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -313,7 +313,6 @@
/**
* Interface to listen for find results.
- * @hide
*/
public interface FindListener {
/**
@@ -1249,8 +1248,7 @@
* Register the listener to be notified as find-on-page operations progress.
* This will replace the current listener.
*
- * @param listener An implementation of {@link WebView#FindListener}.
- * @hide
+ * @param listener An implementation of {@link FindListener}.
*/
public void setFindListener(FindListener listener) {
checkThread();
@@ -1258,11 +1256,15 @@
}
/**
- * Highlight and scroll to the next occurance of String in findAll.
- * Wraps the page infinitely, and scrolls. Must be called after
- * calling findAll.
+ * Highlight and scroll to the next match found by {@link #findAll} or
+ * {@link #findAllAsync}, wrapping around page boundaries as necessary.
+ * Notifies any registered {@link FindListener}. If neither
+ * {@link #findAll} nor {@link #findAllAsync(String)} has been called yet,
+ * or if {@link #clearMatches} has been called since the last find
+ * operation, this function does nothing.
*
* @param forward Direction to search.
+ * @see #setFindListener
*/
public void findNext(boolean forward) {
checkThread();
@@ -1271,10 +1273,13 @@
/**
* Find all instances of find on the page and highlight them.
+ * Notifies any registered {@link FindListener}.
*
* @param find String to find.
* @return int The number of occurances of the String "find"
* that were found.
+ * @deprecated {@link #findAllAsync} is preferred.
+ * @see #setFindListener
*/
public int findAll(String find) {
checkThread();
@@ -1283,10 +1288,12 @@
/**
* Find all instances of find on the page and highlight them,
- * asynchronously.
+ * asynchronously. Notifies any registered {@link FindListener}.
+ * Successive calls to this or {@link #findAll} will cancel any
+ * pending searches.
*
* @param find String to find.
- * @hide
+ * @see #setFindListener
*/
public void findAllAsync(String find) {
checkThread();
@@ -1333,8 +1340,9 @@
return getFactory().getStatics().findAddress(addr);
}
- /*
- * Clear the highlighting surrounding text matches created by findAll.
+ /**
+ * Clear the highlighting surrounding text matches created by
+ * {@link #findAll} or {@link #findAllAsync}.
*/
public void clearMatches() {
checkThread();
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 4c118ac..8dc3b7e 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -461,6 +461,7 @@
selectionStart = Math.min(selectionStart, editable.length());
selectionEnd = Math.min(selectionEnd, editable.length());
setSelection(selectionStart, selectionEnd);
+ finishComposingText();
}
public void replaceSelection(CharSequence text) {
@@ -3588,7 +3589,9 @@
@Override
public void findNext(boolean forward) {
if (0 == mNativeClass) return; // client isn't initialized
- mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0);
+ if (mFindRequest != null) {
+ mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0, mFindRequest);
+ }
}
/**
@@ -3605,28 +3608,26 @@
private int findAllBody(String find, boolean isAsync) {
if (0 == mNativeClass) return 0; // client isn't initialized
- mLastFind = find;
+ mFindRequest = null;
if (find == null) return 0;
mWebViewCore.removeMessages(EventHub.FIND_ALL);
- WebViewCore.FindAllRequest request = new
- WebViewCore.FindAllRequest(find);
+ mFindRequest = new WebViewCore.FindAllRequest(find);
if (isAsync) {
- mWebViewCore.sendMessage(EventHub.FIND_ALL, request);
+ mWebViewCore.sendMessage(EventHub.FIND_ALL, mFindRequest);
return 0; // no need to wait for response
}
- synchronized(request) {
+ synchronized(mFindRequest) {
try {
- mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL,
- request);
- while (request.mMatchCount == -1) {
- request.wait();
+ mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL, mFindRequest);
+ while (mFindRequest.mMatchCount == -1) {
+ mFindRequest.wait();
}
}
catch (InterruptedException e) {
return 0;
}
+ return mFindRequest.mMatchCount;
}
- return request.mMatchCount;
}
/**
@@ -3657,7 +3658,7 @@
return true;
}
if (text == null) {
- text = mLastFind;
+ text = mFindRequest == null ? null : mFindRequest.mSearchText;
}
if (text != null) {
mFindCallback.setText(text);
@@ -3683,9 +3684,8 @@
// or not we draw the highlights for matches.
private boolean mFindIsUp;
- // Keep track of the last string sent, so we can search again when find is
- // reopened.
- private String mLastFind;
+ // Keep track of the last find request sent.
+ private WebViewCore.FindAllRequest mFindRequest = null;
/**
* Return the first substring consisting of the address of a physical
@@ -8476,13 +8476,27 @@
}
case UPDATE_MATCH_COUNT: {
- boolean isNewFind = mLastFind == null || !mLastFind.equals(msg.obj);
- if (mFindCallback != null)
- mFindCallback.updateMatchCount(msg.arg1, msg.arg2, isNewFind);
- if (mFindListener != null)
- mFindListener.onFindResultReceived(msg.arg1, msg.arg2, true);
+ WebViewCore.FindAllRequest request = (WebViewCore.FindAllRequest)msg.obj;
+ if (request == null) {
+ if (mFindCallback != null) {
+ mFindCallback.updateMatchCount(0, 0, true);
+ }
+ } else if (request == mFindRequest) {
+ int matchCount, matchIndex;
+ synchronized (mFindRequest) {
+ matchCount = request.mMatchCount;
+ matchIndex = request.mMatchIndex;
+ }
+ if (mFindCallback != null) {
+ mFindCallback.updateMatchCount(matchIndex, matchCount, false);
+ }
+ if (mFindListener != null) {
+ mFindListener.onFindResultReceived(matchIndex, matchCount, true);
+ }
+ }
break;
}
+
case CLEAR_CARET_HANDLE:
selectionDone();
break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b4ebc09..5549d89 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1041,9 +1041,11 @@
public FindAllRequest(String text) {
mSearchText = text;
mMatchCount = -1;
+ mMatchIndex = -1;
}
- public String mSearchText;
+ public final String mSearchText;
public int mMatchCount;
+ public int mMatchIndex;
}
/**
@@ -1777,21 +1779,32 @@
nativeSelectAll(mNativeClass);
break;
case FIND_ALL: {
- FindAllRequest request = (FindAllRequest) msg.obj;
- if (request == null) {
- nativeFindAll(mNativeClass, null);
- } else {
- request.mMatchCount = nativeFindAll(
- mNativeClass, request.mSearchText);
- synchronized(request) {
+ FindAllRequest request = (FindAllRequest)msg.obj;
+ if (request != null) {
+ int matchCount = nativeFindAll(mNativeClass, request.mSearchText);
+ int matchIndex = nativeFindNext(mNativeClass, true);
+ synchronized (request) {
+ request.mMatchCount = matchCount;
+ request.mMatchIndex = matchIndex;
request.notify();
}
+ } else {
+ nativeFindAll(mNativeClass, null);
}
+ Message.obtain(mWebViewClassic.mPrivateHandler,
+ WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
break;
}
- case FIND_NEXT:
- nativeFindNext(mNativeClass, msg.arg1 != 0);
+ case FIND_NEXT: {
+ FindAllRequest request = (FindAllRequest)msg.obj;
+ int matchIndex = nativeFindNext(mNativeClass, msg.arg1 != 0);
+ synchronized (request) {
+ request.mMatchIndex = matchIndex;
+ }
+ Message.obtain(mWebViewClassic.mPrivateHandler,
+ WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
break;
+ }
}
}
};
@@ -2825,17 +2838,6 @@
.sendToTarget();
}
- // called by JNI
- private void updateMatchCount(int matchIndex, int matchCount,
- String findText) {
- if (mWebViewClassic == null) {
- return;
- }
- Message.obtain(mWebViewClassic.mPrivateHandler,
- WebViewClassic.UPDATE_MATCH_COUNT, matchIndex, matchCount,
- findText).sendToTarget();
- }
-
private native void nativeRevealSelection(int nativeClass);
private native String nativeRequestLabel(int nativeClass, int framePtr,
int nodePtr);
@@ -3086,7 +3088,7 @@
private native void nativeAutoFillForm(int nativeClass, int queryId);
private native void nativeScrollLayer(int nativeClass, int layer, Rect rect);
private native int nativeFindAll(int nativeClass, String text);
- private native void nativeFindNext(int nativeClass, boolean forward);
+ private native int nativeFindNext(int nativeClass, boolean forward);
/**
* Deletes editable text between two points. Note that the selection may
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 9c9eb4b..b7a126e 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -248,7 +248,6 @@
}
}
setText(text);
- Slog.v("Chronometer", "updateText: sec=" + seconds + " mFormat=" + mFormat + " text=" + text);
}
private void updateRunning() {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index e00fe9f..af67d55 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -340,8 +340,12 @@
final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
+ final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
+ (ActionMenuItemView) child : null;
+ final boolean hasText = itemView != null && itemView.hasText();
+
int cellsUsed = 0;
- if (cellsRemaining > 0) {
+ if (cellsRemaining > 0 && (!hasText || cellsRemaining >= 2)) {
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
cellSize * cellsRemaining, MeasureSpec.AT_MOST);
child.measure(childWidthSpec, childHeightSpec);
@@ -349,11 +353,10 @@
final int measuredWidth = child.getMeasuredWidth();
cellsUsed = measuredWidth / cellSize;
if (measuredWidth % cellSize != 0) cellsUsed++;
+ if (hasText && cellsUsed < 2) cellsUsed = 2;
}
- final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
- (ActionMenuItemView) child : null;
- final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText();
+ final boolean expandable = !lp.isOverflowButton && hasText;
lp.expandable = expandable;
lp.cellsUsed = cellsUsed;
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 8521481..d1652df 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -18,14 +18,11 @@
import com.android.internal.app.ActionBarImpl;
-import android.animation.LayoutTransition;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
-import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
/**
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 3d350ed..244b166 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -218,6 +218,18 @@
return surfaceTexture->updateTexImage();
}
+static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
+{
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ return surfaceTexture->detachFromContext();
+}
+
+static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
+{
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ return surfaceTexture->attachToContext((GLuint)tex);
+}
+
static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
jfloatArray jmtx)
{
@@ -242,14 +254,16 @@
// ----------------------------------------------------------------------------
static JNINativeMethod gSurfaceTextureMethods[] = {
- {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
- {"nativeInit", "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
- {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
+ {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
+ {"nativeInit", "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
+ {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
{"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
- {"nativeUpdateTexImage", "()I", (void*)SurfaceTexture_updateTexImage },
- {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
- {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp },
- {"nativeRelease", "()V", (void*)SurfaceTexture_release },
+ {"nativeUpdateTexImage", "()I", (void*)SurfaceTexture_updateTexImage },
+ {"nativeDetachFromGLContext", "()I", (void*)SurfaceTexture_detachFromGLContext },
+ {"nativeAttachToGLContext", "(I)I", (void*)SurfaceTexture_attachToGLContext },
+ {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
+ {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp },
+ {"nativeRelease", "()V", (void*)SurfaceTexture_release },
};
int register_android_graphics_SurfaceTexture(JNIEnv* env)
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 655a834..19bc154 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -416,8 +416,8 @@
if (env != NULL && clazz != NULL) {
env->DeleteGlobalRef(clazz);
}
- if (looper != NULL && mainWorkRead >= 0) {
- looper->removeFd(mainWorkRead);
+ if (messageQueue != NULL && mainWorkRead >= 0) {
+ messageQueue->getLooper()->removeFd(mainWorkRead);
}
if (nativeInputQueue != NULL) {
nativeInputQueue->mWorkWrite = -1;
@@ -481,7 +481,7 @@
// These are used to wake up the main thread to process work.
int mainWorkRead;
int mainWorkWrite;
- sp<Looper> looper;
+ sp<MessageQueue> messageQueue;
};
void android_NativeActivity_finish(ANativeActivity* activity) {
@@ -515,16 +515,6 @@
// ------------------------------------------------------------------------
-static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
- if (env->ExceptionCheck()) {
- ALOGE("An exception was thrown by callback '%s'.", methodName);
- LOGE_EX(env);
- env->ExceptionClear();
- return true;
- }
- return false;
-}
-
/*
* Callback for handling native events on the application's main thread.
*/
@@ -551,7 +541,8 @@
if (inputEventObj) {
handled = code->env->CallBooleanMethod(code->clazz,
gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
- checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
+ code->messageQueue->raiseAndClearException(
+ code->env, "dispatchUnhandledKeyEvent");
code->env->DeleteLocalRef(inputEventObj);
} else {
ALOGE("Failed to obtain key event for dispatchUnhandledKeyEvent.");
@@ -566,7 +557,7 @@
if (inputEventObj) {
code->env->CallVoidMethod(code->clazz,
gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
- checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
+ code->messageQueue->raiseAndClearException(code->env, "preDispatchKeyEvent");
code->env->DeleteLocalRef(inputEventObj);
} else {
ALOGE("Failed to obtain key event for preDispatchKeyEvent.");
@@ -575,27 +566,27 @@
} break;
case CMD_FINISH: {
code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.finish);
- checkAndClearExceptionFromCallback(code->env, "finish");
+ code->messageQueue->raiseAndClearException(code->env, "finish");
} break;
case CMD_SET_WINDOW_FORMAT: {
code->env->CallVoidMethod(code->clazz,
gNativeActivityClassInfo.setWindowFormat, work.arg1);
- checkAndClearExceptionFromCallback(code->env, "setWindowFormat");
+ code->messageQueue->raiseAndClearException(code->env, "setWindowFormat");
} break;
case CMD_SET_WINDOW_FLAGS: {
code->env->CallVoidMethod(code->clazz,
gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
- checkAndClearExceptionFromCallback(code->env, "setWindowFlags");
+ code->messageQueue->raiseAndClearException(code->env, "setWindowFlags");
} break;
case CMD_SHOW_SOFT_INPUT: {
code->env->CallVoidMethod(code->clazz,
gNativeActivityClassInfo.showIme, work.arg1);
- checkAndClearExceptionFromCallback(code->env, "showIme");
+ code->messageQueue->raiseAndClearException(code->env, "showIme");
} break;
case CMD_HIDE_SOFT_INPUT: {
code->env->CallVoidMethod(code->clazz,
gNativeActivityClassInfo.hideIme, work.arg1);
- checkAndClearExceptionFromCallback(code->env, "hideIme");
+ code->messageQueue->raiseAndClearException(code->env, "hideIme");
} break;
default:
ALOGW("Unknown work command: %d", work.cmd);
@@ -634,9 +625,9 @@
return 0;
}
- code->looper = android_os_MessageQueue_getLooper(env, messageQueue);
- if (code->looper == NULL) {
- ALOGW("Unable to retrieve MessageQueue's Looper");
+ code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue);
+ if (code->messageQueue == NULL) {
+ ALOGW("Unable to retrieve native MessageQueue");
delete code;
return 0;
}
@@ -655,7 +646,8 @@
result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
SLOGW_IF(result != 0, "Could not make main work write pipe "
"non-blocking: %s", strerror(errno));
- code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
+ code->messageQueue->getLooper()->addFd(
+ code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
code->ANativeActivity::callbacks = &code->callbacks;
if (env->GetJavaVM(&code->vm) < 0) {
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 12a77d5..a4dcac6 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "MessageQueue-JNI"
#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
#include <utils/Looper.h>
#include <utils/Log.h>
@@ -24,31 +25,46 @@
namespace android {
-// ----------------------------------------------------------------------------
-
static struct {
jfieldID mPtr; // native object attached to the DVM MessageQueue
} gMessageQueueClassInfo;
-// ----------------------------------------------------------------------------
-class NativeMessageQueue {
+class NativeMessageQueue : public MessageQueue {
public:
NativeMessageQueue();
- ~NativeMessageQueue();
+ virtual ~NativeMessageQueue();
- inline sp<Looper> getLooper() { return mLooper; }
+ virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
- void pollOnce(int timeoutMillis);
+ void pollOnce(JNIEnv* env, int timeoutMillis);
+
void wake();
private:
- sp<Looper> mLooper;
+ bool mInCallback;
+ jthrowable mExceptionObj;
};
-// ----------------------------------------------------------------------------
-NativeMessageQueue::NativeMessageQueue() {
+MessageQueue::MessageQueue() {
+}
+
+MessageQueue::~MessageQueue() {
+}
+
+bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
+ jthrowable exceptionObj = env->ExceptionOccurred();
+ if (exceptionObj) {
+ env->ExceptionClear();
+ raiseException(env, msg, exceptionObj);
+ env->DeleteLocalRef(exceptionObj);
+ return true;
+ }
+ return false;
+}
+
+NativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
@@ -59,8 +75,32 @@
NativeMessageQueue::~NativeMessageQueue() {
}
-void NativeMessageQueue::pollOnce(int timeoutMillis) {
+void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) {
+ if (exceptionObj) {
+ if (mInCallback) {
+ if (mExceptionObj) {
+ env->DeleteLocalRef(mExceptionObj);
+ }
+ mExceptionObj = jthrowable(env->NewLocalRef(exceptionObj));
+ ALOGE("Exception in MessageQueue callback: %s", msg);
+ jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
+ } else {
+ ALOGE("Exception: %s", msg);
+ jniLogException(env, ANDROID_LOG_ERROR, LOG_TAG, exceptionObj);
+ LOG_ALWAYS_FATAL("raiseException() was called when not in a callback, exiting.");
+ }
+ }
+}
+
+void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
+ mInCallback = true;
mLooper->pollOnce(timeoutMillis);
+ mInCallback = false;
+ if (mExceptionObj) {
+ env->Throw(mExceptionObj);
+ env->DeleteLocalRef(mExceptionObj);
+ mExceptionObj = NULL;
+ }
}
void NativeMessageQueue::wake() {
@@ -81,19 +121,20 @@
reinterpret_cast<jint>(nativeMessageQueue));
}
-sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj) {
+sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
NativeMessageQueue* nativeMessageQueue =
android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj);
- return nativeMessageQueue != NULL ? nativeMessageQueue->getLooper() : NULL;
+ return nativeMessageQueue;
}
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
- if (! nativeMessageQueue) {
+ if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return;
}
+ nativeMessageQueue->incStrong(env);
android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
}
@@ -102,7 +143,7 @@
android_os_MessageQueue_getNativeMessageQueue(env, obj);
if (nativeMessageQueue) {
android_os_MessageQueue_setNativeMessageQueue(env, obj, NULL);
- delete nativeMessageQueue;
+ nativeMessageQueue->decStrong(env);
}
}
@@ -113,7 +154,7 @@
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jint ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
- nativeMessageQueue->pollOnce(timeoutMillis);
+ nativeMessageQueue->pollOnce(env, timeoutMillis);
}
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jobject obj, jint ptr) {
diff --git a/core/jni/android_os_MessageQueue.h b/core/jni/android_os_MessageQueue.h
index f961d8f..49d2aa0 100644
--- a/core/jni/android_os_MessageQueue.h
+++ b/core/jni/android_os_MessageQueue.h
@@ -18,12 +18,53 @@
#define _ANDROID_OS_MESSAGEQUEUE_H
#include "jni.h"
+#include <utils/Looper.h>
namespace android {
-class Looper;
+class MessageQueue : public RefBase {
+public:
+ /* Gets the message queue's looper. */
+ inline sp<Looper> getLooper() const {
+ return mLooper;
+ }
-extern sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj);
+ /* Checks whether the JNI environment has a pending exception.
+ *
+ * If an exception occurred, logs it together with the specified message,
+ * and calls raiseException() to ensure the exception will be raised when
+ * the callback returns, clears the pending exception from the environment,
+ * then returns true.
+ *
+ * If no exception occurred, returns false.
+ */
+ bool raiseAndClearException(JNIEnv* env, const char* msg);
+
+ /* Raises an exception from within a callback function.
+ * The exception will be rethrown when control returns to the message queue which
+ * will typically cause the application to crash.
+ *
+ * This message can only be called from within a callback function. If it is called
+ * at any other time, the process will simply be killed.
+ *
+ * Does nothing if exception is NULL.
+ *
+ * (This method does not take ownership of the exception object reference.
+ * The caller is responsible for releasing its reference when it is done.)
+ */
+ virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) = 0;
+
+protected:
+ MessageQueue();
+ virtual ~MessageQueue();
+
+protected:
+ sp<Looper> mLooper;
+};
+
+/* Gets the native object associated with a MessageQueue. */
+extern sp<MessageQueue> android_os_MessageQueue_getMessageQueue(
+ JNIEnv* env, jobject messageQueueObj);
} // namespace android
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 72c171c..d80bfb3 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -45,7 +45,7 @@
class NativeDisplayEventReceiver : public RefBase {
public:
NativeDisplayEventReceiver(JNIEnv* env,
- jobject receiverObj, const sp<Looper>& looper);
+ jobject receiverObj, const sp<MessageQueue>& messageQueue);
status_t initialize();
status_t scheduleVsync();
@@ -55,7 +55,7 @@
private:
jobject mReceiverObjGlobal;
- sp<Looper> mLooper;
+ sp<MessageQueue> mMessageQueue;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
@@ -65,9 +65,9 @@
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
- jobject receiverObj, const sp<Looper>& looper) :
+ jobject receiverObj, const sp<MessageQueue>& messageQueue) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mLooper(looper), mWaitingForVsync(false) {
+ mMessageQueue(messageQueue), mWaitingForVsync(false) {
ALOGV("receiver %p ~ Initializing input event receiver.", this);
}
@@ -75,7 +75,7 @@
ALOGV("receiver %p ~ Disposing display event receiver.", this);
if (!mReceiver.initCheck()) {
- mLooper->removeFd(mReceiver.getFd());
+ mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -89,7 +89,7 @@
return result;
}
- int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
+ int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
handleReceiveCallback, this);
if (rc < 0) {
return UNKNOWN_ERROR;
@@ -151,12 +151,7 @@
gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
ALOGV("receiver %p ~ Returned from vsync handler.", data);
- if (env->ExceptionCheck()) {
- ALOGE("An exception occurred while dispatching a vsync event.");
- LOGE_EX(env);
- env->ExceptionClear();
- }
-
+ r->mMessageQueue->raiseAndClearException(env, "dispatchVsync");
return 1; // keep the callback
}
@@ -183,14 +178,14 @@
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
jobject messageQueueObj) {
- sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
- if (looper == NULL) {
+ sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
+ if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
- receiverObj, looper);
+ receiverObj, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index e7d4244..348437d 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -48,7 +48,7 @@
public:
NativeInputEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<InputChannel>& inputChannel,
- const sp<Looper>& looper);
+ const sp<MessageQueue>& messageQueue);
status_t initialize();
status_t finishInputEvent(uint32_t seq, bool handled);
@@ -61,7 +61,7 @@
private:
jobject mReceiverObjGlobal;
InputConsumer mInputConsumer;
- sp<Looper> mLooper;
+ sp<MessageQueue> mMessageQueue;
PreallocatedInputEventFactory mInputEventFactory;
bool mBatchedInputEventPending;
@@ -72,9 +72,10 @@
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
- jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
+ jobject receiverObj, const sp<InputChannel>& inputChannel,
+ const sp<MessageQueue>& messageQueue) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mInputConsumer(inputChannel), mLooper(looper),
+ mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
@@ -86,7 +87,7 @@
ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
#endif
- mLooper->removeFd(mInputConsumer.getChannel()->getFd());
+ mMessageQueue->getLooper()->removeFd(mInputConsumer.getChannel()->getFd());
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mReceiverObjGlobal);
@@ -94,7 +95,8 @@
status_t NativeInputEventReceiver::initialize() {
int receiveFd = mInputConsumer.getChannel()->getFd();
- mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+ mMessageQueue->getLooper()->addFd(
+ receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
return OK;
}
@@ -157,12 +159,8 @@
#endif
env->CallVoidMethod(mReceiverObjGlobal,
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
-
- if (env->ExceptionCheck()) {
- ALOGE("channel '%s' ~ An exception occurred while dispatching that "
- "batched input events are pending.", getInputChannelName());
- LOGE_EX(env);
- env->ExceptionClear();
+ if (mMessageQueue->raiseAndClearException(
+ env, "dispatchBatchedInputEventPending")) {
mBatchedInputEventPending = false; // try again later
}
}
@@ -182,6 +180,7 @@
#endif
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
+ mMessageQueue->raiseAndClearException(env, "new KeyEvent");
break;
case AINPUT_EVENT_TYPE_MOTION:
@@ -190,6 +189,7 @@
#endif
inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
static_cast<MotionEvent*>(inputEvent));
+ mMessageQueue->raiseAndClearException(env, "new MotionEvent");
break;
default:
@@ -200,7 +200,7 @@
if (!inputEventObj) {
ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
mInputConsumer.sendFinishedSignal(seq, false);
- return NO_MEMORY;
+ continue;
}
#if DEBUG_DISPATCH_CYCLE
@@ -211,14 +211,8 @@
env->DeleteLocalRef(inputEventObj);
- if (env->ExceptionCheck()) {
- ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
- getInputChannelName());
- LOGE_EX(env);
- env->ExceptionClear();
-
+ if (mMessageQueue->raiseAndClearException(env, "dispatchInputEvent")) {
mInputConsumer.sendFinishedSignal(seq, false);
- return OK;
}
}
}
@@ -233,14 +227,14 @@
return 0;
}
- sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
- if (looper == NULL) {
+ sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
+ if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
- receiverObj, inputChannel, looper);
+ receiverObj, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5ae12b6..00faa41 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1200,7 +1200,8 @@
android:protectionLevel="signature|system" />
<!-- Allows an application to retrieve the current state of keys and
- switches. This is only for use by the system.-->
+ switches. This is only for use by the system.
+ @deprecated The API that used this permission has been removed. -->
<permission android:name="android.permission.READ_INPUT_STATE"
android:label="@string/permlab_readInputState"
android:description="@string/permdesc_readInputState"
diff --git a/core/res/res/layout/action_mode_close_item.xml b/core/res/res/layout/action_mode_close_item.xml
index ac5af70..8cd0cdd 100644
--- a/core/res/res/layout/action_mode_close_item.xml
+++ b/core/res/res/layout/action_mode_close_item.xml
@@ -19,6 +19,7 @@
android:focusable="true"
android:clickable="true"
android:paddingLeft="8dip"
+ android:contentDescription="@string/action_mode_done"
style="?android:attr/actionModeCloseButtonStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
index 54fde70..785da7c 100644
--- a/core/res/res/layout/notification_action.xml
+++ b/core/res/res/layout/notification_action.xml
@@ -19,5 +19,5 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@android:style/Widget.Holo.Button.Small"
- android:gravity="left"
+ android:gravity="left|center_vertical"
/>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d6073e3..f23c7e2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Stel tyd"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Stel datum"</string>
<string name="date_time_set" msgid="5777075614321087758">"Stel"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Klaar"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Verstek"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NUUT: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Geen toestemmings benodig nie"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Voeg \'n rekening by"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Watter rekening wil jy gebruik?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Voeg rekening by"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Vermeerder"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Verminder"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> raak en hou."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Gly op om te vermeeder en af om te verminder."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Vermeerder minuut"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Verminder minute"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Vermeerder uur"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Verminder uur"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Stel NM."</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Stel VM."</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Vermeerder maand"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Verminder maand"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Vermeerder dag"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Verminder dag"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Vermeerder jaar"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Verminder jaar"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"gekontroleer"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"nie gekontroleer nie"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"gekies"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Deel met"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Deel met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Skyfievatsel. Raak en hou."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Gly af vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Gly links vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Gly regs vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Ontsluit"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Stil"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Klank aan"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Soek"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Sleep om te ontsluit."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Prop \'n kopfoon in om te hoor hoe wagwoordsleutels hardop gesê word."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punt."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2b98607..b0218dd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"ጊዜ አዘጋጅ"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"ውሂብ አዘጋጅ"</string>
<string name="date_time_set" msgid="5777075614321087758">"አዘጋጅ"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"ተጠናቋል"</string>
<string name="default_permission_group" msgid="2690160991405646128">"ነባሪ"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"አዲስ፦ "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"መለያ አክል"</string>
<string name="choose_account_text" msgid="6303348737197849675">"የትኛውን መለያ መጠቀም ትፈልጋለህ?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"መለያ አክል"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"ጨምር"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"ቀንስ"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> ንካ እና ያዝ።"</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"ለመጨመር ወደ ላይ አንሸራትት እና ለመቀነስ ወደ ታች አንሸራትት።"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"ደቂቃ ጨምር"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"ደቂቃ ቀንስ"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"ሰዓት ጨምር"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"ሰዓት ቀንስ"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"PM አዘጋጅ"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"AM አዘጋጅ"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"ወር ጨምር"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"ወር ቀንስ"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"ቀን ጨምር"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ቀን ቀንስ"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"ታይቷል"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"አልተፈተሸም"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"የተመረጠ"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"ተጋራ ከ"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ከ <xliff:g id="APPLICATION_NAME">%s</xliff:g> ጋር ተጋራ"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"ባለስላይድ መያዣ፡፡ ዳስ&ያዝ፡፡"</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ታች አንሸራትት።"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ግራ አንሸራትት።"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ቀኝ አንሸራትት።"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"ክፈት"</string>
<string name="description_target_camera" msgid="969071997552486814">"ካሜራ"</string>
<string name="description_target_silent" msgid="893551287746522182">"ፀጥታ"</string>
<string name="description_target_soundon" msgid="30052466675500172">"ድምፅ አብራ"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ፈልግ"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"ላለመቆለፍ አንሸራት፡፡"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"የይለፍ ቃል ቁልፎች ሲነገሩ ለመስማት የጆሮ ማዳመጫ ሰካ።"</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"ነጥብ."</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9c3ef5e..9c3d658 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"تعيين الوقت"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"تعيين التاريخ"</string>
<string name="date_time_set" msgid="5777075614321087758">"تعيين"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"تم"</string>
<string name="default_permission_group" msgid="2690160991405646128">"افتراضي"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"جديد: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"لا أذونات مطلوبة"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"إضافة حساب"</string>
<string name="choose_account_text" msgid="6303348737197849675">"ما الحساب الذي تريد استخدامه؟"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"إضافة حساب"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"زيادة"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"تقليل"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> المس مع الاستمرار."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"مرر لأعلى للزيادة ولأسفل للتقليل."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"زيادة الدقائق"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"تقليل الدقائق"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"زيادة الساعات"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"تقليل الساعات"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"تعيين المساء"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"تعيين الصباح"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"زيادة الشهور"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"تقليل الشهور"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"زيادة الأيام"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"تقليل الأيام"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"زيادة الأعوام"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"تقليل الأعوام"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"تم التحديد"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"لم يتم التحديد"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"محدد"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"مشاركة مع"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"مشاركة مع <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"مقبض التمرير. المس مع الاستمرار."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"تمرير لأسفل لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"تمرير لليسار لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"تمرير لليمين لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"إلغاء تأمين"</string>
<string name="description_target_camera" msgid="969071997552486814">"الكاميرا"</string>
<string name="description_target_silent" msgid="893551287746522182">"صامت"</string>
<string name="description_target_soundon" msgid="30052466675500172">"تشغيل الصوت"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"مرر بسرعة لإلغاء التأمين."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"يمكنك توصيل سماعة رأس لسماع مفاتيح كلمة المرور عندما يتم نطقها."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"نقطة"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index dcb8f05..9aab752 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Усталяваць час"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Усталяваць дату"</string>
<string name="date_time_set" msgid="5777075614321087758">"Задаць"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Гатова"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Па змаўчанні"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"НОВАЕ: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Дадаць уліковы запіс"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Які ўліковы запіс вы жадаеце выкарыстоўваць?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Дадаць уліковы запіс"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Павялічыць"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Паменшыць"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Націсніце і ўтрымлівайце <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Правядзіце пальцам уверх, каб павялічыць, або ўніз, каб паменшыць."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Павялічыць лічбу хвілін."</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Паменшыць лічбу хвілін."</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Павялічыць лічбу гадзін."</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Паменшыць лічбу гадзін."</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Усталяваць час пасля паўдня"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Усталяваць час да паўдня"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Павялічыць лічбу месяца"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Паменшыць лічбу месяца"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Павялічыць лічбу дня"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Паменшыць лічбу дня"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Павялічыць лічбу года"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Паменшыць лічбу года"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"пастаўлены"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"не пастаўлены"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"абрана"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Апублікаваць з дапамогай"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Адправiць з дапамогай прыкладання <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Правядзіце пальцам уверх, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Правядзіце пальцам уніз, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Правядзіце пальцам улева, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Правядзіце пальцам управа, каб атрымаць <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Разблакаваць"</string>
<string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
<string name="description_target_silent" msgid="893551287746522182">"Ціхі рэжым"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Гук уключаны"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Прагартайце, каб разблакаваць."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Кропка."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index cee54b4..81a75bd 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
<string name="description_target_silent" msgid="893551287746522182">"Тих режим"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Включване на звука"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Прокарайте пръст, за да отключите."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Включете слушалки, за да чуете изговарянето на клавишите за паролата."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Точка."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e360af1..6c6030c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Estableix l\'hora"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Establiment de data"</string>
<string name="date_time_set" msgid="5777075614321087758">"Defineix"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Fet"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminat"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NOU: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Addició d\'un compte"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Quin compte vols utilitzar?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Afegeix un compte"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Incrementa"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Redueix"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Mantén premut <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Fes lliscar el dit cap amunt per incrementar i cap avall per disminuir."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Fes augmentar el minut"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Fes disminuir el minut"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Fes augmentar l\'hora"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Fes disminuir l\'hora"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Estableix com a p. m."</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Estableix com a a. m."</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Fes augmentar el mes"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Fes disminuir el mes"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Fes augmentar el dia"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Fes disminuir el dia"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Fes augmentar l\'any"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Fes disminuir l\'any"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"marcat"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"no marcat"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"seleccionat"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Comparteix amb"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Comparteix amb <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Llisca el dit. Mantén premut."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Fes lliscar el dit cap avall per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Fes lliscar el dit cap a l\'esquerra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Fes lliscar el dit cap a la dreta per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Desbloqueja"</string>
<string name="description_target_camera" msgid="969071997552486814">"Càmera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silenci"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Activa el so"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Llisca el dit per desbloquejar."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Connecta un auricular per escoltar les claus de la contrasenya en veu alta."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punt."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ea206b0..d95feaa 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Fotoaparát"</string>
<string name="description_target_silent" msgid="893551287746522182">"Tichý"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Zapnout zvuk"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Odemknete posunutím prstu."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Chcete-li slyšet, které klávesy jste při zadávání hesla stiskli, připojte sluchátka."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Tečka."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 94c2999..2c7f1306 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Angiv tidspunkt"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Angiv dato"</string>
<string name="date_time_set" msgid="5777075614321087758">"Angiv"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Udført"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NYHED! "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Tilføj en konto"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Hvilken konto vil du bruge?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Tilføj konto"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Højere"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Lavere"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Tryk <xliff:g id="VALUE">%s</xliff:g> gange, og hold inde."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glid op for at øge og ned for at mindske."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Forøg minuttal"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Sænk minuttal"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Forøg timetal"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Sænk timetal"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Indstil PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Indstil AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Senere måned"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Tidligere måned"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Senere dag"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tidligere dag"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Senere år"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Tidligere år"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"markeret"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"ikke markeret"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"udvalgt"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Del med"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Del med <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Glidende håndtag. Tryk og hold nede."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Glid ned for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Glid til venstre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Glid til højre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Lås op"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Lydløs"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Lyd slået til"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glid hurtigt henover for at låse op."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Tilslut et headset for at høre tasterne blive læst højt ved angivelse af adgangskode."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punktum."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 82a60d2..aa44b87 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Uhrzeit festlegen"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Datum festlegen"</string>
<string name="date_time_set" msgid="5777075614321087758">"Speichern"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Fertig"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"Neu: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Konto hinzufügen"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Welches Konto möchten Sie verwenden?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Konto hinzufügen"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Erhöhen"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Verringern"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> berühren und gedrückt halten"</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Zum Erhöhen nach oben und zum Verringern nach unten schieben"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Minuten verlängern"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Minuten verringern"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Stunden verlängern"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Stunden verringern"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Zeit festlegen"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Zeit festlegen"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Monat verlängern"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Monat verringern"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Tag verlängern"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tag verringern"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Jahr verlängern"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Jahr verringern"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"Aktiviert"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"Nicht aktiviert"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"Ausgewählt"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Teilen mit"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Mit <xliff:g id="APPLICATION_NAME">%s</xliff:g> teilen"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Schieberegler: Berühren und halten"</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach unten schieben"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach links schieben"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach rechts schieben"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Entsperren"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Lautlos"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Ton ein"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Zum Entsperren den Finger über den Bildschirm ziehen"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Schließen Sie ein Headset an, um das Passwort gesprochen zu hören."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b9710e5..d85d639 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Ρύθμιση ώρας"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Ορισμός ημερομηνίας"</string>
<string name="date_time_set" msgid="5777075614321087758">"Ορισμός"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Τέλος"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Προεπιλεγμένο"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"ΝΕΟ: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτούνται άδειες"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Προσθήκη λογαριασμού"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Ποιον λογαριασμό θέλετε να χρησιμοποιήσετε;"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Προσθήκη λογαριασμού"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Αύξηση"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Μείωση"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Πατήστε παρατεταμένα το <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Πραγματοποιήστε κύλιση προς τα πάνω για αύξηση και προς τα κάτω για μείωση."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Αύξηση λεπτού"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Μείωση λεπτού"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Αύξηση ώρας"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Μείωση ώρας"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Ορισμός ΜΜ"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Ορισμός ΠΜ"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Αύξηση μήνα"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Μείωση μήνα"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Αύξηση ημέρας"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Μείωση ημέρας"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Αύξηση έτους"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Μείωση έτους"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"ελέγχθηκε"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"δεν επιλέχθηκε"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"επιλεγμένο"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινή χρήση με"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινή χρήση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Στοιχείο χειρισμού με δυνατότητα ολίσθησης. Αγγίξτε και πατήστε παρατεταμένα."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Κύλιση προς τα κάτω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Κύλιση προς τα αριστερά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Κύλιση προς τα δεξιά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Ξεκλείδωμα"</string>
<string name="description_target_camera" msgid="969071997552486814">"Φωτογραφική μηχανή"</string>
<string name="description_target_silent" msgid="893551287746522182">"Αθόρυβο"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Ενεργοποίηση ήχου"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Σύρετε για ξεκλείδωμα."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Συνδέστε ακουστικά για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Τελεία."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c41f2be..fa767ff 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silent"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Sound on"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Swipe to unlock."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Plug in a headset to hear password keys spoken."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Dot"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 19e8e25..5c7b782 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Sonido activado"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Desliza el dedo para desbloquear."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conecta un auricular para escuchar las contraseñas."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punto"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c732ab9..8ade0e0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Establecer hora"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Establecer fecha"</string>
<string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Listo"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NUEVO:"</font></string>
<string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Añadir una cuenta"</string>
<string name="choose_account_text" msgid="6303348737197849675">"¿Qué cuenta quieres usar?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Añadir cuenta"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Aumentar"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Reducir"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Mantén pulsado <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Desliza el dedo hacia arriba para aumentar y hacia abajo para disminuir."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Aumentar minutos"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reducir minutos"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Aumentar horas"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reducir horas"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Establecer p.m."</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Establecer a.m."</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Aumentar mes"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reducir mes"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Aumentar días"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir días"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"seleccionado"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"no seleccionado"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"seleccionado"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Compartir con"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Compartir con <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Mantén pulsado el icono de desbloqueo y deslízalo."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Desliza el dedo hacia abajo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Desliza el dedo hacia la derecha para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
<string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silencio"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Sonido activado"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Desliza el dedo para desbloquear."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conecta un auricular para escuchar las contraseñas."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punto"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 890dd7b..0a8faed 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Kellaaja määramine"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Kuupäeva määramine"</string>
<string name="date_time_set" msgid="5777075614321087758">"Määra"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Valmis"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Vaikimisi"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"UUS: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Lube pole vaja"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Konto lisamine"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Millist kontot soovite kasutada?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Lisa konto"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Suurendamine"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Vähendamine"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> puudutage ja hoidke."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Suurendamiseks lohistage üles, vähendamiseks alla."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Minutite suurendamine"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Minutite vähendamine"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Tundide suurendamine"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Tundide vähendamine"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"PM-i seadmine"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"AM-i seadmine"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Kuu suurendamine"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Kuu vähendamine"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Päeva suurendamine"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Päeva vähendamine"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aasta suurendamine"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Aasta vähendamine"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"märgitud"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"pole märgitud"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"valitud"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Jaga:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Jaga rakendusega <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Libistamispide. Puudutage ja hoidke all."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Lohistage alla: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Lohistage vasakule: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Lohistage paremale: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Luku avamine"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kaamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Avamiseks tõmmake sõrmega."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Paroolide kuulamiseks ühendage peakomplekt."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkt."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ce26f1e..c9329bb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"تنظیم زمان"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"تاریخ تنظیم"</string>
<string name="date_time_set" msgid="5777075614321087758">"تنظیم"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"انجام شد"</string>
<string name="default_permission_group" msgid="2690160991405646128">"پیش فرض"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"جدید: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"افزودن یک حساب"</string>
<string name="choose_account_text" msgid="6303348737197849675">"کدام حساب را میخواهید استفاده کنید؟"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"افزودن حساب"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"افزایش"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"کاهش"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> لمس کرده و نگه دارید."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"برای افزایش به بالا بلغزانید و برای کاهش به پایین بلغزانید."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"افزایش دقیقه"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"کاهش دقیقه"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"افزایش ساعت"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"کاهش ساعت"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"تنظیم ب.ظ"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"تنظیم ق.ظ"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"افزایش ماه"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"کاهش ماه"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"افزایش روز"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"کاهش روز"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"افزایش سال"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"کاهش سال"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"علامت زده"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"بدون علامت"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"انتخاب شد"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"اشتراکگذاری با"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"اشتراکگذاری با <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"اهرم کنترل حرکت. لمس کرده و نگهدارید."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"لغزاندن به پایین برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"لغزاندن به راست برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"بازکردن قفل"</string>
<string name="description_target_camera" msgid="969071997552486814">"دوربین"</string>
<string name="description_target_silent" msgid="893551287746522182">"ساکت"</string>
<string name="description_target_soundon" msgid="30052466675500172">"صدا روشن"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"جستجو"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"برای بازگشایی قفل، بلغزانید."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"برای شنیدن کلیدهای گذرواژه که با صدای بلند خوانده میشوند، هدست را وصل کنید."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"نقطه."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 54e1a1b..8a1079b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Aseta aika"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Aseta päivämäärä"</string>
<string name="date_time_set" msgid="5777075614321087758">"Aseta"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Valmis"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Oletus"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"UUTTA: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Lupia ei tarvita"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Lisää tili"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Mitä tiliä haluat käyttää?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Lisää tili"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Lisää"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Vähennä"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> kosketa pitkään."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Lisää tai vähennä arvoa liu\'uttamalla ylös tai alas."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Lisää minuuttien määrää."</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Vähennä minuuttien määrää."</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Lisää tuntien määrää."</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Vähennä tuntien määrää."</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Aseta ip"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Aseta ap"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Lisää kuukausien määrää."</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Vähennä kuukausien määrää."</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Lisää päivien määrää."</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Vähennä päivien määrää."</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Lisää vuosien määrää."</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Vähennä vuosien määrää."</string>
<string name="checkbox_checked" msgid="7222044992652711167">"valittu"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"ei valittu"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"valittu"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Jaa seuraavien kanssa:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Jaa sovelluksessa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Liukuva valitsin. Kosketa pitkään."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Liu\'uta alas ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Liu\'uta vasemmalle ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Liu\'uta oikealle ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Poista lukitus"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Äänetön"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Ääni käytössä"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Haku"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Poista lukitus liu\'uttamalla."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Liitä kuulokkeet kuullaksesi, mitä näppäimiä painat kirjoittaessasi salasanaa."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Piste."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d4a6f5b..f05e564c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Définir l\'heure"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Définir la date"</string>
<string name="date_time_set" msgid="5777075614321087758">"Définir"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"OK"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Par défaut"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NOUVEAU"</font>" :"</string>
<string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Ajouter un compte"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Quel compte souhaitez-vous utiliser ?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Ajouter un compte"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Augmenter"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Diminuer"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> appuyez de manière prolongée."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Faites glisser vers le haut pour augmenter et vers le bas pour diminuer."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Minute suivante"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Minute précédente"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Heure suivante"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Heure précédente"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Définir la valeur PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Définir la valeur AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Mois suivant"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Mois précédent"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Jour suivant"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Jour précédent"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Année suivante"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Année précédente"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"coché"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"non coché"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"sélectionné"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Partager avec"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Partager avec <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Poignée coulissante. Appuyez de manière prolongée."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Faites glisser vers le bas pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Faites glisser vers la gauche pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Faites glisser vers la droite pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Déverrouiller"</string>
<string name="description_target_camera" msgid="969071997552486814">"Appareil photo"</string>
<string name="description_target_silent" msgid="893551287746522182">"Mode silencieux"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Son activé"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Faites glisser votre doigt pour déverrouiller l\'appareil."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Branchez des écouteurs pour entendre l\'énoncé des touches lors de la saisie du mot de passe."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Point."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d84915e..9a742c4 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"समय सेट करें"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"दिनांक सेट करें"</string>
<string name="date_time_set" msgid="5777075614321087758">"सेट करें"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"पूर्ण"</string>
<string name="default_permission_group" msgid="2690160991405646128">"डिफ़ॉल्ट"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"नया: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"किसी अनुमति की आवश्यकता नहीं है"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"कोई खाता जोड़ें"</string>
<string name="choose_account_text" msgid="6303348737197849675">"आप कौन-सा खाता उपयोग करना चाहते हैं?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"खाता जोड़ें"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"बढ़ाएं"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"कम करें"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> को स्पर्श करके रखें."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"बढ़ाने के लिए ऊपर और कम करने के लिए नीचे स्लाइड करें."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"मिनट बढ़ाएं"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"मिनट कम करें"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"घंटे बढ़ाएं"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"घंटे कम करें"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"सायं सेट करें"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"प्रात: सेट करें"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"माह बढ़ाएं"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"माह कम करें"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"दिन बढ़ाएं"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिन कम करें"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढ़ाएं"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कम करें"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"चेक किया गया"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"चेक नहीं किया गया"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"चयनित"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"इसके साथ साझा करें:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"स्लाइडिंग हैंडल. स्पर्श करके रखें."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए नीचे स्लाइड करें."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए बाएं स्लाइड करें."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए दाएं स्लाइड करें."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"अनलॉक करें"</string>
<string name="description_target_camera" msgid="969071997552486814">"कैमरा"</string>
<string name="description_target_silent" msgid="893551287746522182">"मौन"</string>
<string name="description_target_soundon" msgid="30052466675500172">"ध्वनि चालू करें"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"अनलॉक करने के लिए स्वाइप करें."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"बोली गईं पासवर्ड कुंजियां सुनने के लिए हेडसेट प्लग इन करें."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"बिंदु."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index b0ebc8a..ba0fb7a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Postavljanje vremena"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Postavi datum"</string>
<string name="date_time_set" msgid="5777075614321087758">"Postavi"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Gotovo"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Zadano"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NOVO: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Nije potrebno dopuštenje"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Dodajte račun"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Koji račun želite upotrijebiti?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Dodaj račun"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Povećavanje"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Smanjivanje"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> pritisnite i držite."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Kliznite prema gore za povećavanje i prema dolje za smanjivanje."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Povećanje minuta"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Smanjenje minuta"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Povećanje sati"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Smanjenje sati"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Postavi PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Postavi AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Povećanje mjeseca"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Smanjenje mjeseca"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Povećanje dana"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Smanjenje dana"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povećanje godine"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Smanjenje godine"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"označeno"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"nije označeno"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"odabran"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Dijeljenje sa"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Dijeli s aplikacijom <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Klizna ručka. Dodirnite i držite."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Kliznite prema dolje za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Kliznite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Kliznite desno za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Otključaj"</string>
<string name="description_target_camera" msgid="969071997552486814">"Fotoaparat"</string>
<string name="description_target_silent" msgid="893551287746522182">"Bešumno"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Zvuk je uključen"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Prijeđite prstima da biste otključali."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Priključite slušalice kako biste čuli izgovaranje tipki zaporke."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Točka."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5e3464d..25a8d2a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Némítás"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Hang bekapcsolása"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"A feloldásához húzza végig az ujját."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Csatlakoztasson egy fülhallgatót, ha hallani szeretné a jelszó betűit felolvasva."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Pont."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4fb25c1..944f429 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Setel waktu"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Setel tanggal"</string>
<string name="date_time_set" msgid="5777075614321087758">"Setel"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Selesai"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Default"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"BARU: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Tidak perlu izin"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Tambahkan akun"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Akun mana yang ingin Anda gunakan?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Tambahkan akun"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Menambah"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Mengurangi"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> sentuh dan tahan."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Geser ke atas untuk menambah dan ke bawah untuk mengurangi."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Menambah menit"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Mengurangi menit"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Menambah jam"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Mengurangi jam"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Menyetel PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setel AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Menambah bulan"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Mengurangi bulan"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Menambah hari"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Mengurangi hari"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Menambah tahun"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Mengurangi tahun"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"dicentang"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"tidak diperiksa"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"dipilih"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Berbagi dengan"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Berbagi dengan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Gagang geser. Sentuh & tahan."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Geser ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Geser ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Geser ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Membuka gembok"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Suara hidup"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Penelusuran"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Gesek untuk membuka kunci."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Pasang headset untuk mendengar tombol sandi yang diucapkan."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Titik."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 7f399be..03cf404 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Imposta ora"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Imposta data"</string>
<string name="date_time_set" msgid="5777075614321087758">"Imposta"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Fine"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predefinito"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NUOVA: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Aggiungi un account"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Quale account vuoi usare?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Aggiungi account"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Aumenta"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Riduci"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Tocca e tieni premuto il numero <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Scorri verso l\'alto per aumentare il valore e verso il basso per diminuirlo."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Aumenta minuti"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Riduci minuti"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Aumenta ore"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Riduci ore"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Imposta PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Imposta AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Aumenta mese"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Riduci mese"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Aumenta giorno"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Riduci giorno"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumenta anno"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Riduci anno"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"selezionata"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"non selezionato"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"selezionato"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Condividi con"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Condividi con <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Maniglia scorrevole. Tocca e tieni premuto."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Giù per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"A destra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Sblocca"</string>
<string name="description_target_camera" msgid="969071997552486814">"Fotocamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silenzioso"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Audio attivato"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Fai scorrere per sbloccare."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Collega gli auricolari per ascoltare la pronuncia dei tasti premuti per la password."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punto."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index b03207d..3c6e0c2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"הגדרת שעה"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"הגדר תאריך"</string>
<string name="date_time_set" msgid="5777075614321087758">"הגדר"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"בוצע"</string>
<string name="default_permission_group" msgid="2690160991405646128">"ברירת מחדל"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"חדש: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"לא דרושים אישורים"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"הוסף חשבון"</string>
<string name="choose_account_text" msgid="6303348737197849675">"באיזה חשבון ברצונך להשתמש?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"הוסף חשבון"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"הוסף"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"הפחת"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> גע והחזק."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"הסט למעלה כדי להוסיף ולמטה כדי להפחית."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"הוסף דקה"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"הפחת דקה"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"הוסף שעה"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"הפחת שעה"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"הגדר PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"הגדר AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"הוסף חודש"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"הפחת חודש"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"הוסף יום"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"הפחת יום"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"הוסף שנה"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"הפחת שנה"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"מסומן"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"לא מסומן"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"נבחר"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"שתף עם"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"שתף עם <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"ידית להחלקה. גע והחזק."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"הסט למטה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"הסט שמאלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"הסט ימינה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"בטל נעילה"</string>
<string name="description_target_camera" msgid="969071997552486814">"מצלמה"</string>
<string name="description_target_silent" msgid="893551287746522182">"שקט"</string>
<string name="description_target_soundon" msgid="30052466675500172">"הקול פועל"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"החלק לביטול נעילה."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"חבר אוזניות כדי לשמוע הקראה של מפתחות סיסמה."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"נקודה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 526535f..9e21085 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"時刻設定"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"日付設定"</string>
<string name="date_time_set" msgid="5777075614321087758">"設定"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"完了"</string>
<string name="default_permission_group" msgid="2690160991405646128">"端末既定"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NEW: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"権限の許可は必要ありません"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"アカウントを追加"</string>
<string name="choose_account_text" msgid="6303348737197849675">"どのアカウントを使用しますか?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"アカウントを追加"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"進めます"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"戻します"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g>回タップして押し続けます。"</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"上にスライドで進み、下にスライドで戻ります。"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"1分進めます"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"1分戻します"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"1時間進めます"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"1時間戻します"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"午後に設定"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"午前に設定"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"1か月進めます"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"1か月戻します"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"1日進めます"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"1日戻します"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"1年進めます"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"1年戻します"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"ON"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"OFF"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"ON"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"共有"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>と共有"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"スライダーハンドルです。押し続けます。"</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"下にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"左にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"右にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"ロックを解除"</string>
<string name="description_target_camera" msgid="969071997552486814">"カメラ"</string>
<string name="description_target_silent" msgid="893551287746522182">"マナーモード"</string>
<string name="description_target_soundon" msgid="30052466675500172">"サウンドON"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"検索します"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"ロック解除するにはスワイプします。"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"パスワードのキーが音声出力されるのでヘッドセットを接続してください。"</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"ドット。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index b38b988..8dc3fa6 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"시간 설정"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"날짜 설정"</string>
<string name="date_time_set" msgid="5777075614321087758">"설정"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"완료"</string>
<string name="default_permission_group" msgid="2690160991405646128">"기본값"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"신규: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"권한 필요 없음"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"계정 추가"</string>
<string name="choose_account_text" msgid="6303348737197849675">"사용할 계정을 선택하세요."</string>
<string name="add_account_button_label" msgid="3611982894853435874">"계정 추가"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"늘리기"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"줄이기"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> 길게 터치하세요."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"늘리려면 위로 슬라이드하고 줄이려면 아래로 슬라이드합니다."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"\'분\'을 늘립니다."</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"\'분\'을 줄입니다."</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"\'시간\'을 늘립니다."</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"\'시간\'을 줄입니다."</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"PM 설정"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"AM 설정"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"\'월\'을 늘립니다."</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"\'월\'을 줄입니다."</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"\'일\'을 늘립니다."</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"\'일\'을 줄입니다."</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"\'연도\'를 늘립니다."</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"\'연도\'를 줄입니다."</string>
<string name="checkbox_checked" msgid="7222044992652711167">"확인"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"선택 안함"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"선택됨"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"공유 대상:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>와(과) 공유"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"슬라이딩 핸들을 길게 터치하세요."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 아래로 슬라이드"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 왼쪽으로 슬라이드"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 오른쪽으로 슬라이드"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"잠금 해제"</string>
<string name="description_target_camera" msgid="969071997552486814">"카메라"</string>
<string name="description_target_silent" msgid="893551287746522182">"무음"</string>
<string name="description_target_soundon" msgid="30052466675500172">"사운드 켜기"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"검색"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"스와이프하여 잠급니다."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"비밀번호 키를 음성으로 들으려면 헤드셋을 연결하세요."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"점"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 4d67940..fa13981 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Nustatyti laiką"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Nustatyti datą"</string>
<string name="date_time_set" msgid="5777075614321087758">"Nustatyti"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Baigta"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Numatytasis"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NAUJAS: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Nereikia leidimų"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Pridėti paskyrą"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Kurią paskyrą norite naudoti?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Pridėti paskyrą"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Padidinti"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Sumažinti"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Palieskite <xliff:g id="VALUE">%s</xliff:g> ir laikykite."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Slinkite aukštyn, kad padidintumėte, ir žemyn, kad sumažintumėte."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Padidinti minučių skaičių"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Sumažinti minučių skaičių"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Padidinti valandų skaičių"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Sumažinti valandų skaičių"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Nustatyti po pusiaudienio"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Nustatyti prieš pusiaudienį"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Padidinti mėnesių skaičių"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Sumažinti mėnesių skaičių"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Padidinti dienų skaičių"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Sumažinti dienų skaičių"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Padidinti metų skaičių"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Sumažinti metų skaičių"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"pažymėtas"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"nepatikrinta"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"pasirinkta"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Bendrinti su"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Bendrinti su „<xliff:g id="APPLICATION_NAME">%s</xliff:g>“"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Slydimo valdymas. Palieskite ir laikykite."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Slyskite žemyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Slyskite į kairę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Slyskite į dešinę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Atrakinti"</string>
<string name="description_target_camera" msgid="969071997552486814">"Vaizdo kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Begarsis"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Garsas įjungtas"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Perbraukite pirštu, kad atrakintumėte."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Prijunkite ausines, kad išgirstumėte sakomus slaptažodžio klavišus."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Taškas."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 12a0e58..1fe5316 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Laika iestatīšana"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Datuma iestatīšana"</string>
<string name="date_time_set" msgid="5777075614321087758">"Iestatīt"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Gatavs"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Noklusējums"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"JAUNA: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Atļaujas nav nepieciešamas."</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Pievienot kontu"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Kuru kontu vēlaties izmantot?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Pievienot kontu"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Palielināt"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Samazināt"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g>: pieskarieties un turiet nospiestu."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Velciet uz augšu, lai palielinātu vērtību, un uz leju, lai to samazinātu."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Norādīt vēlākas minūtes"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Norādīt agrākas minūtes"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Norādīt vēlāku stundu"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Norādīt agrāku stundu"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Iestatīt pēcpusdienas laiku"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Iestatīt priekšpusdienas laiku"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Norādīt vēlāku mēnesi"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Norādīt agrāku mēnesi"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Norādīt vēlāku dienu"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Norādīt agrāku dienu"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Norādīt vēlāku gadu"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Norādīt agrāku gadu"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"atzīmēta"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"nav atzīmēta"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"atlasīta"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Kopīgot ar:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Kopīgot ar lietojumprogrammu <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Bīdāms turis. Pieskarieties tam un turiet to nospiestu."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Velciet uz leju, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Velciet pa kreisi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Velciet pa labi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Atbloķēt"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Klusums"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Skaņa ieslēgta"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Velciet ar pirkstu, lai atbloķētu."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Pievienojiet austiņas, lai dzirdētu paroles taustiņu nosaukumus."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkts."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index f725896..da9ca41 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Bunyi dihidupkan"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Leret untuk membuka kunci."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Pasangkan set kepala untuk mendengar kekunci kata laluan disebutkan."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Titik."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8bc9dab..ec580ad 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Stille klokken"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Angi dato"</string>
<string name="date_time_set" msgid="5777075614321087758">"Lagre"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Ferdig"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NYTT: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Legg til en konto"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Hvilken konto vil du bruke?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Legg til konto"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Øk"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Reduser"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> – trykk og hold inne."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Dra opp for å øke og ned for å redusere."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Øk minutter"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduser minutter"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Øk timer"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reduser timer"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Angi p.m."</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Angi a.m."</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Øk måneder"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reduser måneder"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Øk dager"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduser dager"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Øk år"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduser år"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"valgt"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"ikke valgt"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"valgt"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Del med"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Del med <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Glidebryter. Trykk og hold inne."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Dra ned for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Dra til venstre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Dra til høyre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Lås opp"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Stille"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Lyd på"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Sveip for å låse opp."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Koble til hodetelefoner for å høre opplesing av bokstavene i passordet."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punktum."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 61f08e0..94d9712 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Tijd instellen"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Datum instellen"</string>
<string name="date_time_set" msgid="5777075614321087758">"Instellen"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Gereed"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standaard"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NIEUW: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Een account toevoegen"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Welk account wilt u gebruiken?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Account toevoegen"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Verhogen"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Verlagen"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> blijven aanraken."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Veeg omhoog om te verhogen en omlaag om te verlagen."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Hogere waarde voor minuten"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Lagere waarde voor minuten"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Hogere waarde voor uren"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Lagere waarde voor uren"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"PM instellen"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"AM instellen"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Hogere waarde voor maand"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Lagere waarde voor maand"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Hogere waarde voor dag"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Lagere waarde voor dag"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Hogere waarde voor jaar"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Lagere waarde voor jaar"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"aangevinkt"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"niet aangevinkt"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"geselecteerd"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Delen met"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Delen met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Schuifgreep. Tikken en blijven aanraken."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Veeg omlaag voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Veeg naar links voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Veeg naar rechts voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Ontgrendelen"</string>
<string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Stil"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Geluid aan"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Vegen om te ontgrendelen"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Sluit een headset aan om wachtwoordtoetsen te laten voorlezen."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Stip."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 77f8adc..ee10502 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Aparat"</string>
<string name="description_target_silent" msgid="893551287746522182">"Wyciszenie"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Włącz dźwięk"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Przesuń, aby odblokować."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Podłącz zestaw słuchawkowy, aby wysłuchać znaków hasła wypowiadanych na głos."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Kropka"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2a3e2b9..290ae19 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Câmara"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Som ativado"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Deslizar rapidamente para desbloquear."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Ligue os auscultadores com microfone integrado para ouvir as teclas da palavra-passe."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Ponto."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 88b7a57..09fe685 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Câmera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Som ativado"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Deslize para desbloquear."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conecte um fone de ouvido para ouvir as teclas da senha."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Ponto final."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 75c5c7e..f4bc105 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1834,6 +1834,8 @@
<skip />
<!-- no translation found for description_target_soundon (30052466675500172) -->
<skip />
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<!-- no translation found for description_target_unlock_tablet (3833195335629795055) -->
<skip />
<!-- no translation found for keyboard_headset_required_to_hear_password (7011927352267668657) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5409290..9dee72d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Cameră foto"</string>
<string name="description_target_silent" msgid="893551287746522182">"Silenţios"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Sunet activat"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Glisaţi pentru a debloca."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Conectaţi un set căşti-microfon pentru a auzi tastele apăsate când introduceţi parola."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punct."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9d8e4a6..041133cd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Настройка времени"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Настройка даты"</string>
<string name="date_time_set" msgid="5777075614321087758">"Установить"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Готово"</string>
<string name="default_permission_group" msgid="2690160991405646128">"По умолчанию"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"НОВОЕ: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Не требуется разрешений"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Добавить аккаунт"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Выберите аккаунт"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Добавить аккаунт"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Увеличить"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Уменьшить"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Нажмите и удерживайте <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Проведите вверх, чтобы увеличить значение, и вниз, чтобы уменьшить его."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"На минуту вперед"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"На минуту назад"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"На час вперед"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"На час назад"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Установить время после полудня"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Установить время до полудня"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"На месяц вперед"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"На месяц назад"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"На день вперед"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"На год вперед"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На год назад"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"установлено"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"не установлено"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"выбрано"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Открыть доступ:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Открыть доступ приложению \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\""</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Перетаскиваемый значок блокировки. Нажмите и удерживайте."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Проведите вниз, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Проведите влево, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Проведите вправо, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Разблокировать"</string>
<string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
<string name="description_target_silent" msgid="893551287746522182">"Без звука"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Включить звук"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Поиск"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Проведите по экрану, чтобы разблокировать устройство."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Подключите гарнитуру, чтобы услышать пароль."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Точка"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index ca80f6b..c7c7b4f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Fotoaparát"</string>
<string name="description_target_silent" msgid="893551287746522182">"Tichý"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Zapnúť zvuk"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Posunom odomknúť."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Ak si chcete vypočuť vyslovené klávesy hesla, pripojte náhlavnú súpravu."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Bodka."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e664d9c..4dc425b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Fotoaparat"</string>
<string name="description_target_silent" msgid="893551287746522182">"Tiho"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Vklopljen zvok"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Povlecite, če želite odkleniti."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Priključite slušalke, če želite slišati izgovorjene tipke gesla."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Pika."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4a3839b..94024b8 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Подешавање времена"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Подешавање датума"</string>
<string name="date_time_set" msgid="5777075614321087758">"Подеси"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Готово"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Подразумевано"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"НОВО: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Додај налог"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Који налог желите да користите?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Додај налог"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Повећавање"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Смањивање"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> додирните и задржите."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Превуците нагоре да бисте повећали, а надоле да бисте смањили."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Повећавање минута"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Смањивање минута"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Повећавање сати"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Смањивање сати"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Подеси по подне"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Подеси пре подне"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Повећавање месеца"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Смањивање месеца"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Повећавање дана"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Смањивање дана"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Повећавање године"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Смањивање године"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"изабрано"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"није потврђено"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"изабрано"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Дели са"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Дели са апликацијом <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Клизна ручица. Додирните и задржите."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Превуците надоле за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Превуците улево за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Превуците удесно за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Откључај"</string>
<string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
<string name="description_target_silent" msgid="893551287746522182">"Нечујно"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Укључи звук"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Превуците да бисте откључали."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Прикључите слушалице да бисте чули изговорене тастере за лозинку."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Тачка."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 7ba32ce..ec77eb1 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Ange tid"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Ange datum"</string>
<string name="date_time_set" msgid="5777075614321087758">"Ställ in"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Klar"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standardinställning"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"NY: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Lägg till ett konto"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Vilket konto vill du använda?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Lägg till konto"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Öka"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Minska"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> tryck länge."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Dra uppåt för att öka och nedåt för att minska."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Öka minuter"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Minska minuter"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Öka timmar"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Minska timmar"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Ange em"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Ange fm"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Öka månader"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Minska månader"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Öka dagar"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Minska dagar"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Öka år"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Minska år"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"markerat"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"inte markerat"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"markerade"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Dela med"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Dela med <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Skärmlåsfunktion. Tryck och dra."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Dra nedåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Dra åt höger för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Lås upp"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Tyst"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Ljud på"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Lås upp genom att dra."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Anslut mikrofonlurar om du vill att lösenordet ska läsas upp."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkt."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1744095..6b64163 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Kimya"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Sauti imewashwa"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Pitisha ili kufungua."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Chomeka kifaa cha sauti ili kusikiliza vibonye vya nenosiri vikizungumzwa."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Nukta."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 32281b5..a9313b7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"ตั้งเวลา"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"ตั้งวันที่"</string>
<string name="date_time_set" msgid="5777075614321087758">"ตั้งค่า"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"เสร็จสิ้น"</string>
<string name="default_permission_group" msgid="2690160991405646128">"เริ่มต้น"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"ใหม่: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"เพิ่มบัญชี"</string>
<string name="choose_account_text" msgid="6303348737197849675">"คุณต้องการใช้บัญชีใด"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"เพิ่มบัญชี"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"เพิ่ม"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"ลด"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"แตะ <xliff:g id="VALUE">%s</xliff:g> ค้างไว้"</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"เลื่อนขึ้นเพื่อเพิ่มและเลื่อนลงเพื่อลด"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"เพิ่มนาที"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"ลดนาที"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"เพิ่มชั่วโมง"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"ลดชั่วโมง"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"ตั้งค่า PM"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"ตั้งค่า AM"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"เพิ่มเดือน"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"ลดเดือน"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"เพิ่มวัน"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ลดวัน"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"เพิ่มปี"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ลดปี"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"เลือกไว้"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"ไม่ได้ตรวจสอบ"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"เลือกแล้ว"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"แบ่งปันกับ"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"แบ่งปันด้วย <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"ที่จับสำหรับเลื่อน แตะค้างไว้"</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"เลื่อนลงเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"เลื่อนไปทางซ้ายเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"เลื่อนไปทางขวาเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"ปลดล็อก"</string>
<string name="description_target_camera" msgid="969071997552486814">"กล้องถ่ายรูป"</string>
<string name="description_target_silent" msgid="893551287746522182">"ปิดเสียง"</string>
<string name="description_target_soundon" msgid="30052466675500172">"เปิดเสียง"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"กวาดเพื่อปลดล็อก"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"เสียบชุดหูฟังเพื่อฟังเสียงเมื่อพิมพ์รหัสผ่าน"</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"เครื่องหมายจุด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index fd88fc1..2addf86b 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Tahimik"</string>
<string name="description_target_soundon" msgid="30052466675500172">"I-on ang tunog"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Mag-swipe upang i-unlock."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Mag-plug in ng isang headset upang marinig ang mga password key na binabanggit."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Dot."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 251e47c..29cde7d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarla"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarihi ayarla"</string>
<string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Tamamlandı"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Varsayılan"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"YENİ: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Hesap ekleyin"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Hangi hesabı kullanmak istiyorsunuz?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Hesap ekle"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Artır"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Azalt"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> rakamına dokunun ve basılı tutun."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Artırmak için yukarı, azaltmak için aşağı kaydırın."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Dakikayı artır"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Dakikayı azalt"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Saati artır"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Saati azalt"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"ÖS değerini ayarla"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"ÖÖ değerini ayarla"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Ayı artır"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Ayı azalt"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Günü artır"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Günü azalt"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Yılı artır"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yılı azalt"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"işaretli"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"işaretlenmedi"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"seçili"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Şununla paylaş:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ile paylaş"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Kayan tutma yeri. Dokunun ve basılı tutun."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için aşağı kaydırın."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için sola kaydırın."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için sağa kaydırın."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Kilidi aç"</string>
<string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Sessiz"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Ses açık"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Ara"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Kilidi açmak için kaydırın."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Şifre tuşlarının sesli okunmasını dinlemek için mikrofonlu kulaklık takın."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Nokta."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 9054295..f2ef429 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Установити час"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Установити дату"</string>
<string name="date_time_set" msgid="5777075614321087758">"Застосувати"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Готово"</string>
<string name="default_permission_group" msgid="2690160991405646128">"За умовч."</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"НОВИЙ: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Дозвіл не потрібний"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Додати обліковий запис"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Який обліковий запис використовувати?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Додати облік. запис"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Збільшити"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Зменшити"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> – торкніться й утримуйте."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Проведіть пальцем угору, щоб збільшити, і вниз, щоб зменшити."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Вибрати хвилину в майбутньому"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Вибрати хвилину в минулому"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Вибрати годину в майбутньому"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Вибрати годину в минулому"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Установити час \"пп\""</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Установити час \"дп\""</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Вибрати місяць у майбутньому"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Вибрати місяць у минулому"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Вибрати день у майбутньому"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Вибрати день у минулому"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Вибрати рік у майбутньому"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Вибрати рік у минулому"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"перевірено"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"не перевірено"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"вибрано"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Надіслати через"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Надіслати через <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Вказівник-повзунок. Торкніться й утримуйте."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Проведіть пальцем униз, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Проведіть пальцем ліворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Проведіть пальцем праворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Розблокувати"</string>
<string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
<string name="description_target_silent" msgid="893551287746522182">"Без звуку"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Увімкнути звук"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Гортайте, щоб розблокувати."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Підключіть гарнітуру, щоб прослухати відтворені вголос символи пароля."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Крапка."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 609452d..94ce574 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Đặt giờ"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Đặt ngày"</string>
<string name="date_time_set" msgid="5777075614321087758">"Đặt"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"Xong"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Mặc định"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"MỚI: "</font></string>
<string name="no_permissions" msgid="7283357728219338112">"Không yêu cầu quyền"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"Thêm tài khoản"</string>
<string name="choose_account_text" msgid="6303348737197849675">"Bạn muốn sử dụng tài khoản nào?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Thêm tài khoản"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Tăng"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Giảm"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Chạm và giữ <xliff:g id="VALUE">%s</xliff:g>."</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Trượt lên để tăng và trượt xuống để giảm."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Tăng phút"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Giảm phút"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Tăng giờ"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Giảm giờ"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Đặt CH"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Đặt SA"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Tăng tháng"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Giảm tháng"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Tăng ngày"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Giảm ngày"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tăng năm"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Giảm năm"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"đã kiểm tra"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"chưa chọn"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"đã chọn"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Chia sẻ với"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Chia sẻ với <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Tay trượt. Chạm & giữ."</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"Trượt xuống để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Trượt sang trái để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"Trượt sang phải để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_target_unlock" msgid="2228524900439801453">"Mở khóa"</string>
<string name="description_target_camera" msgid="969071997552486814">"Máy ảnh"</string>
<string name="description_target_silent" msgid="893551287746522182">"Im lặng"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Bật âm thanh"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Trượt để mở khóa."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Cắm tai nghe để nghe các khóa mật khẩu được đọc."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Dấu chấm."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 5a9cadc..fd69a3e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"设置时间"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"设置日期"</string>
<string name="date_time_set" msgid="5777075614321087758">"设置"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"完成"</string>
<string name="default_permission_group" msgid="2690160991405646128">"默认"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"新增:"</font></string>
<string name="no_permissions" msgid="7283357728219338112">"不需要任何权限"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"添加帐户"</string>
<string name="choose_account_text" msgid="6303348737197849675">"您要使用哪个帐户?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"添加帐户"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"增大"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"减小"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"触摸 <xliff:g id="VALUE">%s</xliff:g> 次并按住。"</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"向上滑动可增大值,向下滑动可减小值。"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"增大分钟值"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"减小分钟值"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"增大小时值"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"减小小时值"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"设置下午时间"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"设置上午时间"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"增大月份值"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"减小月份值"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"增大日的值"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"减小日的值"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增大年份值"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"减小年份值"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"已选中"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"未选中"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"已选择"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"共享对象"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"与“<xliff:g id="APPLICATION_NAME">%s</xliff:g>”共享"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"滑动手柄。触摸并按住。"</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"向下滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"向左滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"向右滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"解锁"</string>
<string name="description_target_camera" msgid="969071997552486814">"相机"</string>
<string name="description_target_silent" msgid="893551287746522182">"静音"</string>
<string name="description_target_soundon" msgid="30052466675500172">"打开声音"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"搜索"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"滑动解锁。"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"需要插入耳机才能听到密码的按键声。"</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"点。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index aa8eda1..9283fa9 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1019,8 +1019,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"設定時間"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"日期設定"</string>
<string name="date_time_set" msgid="5777075614321087758">"設定"</string>
- <!-- no translation found for date_time_done (2507683751759308828) -->
- <skip />
+ <string name="date_time_done" msgid="2507683751759308828">"完成"</string>
<string name="default_permission_group" msgid="2690160991405646128">"預設值"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ffffa3a3">"新增:"</font></string>
<string name="no_permissions" msgid="7283357728219338112">"無須許可"</string>
@@ -1170,35 +1169,22 @@
<string name="add_account_label" msgid="2935267344849993553">"新增帳戶"</string>
<string name="choose_account_text" msgid="6303348737197849675">"您要使用哪個帳戶?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"新增帳戶"</string>
- <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
- <skip />
- <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
- <skip />
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"增加"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"減少"</string>
<string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> 輕觸並按住。"</string>
- <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
- <skip />
- <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
- <skip />
- <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
- <skip />
- <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
- <skip />
- <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
- <skip />
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"向上滑動即可增加,向下滑動即可減少。"</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"增加分鐘數"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"減少分鐘數"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"增加小時數"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"減少小時數"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"設定 PM 值"</string>
<string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"設定 AM 值"</string>
- <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
- <skip />
- <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
- <skip />
- <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
- <skip />
- <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
- <skip />
- <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
- <skip />
- <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
- <skip />
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"增加月數"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"減少月數"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"增加日數"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"減少日數"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增加年數"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"減少年數"</string>
<string name="checkbox_checked" msgid="7222044992652711167">"已勾選"</string>
<string name="checkbox_not_checked" msgid="5174639551134444056">"尚未勾選"</string>
<string name="radiobutton_selected" msgid="8603599808486581511">"已選取"</string>
@@ -1218,18 +1204,15 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"分享對象:"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"與「<xliff:g id="APPLICATION_NAME">%s</xliff:g>」分享"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"滑動控制。持續輕觸。"</string>
- <!-- no translation found for description_direction_up (7169032478259485180) -->
- <skip />
- <!-- no translation found for description_direction_down (5087739728639014595) -->
- <skip />
- <!-- no translation found for description_direction_left (7207478719805562165) -->
- <skip />
- <!-- no translation found for description_direction_right (8034433242579600980) -->
- <skip />
+ <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
+ <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
<string name="description_target_unlock" msgid="2228524900439801453">"解除鎖定"</string>
<string name="description_target_camera" msgid="969071997552486814">"相機"</string>
<string name="description_target_silent" msgid="893551287746522182">"靜音"</string>
<string name="description_target_soundon" msgid="30052466675500172">"開啟音效"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"滑動即可解鎖。"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"連接耳機即可聽取系統朗讀密碼按鍵。"</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"點。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 200bbea..6fe919d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1230,6 +1230,8 @@
<string name="description_target_camera" msgid="969071997552486814">"Ikhamera"</string>
<string name="description_target_silent" msgid="893551287746522182">"Thulile"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Umsindo uvuliwe"</string>
+ <!-- no translation found for description_target_search (3091587249776033139) -->
+ <skip />
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Swayipha ukuze uvule."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Plaka ku-headset ukuze uzwe okhiye bephasiwedi ezindlebeni zakho bezwakala kakhulu."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Icashazi."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5b6b35a..aabe407 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2349,6 +2349,8 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity"/>
+ <!-- Set true when the spell checker supports sentence level spell checking. -->
+ <attr name="supportsSentenceSpellCheck" format="boolean" />
</declare-styleable>
<!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 195c2e1..ca0e913 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3578,4 +3578,5 @@
<public type="attr" name="parentActivityName" />
+ <public type="attr" name="supportsSentenceSpellCheck" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index baeb9cc..bc5b1bc 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1158,6 +1158,7 @@
<item name="android:minWidth">@android:dimen/action_button_min_width</item>
<item name="android:minHeight">?android:attr/actionBarSize</item>
<item name="android:gravity">center</item>
+ <item name="android:maxLines">2</item>
</style>
<style name="Widget.ActionButton.Overflow">
@@ -1861,6 +1862,7 @@
<item name="android:paddingLeft">12dip</item>
<item name="android:paddingRight">12dip</item>
<item name="android:scaleType">center</item>
+ <item name="android:maxLines">2</item>
</style>
<style name="Widget.Holo.ActionButton.Overflow">
diff --git a/docs/html/guide/topics/ui/accessibility/apps.jd b/docs/html/guide/topics/ui/accessibility/apps.jd
index ff34be6..dc91638 100644
--- a/docs/html/guide/topics/ui/accessibility/apps.jd
+++ b/docs/html/guide/topics/ui/accessibility/apps.jd
@@ -111,7 +111,7 @@
<p>By including the description, speech-based accessibility services can announce "Add note" when a
user moves focus to this button or hovers over it.</p>
-<p class="note">Note: For {@link android.widget.EditText} fields, provide an
+<p class="note"><strong>Note:</strong> For {@link android.widget.EditText} fields, provide an
<a href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">android:hint</a>
attribute to help users understand what content is expected.</p>
@@ -119,8 +119,10 @@
<p>Focus navigation allows users with disabilities to step through user interface controls using a
directional controller. Directional controllers can be physical, such as a clickable trackball,
-directional pad (D-Pad) or arrow keys, tab key navigation with an attached keyboard or a software
-application that provides an on-screen directional control.</p>
+directional pad (D-pad) or arrow keys, tab key navigation with an attached keyboard or a software
+application, such as the
+<a href="https://play.google.com/store/apps/details?id=com.googlecode.eyesfree.inputmethod.latin">
+Eyes-Free Keyboard</a>, that provides an on-screen directional control.</p>
<p>A directional controller is a primary means of navigation for many users.
Verify that all user interface (UI) controls in your application are accessible
@@ -566,5 +568,7 @@
<p>As part of your accessibility testing, you can test navigation of your application using focus,
even if your test devices does not have a directional controller. The <a
href="{@docRoot}guide/developing/tools/emulator.html">Android Emulator</a> provides a
-simulated directional controller that you can easily use to test navigation. You can also use the
-arrow keys and Enter key on your keyboard with the Emulator to simulate use of a D-pad.</p>
+simulated directional controller that you can easily use to test navigation. You can also use a
+software-based directional controller, such as the one provided by the
+<a href="https://play.google.com/store/apps/details?id=com.googlecode.eyesfree.inputmethod.latin">
+Eyes-Free Keyboard</a> to simulate use of a D-pad.</p>
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 4dc915f..8af4a1c 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -194,7 +194,7 @@
appropriate for the view group. As you can see in figure 1, the parent
view group defines layout parameters for each child view (including the child view group).</p>
-<img src="{@docRoot}images/layoutparams.png" alt="" height="300" align="center"/>
+<img src="{@docRoot}images/layoutparams.png" alt="" />
<p class="img-caption"><strong>Figure 1.</strong> Visualization of a view hierarchy with layout
parameters associated with each view.</p>
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index 83c8150..45c9ac9 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -51,7 +51,7 @@
can build it up using Android's set of predefined widgets and layouts, or with custom Views that you
create yourself.</p>
-<img src="{@docRoot}images/viewgroup.png" alt="" width="312" height="211" align="center"/>
+<img src="{@docRoot}images/viewgroup.png" alt="" />
<p>
In order to attach the view hierarchy tree to the screen for rendering, your Activity must call the
diff --git a/docs/html/images/layoutparams.png b/docs/html/images/layoutparams.png
index 7473dcc..d99625e 100644
--- a/docs/html/images/layoutparams.png
+++ b/docs/html/images/layoutparams.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/adt-firstapp-setup.png b/docs/html/images/training/firstapp/adt-firstapp-setup.png
new file mode 100644
index 0000000..c092562
--- /dev/null
+++ b/docs/html/images/training/firstapp/adt-firstapp-setup.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/edittext_gravity.png b/docs/html/images/training/firstapp/edittext_gravity.png
new file mode 100644
index 0000000..f78e676
--- /dev/null
+++ b/docs/html/images/training/firstapp/edittext_gravity.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/edittext_wrap.png b/docs/html/images/training/firstapp/edittext_wrap.png
new file mode 100644
index 0000000..156776d
--- /dev/null
+++ b/docs/html/images/training/firstapp/edittext_wrap.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/firstapp.png b/docs/html/images/training/firstapp/firstapp.png
new file mode 100644
index 0000000..d69cd20
--- /dev/null
+++ b/docs/html/images/training/firstapp/firstapp.png
Binary files differ
diff --git a/docs/html/images/viewgroup.png b/docs/html/images/viewgroup.png
index a4c2518..2c86ddb 100644
--- a/docs/html/images/viewgroup.png
+++ b/docs/html/images/viewgroup.png
Binary files differ
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 6f06de3..fddbcc7 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -62,7 +62,7 @@
<div class="toggleable open">
<a href="#" onclick="return toggleDiv(this)"><img src=
"{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
- Android NDK, Revision 7c</a> <em>(March 2012)</em>
+ Android NDK, Revision 7c</a> <em>(April 2012)</em>
<div class="toggleme">
<p>This release of the NDK includes an important fix for Tegra2-based devices, and a few
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 3aafea9e..a70b0f3 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -191,9 +191,7 @@
<span style="display:none" class="zh-TW"></span>
</span>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7c</a>
- <span class="new">new!</span>
- </li>
+ <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7c</a></li>
<li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
</ul>
</li>
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
new file mode 100644
index 0000000..847163a
--- /dev/null
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -0,0 +1,363 @@
+page.title=Building a Simple User Interface
+parent.title=Building Your First App
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Running Your App
+previous.link=running-app.html
+next.title=Starting Another Activity
+next.link=starting-activity.html
+
+@jd:body
+
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+
+<ol>
+ <li><a href="#LinearLayout">Use a Linear Layout</a></li>
+ <li><a href="#TextInput">Add a Text Input Box</a></li>
+ <li><a href="#Strings">Add String Resources</a></li>
+ <li><a href="#Button">Add a Button</a></li>
+ <li><a href="#Weight">Make the Input Box Fill in the Screen Width</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a></li>
+</ul>
+
+
+</div>
+</div>
+
+
+
+<p>The graphical user interface for an Android app is built using a hierarchy of {@link
+android.view.View} and {@link android.view.ViewGroup} objects. {@link android.view.View} objects are
+usually UI widgets such as a button or text field and {@link android.view.ViewGroup} objects are
+invisible view containers that define how the child views are laid out, such as in a
+grid or a vertical list.</p>
+
+<p>Android provides an XML vocabulary that corresponds to the subclasses of {@link
+android.view.View} and {@link android.view.ViewGroup} so you can define your UI in XML with a
+hierarchy of view elements.</p>
+
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h2>Alternative Layouts</h2>
+ <p>Separating the UI layout into XML files is important for several reasons,
+but it's especially important on Android because it allows you to define alternative layouts for
+different screen sizes. For example, you can create two versions of a layout and tell
+the system to use one on "small" screens and the other on "large" screens. For more information,
+see the class about <a
+href="{@docRoot}training/supporting-hardware/index.html">Supporting Various Hardware</a>.</p>
+</div>
+</div>
+
+<img src="{@docRoot}images/viewgroup.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> Illustration of how {@link
+android.view.ViewGroup} objects form branches in the layout and contain {@link
+android.view.View} objects.</p>
+
+<p>In this lesson, you'll create a layout in XML that includes a text input field and a
+button. In the following lesson, you'll respond when the button is pressed by sending the
+content of the text field to another activity.</p>
+
+
+
+<h2 id="LinearLayout">Use a Linear Layout</h2>
+
+<p>Open the <code>main.xml</code> file from the <code>res/layout/</code>
+directory (every new Android project includes this file by default).</p>
+
+<p class="note"><strong>Note:</strong> In Eclipse, when you open a layout file, you’re first shown
+the ADT Layout Editor. This is an editor that helps you build layouts using WYSIWYG tools. For this
+lesson, you’re going to work directly with the XML, so click the <em>main.xml</em> tab at
+the bottom of the screen to open the XML editor.</p>
+
+<p>By default, the <code>main.xml</code> file includes a layout with a {@link
+android.widget.LinearLayout} root view group and a {@link android.widget.TextView} child view.
+You’re going to re-use the {@link android.widget.LinearLayout} in this lesson, but change its
+contents and layout orientation.</p>
+
+<p>First, delete the {@link android.widget.TextView} element and change the value
+<a href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:orientation">{@code
+android:orientation}</a> to be <code>"horizontal"</code>. The result looks like this:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal" >
+</LinearLayout>
+</pre>
+
+<p>{@link android.widget.LinearLayout} is a view group (a subclass of {@link
+android.view.ViewGroup}) that lays out child views in either a vertical or horizontal orientation,
+as specified by the <a
+href="{@docRoot}reference/android/widget/LinearLayout.html#attr_android:orientation">{@code
+android:orientation}</a> attribute. Each child of a {@link android.widget.LinearLayout} appears on
+the screen in the order in which it appears in the XML.</p>
+
+<p>The other two attributes, <a
+href="{@docRoot}reference/android/view/View.html#attr_android:layout_width">{@code
+android:layout_width}</a> and <a
+href="{@docRoot}reference/android/view/View.html#attr_android:layout_height">{@code
+android:layout_height}</a>, are required for all views in order to specify their size.</p>
+
+<p>Because the {@link android.widget.LinearLayout} is the root view in the layout, it should fill
+the entire screen area that's
+available to the app by setting the width and height to
+<code>"fill_parent"</code>.</p>
+
+<p class="note"><strong>Note:</strong> Beginning with Android 2.2 (API level 8),
+<code>"fill_parent"</code> has been renamed <code>"match_parent"</code> to better reflect the
+behavior. The reason is that if you set a view to <code>"fill_parent"</code> it does not expand to
+fill the remaining space after sibling views are considered, but instead expands to
+<em>match</em> the size of the parent view no matter what—it will overlap any sibling
+views.</p>
+
+<p>For more information about layout properties, see the <a
+href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layout</a> guide.</p>
+
+
+
+<h2 id="TextInput">Add a Text Input Box</h2>
+
+<p>To create a user-editable text box, add an {@link android.widget.EditText
+<EditText>} element inside the {@link android.widget.LinearLayout <LinearLayout>}. The {@link
+android.widget.EditText} class is a subclass of {@link android.view.View} that displays an editable
+text box.</p>
+
+<p>Like every {@link android.view.View} object, you must define certain XML attributes to specify
+the {@link android.widget.EditText} object's properties. Here’s how you should declare it
+inside the {@link android.widget.LinearLayout <LinearLayout>} element:</p>
+
+<pre>
+ <EditText android:id="@+id/edit_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:hint="@string/edit_message" />
+</pre>
+
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h3>About resource objects</h3>
+ <p>A resource object is simply a unique integer name that's associated with an app resource,
+such as a bitmap, layout file, or string.</p>
+ <p>Every resource has a
+corresponding resource object defined in your project's {@code gen/R.java} file. You can use the
+object names in the {@code R} class to refer to your resources, such as when you need to specify a
+string value for the <a
+href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
+attribute. You can also create arbitrary resource IDs that you associate with a view using the <a
+href="{@docRoot}reference/android/view/View.html#attr_android:id">{@code android:id}</a> attribute,
+which allows you to reference that view from other code.</p>
+ <p>The SDK tools generate the {@code R.java} each time you compile your app. You should never
+modify this file by hand.</p>
+</div>
+</div>
+
+<p>About these attributes:</p>
+
+<dl>
+<dt><a href="{@docRoot}reference/android/view/View.html#attr_android:id">{@code android:id}</a></dt>
+<dd>This provides a unique identifier for the view, which you can use to reference the object
+from your app code, such as to read and manipulate the object (you'll see this in the next
+lesson).
+
+<p>The at-symbol (<code>@</code>) is required when you want to refer to a resource object from
+XML, followed by the resource type ({@code id} in this case), then the resource name ({@code
+edit_message}). (Other resources can use the same name as long as they are not the same
+resource type—for example, the string resource uses the same name.)</p>
+
+<p>The plus-symbol (<code>+</code>) is needed only when you're defining a resource ID for the
+first time. It tells the SDK tools that the resource ID needs to be created. Thus, when the app is
+compiled, the SDK tools use the ID value, <code>edit_message</code>, to create a new identifier in
+your project's {@code gen/R.java} file that is now assiciated with the {@link
+android.widget.EditText} element. Once the resource ID is created, other references to the ID do not
+need the plus symbol. See the sidebox for more information about resource objects.</p></dd>
+
+<dt><a
+href="{@docRoot}reference/android/view/View.html#attr_android:layout_width">{@code
+android:layout_width}</a> and <a
+href="{@docRoot}reference/android/view/View.html#attr_android:layout_height">{@code
+android:layout_height}</a></dt>
+<dd>Instead of using specific sizes for the width and height, the <code>"wrap_content"</code> value
+specifies that the view should be only as big as needed to fit the contents of the view. If you
+were to instead use <code>"fill_parent"</code>, then the {@link android.widget.EditText}
+element would fill the screen, because it'd match the size of the parent {@link
+android.widget.LinearLayout}. For more information, see the <a
+href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> guide.</dd>
+
+<dt><a
+href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code
+android:hint}</a></dt>
+<dd>This is a default string to display when the text box is empty. Instead of using a hard-coded
+string as the value, the value given in this example refers to a string resource. When you add the
+{@code
+"@string/edit_message"} value, you’ll see a compiler error because there’s no matching string
+resource by that name. You'll fix this in the next section by defining the string
+resource.</dd>
+</dl>
+
+
+
+<h2 id="Strings">Add String Resources</h2>
+
+<p>When you need to add text in the user interface, you should always specify each string of text in
+a resource file. String resources allow you to maintain a single location for all string
+values, which makes it easier to find and update text. Externalizing the strings also allows you to
+localize your app to different languages by providing alternative definitions for each
+string.</p>
+
+<p>By default, your Android project includes a string resource file at
+<code>res/values/strings.xml</code>. Open this file, delete the existing <code>"hello"</code>
+string, and add one for the
+<code>"edit_message"</code> string used by the {@link android.widget.EditText <EditText>}
+element.</p>
+
+<p>While you’re in this file, also add a string for the button you’ll soon add, called
+<code>"button_send"</code>.</p>
+
+<p>The result for <code>strings.xml</code> looks like this:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">My First App</string>
+ <string name="edit_message">Enter a message</string>
+ <string name="button_send">Send</string>
+</resources>
+</pre>
+
+<p>For more information about using string resources to localize your app for several languages,
+see the <a
+href="{@docRoot}training/basics/supporting-devices/index.html">Supporting Various Devices</a>
+class.</p>
+
+
+
+
+<h2 id="Button">Add a Button</h2>
+
+<p>Now add a {@link android.widget.Button <Button>} to the layout, immediately following the
+{@link android.widget.EditText <EditText>} element:</p>
+
+<pre>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button_send" />
+</pre>
+
+<p>The height and width are set to <code>"wrap_content"</code> so the button is only as big as
+necessary to fit the button's text.</p>
+
+
+
+<h2 id="Weight">Make the Input Box Fill in the Screen Width</h2>
+
+<p>The layout is currently designed so that both the {@link android.widget.EditText} and {@link
+android.widget.Button} widgets are only as big as necessary to fit their content, as shown in
+figure 2.</p>
+
+<img src="{@docRoot}images/training/firstapp/edittext_wrap.png" />
+<p class="img-caption"><strong>Figure 2.</strong> The {@link android.widget.EditText} and {@link
+android.widget.Button} widgets have their widths set to
+<code>"wrap_content"</code>.</p>
+
+<p>This works fine for the button, but not as well for the text box, because the user might type
+something longer and there's extra space left on the screen. So, it'd be nice to fill that width
+using the text box.
+{@link android.widget.LinearLayout} enables such a design with the <em>weight</em> property, which
+you can specify using the <a
+href="{@docRoot}reference/android/widget/LinearLayout.LayoutParams.html#weight">{@code
+android:layout_weight}</a> attribute.</p>
+
+<p>The weight value allows you to specify the amount of remaining space each view should consume,
+relative to the amount consumed by sibling views, just like the ingredients in a drink recipe: "2
+parts vodka, 1 part coffee liquer" means two-thirds of the drink is vodka. For example, if you give
+one view a weight of 2 and another one a weight of 1, the sum is 3, so the first view gets 2/3 of
+the remaining space and the second view gets the rest. If you give a third view a weight of 1,
+then the first view now gets 1/2 the remaining space, while the remaining two each get 1/4.</p>
+
+<p>The default weight for all views is 0, so if you specify any weight value
+greater than 0 to only one view, then that view fills whatever space remains after each view is
+given the space it requires. So, to fill the remaining space with the {@link
+android.widget.EditText} element, give it a weight of 1 and leave the button with no weight.</p>
+
+<pre>
+ <EditText
+ android:layout_weight="1"
+ ... />
+</pre>
+
+<p>In order to improve the layout efficiency when you specify the weight, you should change the
+width of the {@link android.widget.EditText} to be
+zero (0dp). Setting the width to zero improves layout performance because using
+<code>"wrap_content"</code> as the width requires the system to calculate a width that is
+ultimately irrelevant because the weight value requires another width calculation to fill the
+remaining space.</p>
+<pre>
+ <EditText
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ ... />
+</pre>
+
+<p>Figure 3
+shows the result when you assign all weight to the {@link android.widget.EditText} element.</p>
+
+<img src="{@docRoot}images/training/firstapp/edittext_gravity.png" />
+<p class="img-caption"><strong>Figure 3.</strong> The {@link android.widget.EditText} widget is
+given all the layout weight, so fills the remaining space in the {@link
+android.widget.LinearLayout}.</p>
+
+<p>Here’s how your complete layout file should now look:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal">
+ <EditText android:id="@+id/edit_message"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:hint="@string/edit_message" />
+ <Button android:id="@+id/button_send"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button_send" />
+</LinearLayout>
+</pre>
+
+<p>This layout is applied by the default {@link android.app.Activity} class
+that the SDK tools generated when you created the project, so you can now run the app to see the
+results:</p>
+
+<ul>
+ <li>In Eclipse, click <strong>Run</strong> from the toolbar.</li>
+ <li>Or from a command line, change directories to the root of your Android project and
+execute:
+<pre>
+ant debug
+adb install bin/MyFirstApp-debug.apk
+</pre></li>
+</ul>
+
+<p>Continue to the next lesson to learn how you can respond to button presses, read content
+from the text field, start another activity, and more.</p>
+
+
+
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
new file mode 100644
index 0000000..5a89f2e
--- /dev/null
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -0,0 +1,142 @@
+page.title=Creating an Android Project
+parent.title=Building Your First App
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Running Your App
+next.link=running-app.html
+
+@jd:body
+
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+
+<ol>
+ <li><a href="#Eclipse">Create a Project with Eclipse</a></li>
+ <li><a href="#CommandLine">Create a Project with Command Line Tools</a></li>
+</ol>
+
+<h2>You should also read</h2>
+
+<ul>
+ <li><a href="{@docRoot}sdk/installing.html">Installing the
+SDK</a></li>
+ <li><a href="{@docRoot}guide/developing/projects/index.html">Managing Projects</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>An Android project contains all the files that comprise the source code for your Android
+app. The Android SDK tools make it easy to start a new Android project with a set of
+default project directories and files.</p>
+
+<p>This lesson
+shows how to create a new project either using Eclipse (with the ADT plugin) or using the
+SDK tools from a command line.</p>
+
+<p class="note"><strong>Note:</strong> You should already have the Android SDK installed, and if
+you're using Eclipse, you should have installed the <a
+href="{@docRoot}sdk/eclipse-adt.html">ADT plugin</a> as well. If you have not installed
+these, see <a href="{@docRoot}sdk/installing.html">Installing the Android SDK</a> and return here
+when you've completed the installation.</p>
+
+
+<h2 id="Eclipse">Create a Project with Eclipse</h2>
+
+<div class="figure" style="width:416px">
+<img src="{@docRoot}images/training/firstapp/adt-firstapp-setup.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> The new project wizard in Eclipse.</p>
+</div>
+
+<ol>
+ <li>In Eclipse, select <strong>File > New > Project</strong>.
+The resulting dialog should have a folder labeled <em>Android</em>. (If you don’t see the
+<em>Android</em> folder,
+then you have not installed the ADT plugin—see <a
+href="{@docRoot}sdk/eclipse-adt.html#installing">Installing the ADT Plugin</a>).</li>
+ <li>Open the <em>Android</em> folder, select <em>Android Project</em> and click
+<strong>Next</strong>.</li>
+ <li>Enter a project name (such as "MyFirstApp") and click <strong>Next</strong>.</li>
+ <li>Select a build target. This is the platform version against which you will compile your app.
+<p>We recommend that you select the latest version possible. You can still build your app to
+support older versions, but setting the build target to the latest version allows you to
+easily optimize your app for a great user experience on the latest Android-powered devices.</p>
+<p>If you don't see any built targets listed, you need to install some using the Android SDK
+Manager tool. See <a href="{@docRoot}sdk/installing.html#AddingComponents">step 4 in the
+installing guide</a>.</p>
+<p>Click <strong>Next</strong>.</p></li>
+ <li>Specify other app details, such as the:
+ <ul>
+ <li><em>Application Name</em>: The app name that appears to the user. Enter "My First
+App".</li>
+ <li><em>Package Name</em>: The package namespace for your app (following the same
+rules as packages in the Java programming language). Your package name
+must be unique across all packages installed on the Android system. For this reason, it's important
+that you use a standard domain-style package name that’s appropriate to your company or
+publisher entity. For
+your first app, you can use something like "com.example.myapp." However, you cannot publish your
+app using the "com.example" namespace.</li>
+ <li><em>Create Activity</em>: This is the class name for the primary user activity in your
+app (an activity represents a single screen in your app). Enter "MyFirstActivity".</li>
+ <li><em>Minimum SDK</em>: Select <em>4 (Android 1.6)</em>.
+ <p>Because this version is lower than the build target selected for the app, a warning
+appears, but that's alright. You simply need to be sure that you don't use any APIs that require an
+<a href="{@docRoot}guide/appendix/api-levels.html">API level</a> greater than the minimum SDK
+version without first using some code to verify the device's system version (you'll see this in some
+other classes).</p>
+ </li>
+ </ul>
+ <p>Click <strong>Finish</strong>.</p>
+ </li>
+</ol>
+
+<p>Your Android project is now set up with some default files and you’re ready to begin
+building the app. Continue to the <a href="running-app.html">next lesson</a>.</p>
+
+
+
+<h2 id="CommandLine">Create a Project with Command Line Tools</h2>
+
+<p>If you're not using the Eclipse IDE with the ADT plugin, you can instead create your project
+using the SDK tools in a command line:</p>
+
+<ol>
+ <li>Change directories into the Android SDK’s <code>tools/</code> path.</li>
+ <li>Execute:
+<pre class="no-pretty-print">android list targets</pre>
+<p>This prints a list of the available Android platforms that you’ve downloaded for your SDK. Find
+the platform against which you want to compile your app. Make a note of the target id. We
+recommend that you select the highest version possible. You can still build your app to
+support older versions, but setting the build target to the latest version allows you to optimize
+your app for the latest devices.</p>
+<p>If you don't see any targets listed, you need to
+install some using the Android SDK
+Manager tool. See <a href="{@docRoot}sdk/installing.html#AddingComponents">step 4 in the
+installing guide</a>.</p></li>
+ <li>Execute:
+<pre class="no-pretty-print">
+android create project --target <target-id> --name MyFirstApp \
+--path <path-to-workspace>/MyFirstApp --activity MyFirstActivity \
+--package com.example.myapp
+</pre>
+<p>Replace <code><target-id></code> with an id from the list of targets (from the previous step)
+and replace
+<code><path-to-workspace></code> with the location in which you want to save your Android
+projects.</p></li>
+</ol>
+
+<p>Your Android project is now set up with several default configurations and you’re ready to begin
+building the app. Continue to the <a href="running-app.html">next lesson</a>.</p>
+
+<p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
+<code>tools/</code> directory to your <code>PATH</code> environment variable.</p>
+
+
+
+
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
new file mode 100644
index 0000000..a95ed8e
--- /dev/null
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -0,0 +1,64 @@
+page.title=Building Your First App
+
+trainingnavtop=true
+startpage=true
+next.title=Creating an Android Project
+next.link=creating-project.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+
+<ul>
+ <li>Android 1.6 or higher</li>
+ <li><a href="http://developer.android.com/sdk/index.html">Android SDK</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>Welcome to Android application development!</p>
+
+<p>This class teaches you how to build your first Android app. You’ll learn how to create an Android
+project and run a debuggable version of the app. You'll also learn some fundamentals of Android app
+design, including how to build a simple user interface and handle user input.</p>
+
+<p>Before you start this class, be sure that you have your development environment set up. You need
+to:</p>
+<ol>
+ <li>Download the Android SDK Starter Package.</li>
+ <li>Install the ADT plugin for Eclipse (if you’ll use the Eclipse IDE).</li>
+ <li>Download the latest SDK tools and platforms using the SDK Manager.</li>
+</ol>
+
+<p>If you haven't already done this setup, read <a href="{@docRoot}sdk/installing.html">Installing
+the SDK</a>. Once you've finished the setup, you're ready to begin this class.</p>
+
+<p>This class uses a tutorial format that incrementally builds a small Android app in order to teach
+you some fundamental concepts about Android development, so it's important that you follow each
+step.</p>
+
+<p><strong><a href="creating-project.html">Start the first lesson ›</a></strong></p>
+
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt><b><a href="creating-project.html">Creating an Android Project</a></b></dt>
+ <dd>Shows how to create a project for an Android app, which includes a set of default
+app files.</dd>
+
+ <dt><b><a href="running-app.html">Running Your Application</a></b></dt>
+ <dd>Shows how to run your app on an Android-powered device or the Android
+emulator.</dd>
+
+ <dt><b><a href="building-ui.html">Building a Simple User Interface</a></b></dt>
+ <dd>Shows how to create a new user interface using an XML file.</dd>
+
+ <dt><b><a href="starting-activity.html">Starting Another Activity</a></b></dt>
+ <dd>Shows how to respond to a button press, start another activity, send it some
+data, then receive the data in the subsequent activity.</dd>
+</dl>
diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
new file mode 100644
index 0000000..2398fa0
--- /dev/null
+++ b/docs/html/training/basics/firstapp/running-app.jd
@@ -0,0 +1,178 @@
+page.title=Running Your App
+parent.title=Building Your First App
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Creating a Project
+previous.link=creating-project.html
+next.title=Building a Simple User Interface
+next.link=building-ui.html
+
+@jd:body
+
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+
+<ol>
+ <li><a href="#RealDevice">Run on a Real Device</a></li>
+ <li><a href="#Emulator">Run on the Emulator</a></li>
+</ol>
+
+<h2>You should also read</h2>
+
+<ul>
+ <li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li>
+ <li><a href="{@docRoot}guide/developing/devices/index.html">Managing Virtual Devices</a></li>
+ <li><a href="{@docRoot}guide/developing/projects/index.html">Managing Projects</a></li>
+</ul>
+
+
+</div>
+</div>
+
+
+<p>If you followed the <a href="{@docRoot}creating-project.html">previous lesson</a> to create an
+Android project, it includes a default set of "Hello World" source files that allow you to
+run the app right away.</p>
+
+<p>How you run your app depends on two things: whether you have a real Android-powered device and
+whether you’re using Eclipse. This lesson shows you how to install and run your app on a
+real device and on the Android emulator, and in both cases with either Eclipse or the command line
+tools.</p>
+
+<p>Before you run your app, you should be aware of a few directories and files in the Android
+project:</p>
+
+<dl>
+ <dt><code>AndroidManifest.xml</code></dt>
+ <dd>This manifest file describes the fundamental characteristics of the app and defines each of
+its components. You'll learn about various declarations in this file as you read more training
+classes.</dd>
+ <dt><code>src/</code></dt>
+ <dd>Directory for your app's main source files. By default, it includes an {@link
+android.app.Activity} class that runs when your app is launched using the app icon.</dd>
+ <dt><code>res/</code></dt>
+ <dd>Contains several sub-directories for app resources. Here are just a few:
+ <dl style="margin-top:1em">
+ <dt><code>drawable-hdpi/</code></dt>
+ <dd>Directory for drawable objects (such as bitmaps) that are designed for high-density
+(hdpi) screens. Other drawable directories contain assets designed for other screen densities.</dd>
+ <dt><code>layout/</code></dt>
+ <dd>Directory for files that define your app's user interface.</dd>
+ <dt><code>values/</code></dt>
+ <dd>Directory for other various XML files that contain a collection of resources, such as
+string and color definitions.</dd>
+ </dl>
+ </dd>
+</dl>
+
+<p>When you build and run the default Android project, the default {@link android.app.Activity}
+class in the <code>src/</code> directory starts and loads a layout file from the
+<code>layout/</code> directory, which includes a "Hello World" message. Not real exciting, but it's
+important that you understand how to build and run your app before adding real functionality to
+the app.</p>
+
+
+
+<h2 id="RealDevice">Run on a Real Device</h2>
+
+<p>Whether you’re using Eclipse or the command line, you need to:</p>
+
+<ol>
+ <li>Plug in your Android-powered device to your machine with a USB cable.
+If you’re developing on Windows, you might need to install the appropriate USB driver for your
+device. For help installing drivers, see the <a href=”{@docRoot}sdk/oem-usb.html”>OEM USB
+Drivers</a> document.</li>
+ <li>Ensure that <strong>USB debugging</strong> is enabled in the device Settings (open Settings
+and navitage to <strong>Applications > Development</strong> on most devices, or select
+<strong>Developer options</strong> on Android 4.0 and higher).</li>
+</ol>
+
+<p>To run the app from Eclipse, open one of your project's files and click
+<strong>Run</strong> from the toolbar. Eclipse installs the app on your connected device and starts
+it.</p>
+
+
+<p>Or to run your app from a command line:</p>
+
+<ol>
+ <li>Change directories to the root of your Android project and execute:
+<pre class="no-pretty-print">ant debug</pre></li>
+ <li>Make sure the Android SDK <code>platform-tools/</code> directory is included in your
+<code>PATH</code> environment variable, then execute:
+<pre class="no-pretty-print">adb install bin/MyFirstApp-debug.apk</pre></li>
+ <li>On your device, locate <em>MyFirstActivity</em> and open it.</li>
+</ol>
+
+<p>To start adding stuff to the app, continue to the <a href="building-ui.html">next
+lesson</a>.</p>
+
+
+
+<h2 id="Emulator">Run on the Emulator</h2>
+
+<p>Whether you’re using Eclipse or the command line, you need to first create an <a
+href="{@docRoot}guide/developing/devices/index.html">Android Virtual
+Device</a> (AVD). An AVD is a
+device configuration for the Android emulator that allows you to model
+different device configurations.</p>
+
+<div class="figure" style="width:457px">
+ <img src="{@docRoot}images/screens_support/avds-config.png" alt="" />
+ <p class="img-caption"><strong>Figure 1.</strong> The AVD Manager showing a few virtual
+devices.</p>
+</div>
+
+<p>To create an AVD:</p>
+<ol>
+ <li>Launch the Android Virtual Device Manager:
+ <ol type="a">
+ <li>In Eclipse, select <strong>Window > AVD Manager</strong>, or click the <em>AVD
+Manager</em> icon in the Eclipse toolbar.</li>
+ <li>From the command line, change directories to <code><sdk>/tools/</code> and execute:
+<pre class="no-pretty-print">./android avd</pre></li>
+ </ol>
+ </li>
+ <li>In the <em>Android Virtual Device Device Manager</em> panel, click <strong>New</strong>.</li>
+ <li>Fill in the details for the AVD.
+Give it a name, a platform target, an SD card size, and a skin (HVGA is default).</li>
+ <li>Click <strong>Create AVD</strong>.</li>
+ <li>Select the new AVD from the <em>Android Virtual Device Manager</em> and click
+<strong>Start</strong>.</li>
+ <li>After the emulator boots up, unlock the emulator screen.</li>
+</ol>
+
+<p>To run the app from Eclipse, open one of your project's files and click
+<strong>Run</strong> from the toolbar. Eclipse installs the app on your AVD and starts it.</p>
+
+
+<p>Or to run your app from the command line:</p>
+
+<ol>
+ <li>Change directories to the root of your Android project and execute:
+<pre class="no-pretty-print">ant debug</pre></li>
+ <li>Make sure the Android SDK <code>platform-tools/</code> directory is included in your
+<code>PATH</code> environment
+variable, then execute:
+<pre class="no-pretty-print">adb install bin/MyFirstApp-debug.apk</pre></li>
+ <li>On the emulator, locate <em>MyFirstActivity</em> and open it.</li>
+</ol>
+
+
+<p>To start adding stuff to the app, continue to the <a href="building-ui.html">next
+lesson</a>.</p>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
new file mode 100644
index 0000000..16a6fd8
--- /dev/null
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -0,0 +1,308 @@
+page.title=Starting Another Activity
+parent.title=Building Your First App
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Building a Simpler User Interface
+previous.link=building-ui.html
+
+@jd:body
+
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+
+<ol>
+ <li><a href="#RespondToButton">Respond to the Send Button</a></li>
+ <li><a href="#BuildIntent">Build an Intent</a></li>
+ <li><a href="#StartActivity">Start the Second Activity</a></li>
+ <li><a href="#CreateActivity">Create the Second Activity</a>
+ <ol>
+ <li><a href="#AddToManifest">Add it to the manifest</a></li>
+ </ol>
+ </li>
+ <li><a href="#ReceiveIntent">Receive the Intent</a></li>
+ <li><a href="#DisplayMessage">Display the Message</a></li>
+</ol>
+
+<h2>You should also read</h2>
+
+<ul>
+ <li><a href="{@docRoot}sdk/installing.html">Installing the
+SDK</a></li>
+</ul>
+
+
+</div>
+</div>
+
+
+
+<p>After completing the <a href="building-ui.html">previous lesson</a>, you have an app that
+shows an activity (a single screen) with a text box and a button. In this lesson, you’ll add some
+code to <code>MyFirstActivity</code> that
+starts a new activity when the user selects the Send button.</p>
+
+
+<h2 id="RespondToButton">Respond to the Send Button</h2>
+
+<p>To respond to the button's on-click event, open the <code>main.xml</code> layout file and add the
+<a
+href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>
+attribute to the {@link android.widget.Button <Button>} element:</p>
+
+<pre>
+<Button android:id="@+id/button_send"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button_send"
+ android:onClick="sendMessage" />
+</pre>
+
+<p>The <a
+href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code
+android:onClick}</a> attribute’s value, <code>sendMessage</code>, is the name of a method in your
+activity that you want to call when the user selects the button.</p>
+
+<p>Add the corresponding method inside the <code>MyFirstActivity</code> class:</p>
+
+<pre>
+/** Called when the user selects the Send button */
+public void sendMessage(View view) {
+ // Do something in response to button
+}
+</pre>
+
+<p class="note"><strong>Tip:</strong> In Eclipse, press Ctrl + Shift + O to import missing classes
+(Cmd + Shift + O on Mac).</p>
+
+<p>Note that, in order for the system to match this method to the method name given to <a
+href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>,
+the signature must be exactly as shown. Specifically, the method must:</p>
+
+<ul>
+<li>Be public</li>
+<li>Have a void return value</li>
+<li>Have a {@link android.view.View} as the only parameter (this will be the {@link
+android.view.View} that was clicked)</li>
+</ul>
+
+<p>Next, you’ll fill in this method to read the contents of the text box and deliver that text to
+another activity.</p>
+
+
+
+<h2 id="BuildIntent">Build an Intent</h2>
+
+<p>An {@link android.content.Intent} is an object that provides runtime binding between separate
+components (such as two activities). The {@link android.content.Intent} represents an
+app’s "intent to do something." You can use an {@link android.content.Intent} for a wide
+variety of tasks, but most often they’re used to start another activity.</p>
+
+<p>Inside the {@code sendMessage()} method, create an {@link android.content.Intent} to start
+an activity called {@code DisplayMessageActvity}:</p>
+
+<pre>
+Intent intent = new Intent(this, DisplayMessageActivity.class);
+</pre>
+
+<p>The constructor used here takes two parameters:</p>
+<ul>
+ <li>A {@link
+android.content.Context} as its first parameter ({@code this} is used because the {@link
+android.app.Activity} class is a subclass of {@link android.content.Context})
+ <li>The {@link java.lang.Class} of the app component to which the system should deliver
+the {@link android.content.Intent} (in this case, the activity that should be started)
+</ul>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h3>Sending an intent to other apps</h3>
+ <p>The intent created in this lesson is what's considered an <em>explicit intent</em>, because the
+{@link android.content.Intent}
+specifies the exact app component to which the intent should be given. However, intents
+can also be <em>implicit</em>, in which case the {@link android.content.Intent} does not specify
+the desired component, but allows any app installed on the device to respond to the intent
+as long as it satisfies the meta-data specifications for the action that's specified in various
+{@link android.content.Intent} parameters. For more informations, see the class about <a
+href="{@docRoot}training/intents/index.html">Interacting with Other Apps</a>.</p>
+</div>
+</div>
+
+<p class="note"><strong>Note:</strong> The reference to {@code DisplayMessageActivity}
+will raise an error if you’re using an IDE such as Eclipse because the class doesn’t exist yet.
+Ignore the error for now; you’ll create the class soon.</p>
+
+<p>An intent not only allows you to start another activity, but can carry a bundle of data to the
+activity as well. So, use {@link android.app.Activity#findViewById findViewById()} to get the
+{@link android.widget.EditText} element and add its message to the intent:</p>
+
+<pre>
+Intent intent = new Intent(this, DisplayMessageActivity.class);
+EditText editText = (EditText) findViewById(R.id.edit_message);
+String message = editText.getText().toString();
+intent.putExtra(EXTRA_MESSAGE, message);
+</pre>
+
+<p>An {@link android.content.Intent} can carry a collection of various data types as key-value
+pairs called <em>extras</em>. The {@link android.content.Intent#putExtra putExtra()} method takes a
+string as the key and the value in the second parameter.</p>
+
+<p>In order for the next activity to query the extra data, you should define your keys using a
+public constant. So add the {@code EXTRA_MESSAGE} definition to the top of the {@code
+MyFirstActivity} class:</p>
+
+<pre>
+public class MyFirstActivity extends Activity {
+ public final static String EXTRA_MESSAGE = "com.example.myapp.MESSAGE";
+ ...
+}
+</pre>
+
+<p>It's generally a good practice to define keys for extras with your app's package name as a prefix
+to ensure it's unique, in case your app interacts with other apps.</p>
+
+
+<h2 id="StartActivity">Start the Second Activity</h2>
+
+<p>To start an activity, you simply need to call {@link android.app.Activity#startActivity
+startActivity()} and pass it your {@link android.content.Intent}.</p>
+
+<p>The system receives this call and starts an instance of the {@link android.app.Activity}
+specified by the {@link android.content.Intent}.</p>
+
+<p>With this method included, the complete {@code sendMessage()} method that's invoked by the Send
+button now looks like this:</p>
+
+<pre>
+/** Called when the user selects the Send button */
+public void sendMessage(View view) {
+ Intent intent = new Intent(this, DisplayMessageActivity.class);
+ EditText editText = (EditText) findViewById(R.id.edit_message);
+ String message = editText.getText().toString();
+ intent.putExtra(EXTRA_MESSAGE, message);
+ startActivity(intent);
+}
+</pre>
+
+<p>Now you need to create the {@code DisplayMessageActivity} class in order for this to
+work.</p>
+
+
+
+<h2 id="CreateActivity">Create the Second Activity</h2>
+
+<p>In your project, create a new class file under the <code>src/<package-name>/</code>
+directory called <code>DisplayMessageActivity.java</code>.</p>
+
+<p class="note"><strong>Tip:</strong> In Eclipse, right-click the package name under the
+<code>src/</code> directory and select <strong>New > Class</strong>.
+Enter "DisplayMessageActivity" for the name and {@code android.app.Activity} for the superclass.</p>
+
+<p>Inside the class, add the {@link android.app.Activity#onCreate onCreate()} callback method:</p>
+
+<pre>
+public class DisplayMessageActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
+</pre>
+
+<p>All subclasses of {@link android.app.Activity} must implement the {@link
+android.app.Activity#onCreate onCreate()} method. The system calls this when creating a new
+instance of the activity. It is where you must define the activity layout and where you should
+initialize essential activity components.</p>
+
+
+
+<h3 id="AddToManifest">Add it to the manifest</h3>
+
+<p>You must declare all activities in your manifest file, <code>AndroidManifest.xml</code>, using an
+<a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element.</p>
+
+<p>Because {@code DisplayMessageActivity} is invoked using an explicit intent, it does not require
+any intent filters (such as those you can see in the manifest for <code>MyFirstActivity</code>). So
+the declaration for <code>DisplayMessageActivity</code> can be simply one line of code inside the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
+element:</p>
+
+<pre>
+<application ... >
+ <activity android:name="com.example.myapp.DisplayMessageActivity" />
+ ...
+</application>
+</pre>
+
+<p>The app is now runnable because the {@link android.content.Intent} in the
+first activity now resolves to the {@code DisplayMessageActivity} class. If you run the app now,
+pressing the Send button starts the
+second activity, but it doesn't show anything yet.</p>
+
+
+<h2 id="ReceiveIntent">Receive the Intent</h2>
+
+<p>Every {@link android.app.Activity} is invoked by an {@link android.content.Intent}, regardless of
+how the user navigated there. You can get the {@link android.content.Intent} that started your
+activity by calling {@link android.app.Activity#getIntent()} and the retrieve data contained
+within it.</p>
+
+<p>In the {@code DisplayMessageActivity} class’s {@link android.app.Activity#onCreate onCreate()}
+method, get the intent and extract the message delivered by {@code MyFirstActivity}:</p>
+
+<pre>
+Intent intent = getIntent();
+String message = intent.getStringExtra(MyFirstActivity.EXTRA_MESSAGE);
+</pre>
+
+
+
+<h2 id="DisplayMessage">Display the Message</h2>
+
+<p>To show the message on the screen, create a {@link android.widget.TextView} widget and set the
+text using {@link android.widget.TextView#setText setText()}. Then add the {@link
+android.widget.TextView} as the root view of the activity’s layout by passing it to {@link
+android.app.Activity#setContentView setContentView()}.</p>
+
+<p>The complete {@link android.app.Activity#onCreate onCreate()} method for {@code
+DisplayMessageActivity} now looks like this:</p>
+
+<pre>
+@Override
+public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Get the message from the intent
+ Intent intent = getIntent();
+ String message = intent.getStringExtra(MyFirstActivity.EXTRA_MESSAGE);
+
+ // Create the text view
+ TextView textView = new TextView(this);
+ textView.setTextSize(40);
+ textView.setText(message);
+
+ setContentView(textView);
+}
+</pre>
+
+<p>You can now run the app, type a message in the text box, press Send, and view the message on the
+second activity.</p>
+
+<img src="{@docRoot}images/training/firstapp/firstapp.png" />
+<p class="img-caption"><strong>Figure 1.</strong> Both activities in the final app, running
+on Android 4.0.
+
+<p>That's it, you've built your first Android app!</p>
+
+<p>To learn more about building Android apps, continue to follow the
+basic training classes. The next class is <a
+href="{@docRoot}training/activity-lifecycle/index.html">Managing the Activity Lifecycle</a>.</p>
+
+
+
+
diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd
new file mode 100644
index 0000000..49ea81d
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/index.jd
@@ -0,0 +1,49 @@
+page.title=Supporting Different Devices
+
+trainingnavtop=true
+startpage=true
+next.title=Supporting Multiple Languages
+next.link=languages.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 1.6 or higher</li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/resources/index.html">Application Resources</a></li>
+ <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></li>
+</ul>
+
+
+</div>
+</div>
+
+<p>Android devices come in many shapes and sizes all around the world. With a wide range of device
+types, you have an opportunity to reach a huge audience with your app. In order to be as successful
+as possible on Android, your app needs to adapt to various device configurations. Some of the
+important variations that you should consider include different languages, screen sizes, and
+versions of the Android platform.</p>
+
+<p>This class teaches you how to use basic platform features that leverage alternative
+resources and other features so your app can provide an optimized user experience on a
+variety of Android-compatible devices, using a single application package (APK).</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt><b><a href="languages.html">Supporting Different Languages</a></b></dt>
+ <dd>Learn how to support multiple languages with alternative string resources.</dd>
+ <dt><b><a href="screens.html">Supporting Different Screens</a></b></dt>
+ <dd>Learn how to optimize the user experience for different screen sizes and densities.</dd>
+ <dt><b><a href="platforms.html">Supporting Different Platform Versions</a></b></dt>
+ <dd>Learn how to use APIs available in new versions of Android while continuing to support
+older versions of Android.</dd>
+</dl>
+
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
new file mode 100644
index 0000000..fcc95c2
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -0,0 +1,134 @@
+page.title=Supporting Different Languages
+parent.title=Supporting Different Devices
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Supporting Different Screens
+next.link=screens.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This class teaches you to</h2>
+ <ol>
+ <li><a href="#CreateDirs">Create Locale Directories and String Files</a></li>
+ <li><a href="#UseString">Use the String Resources</a></li>
+ </ol>
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/resources/localization.html">Localization</a></li>
+ </ul>
+ </div>
+</div>
+
+<p>It’s always a good practice to extract UI strings from your app code and keep them
+in an external file. Android makes this easy with a resources directory in each Android
+project.</p>
+
+<p>If you created your project using the Android SDK
+Tools (read <a href="{@docRoot}training/basics/firstapp/creating-project.html">Creating an
+Android Project</a>), the tools create a <code>res/</code> directory in the top level of
+the project. Within this <code>res/</code> directory are subdirectories for various resource
+types. There are also a few default files such as <code>res/values/strings.xml</code>, which holds
+your string values.</p>
+
+
+<h2 id="CreateDirs">Create Locale Directories and String Files</h2>
+
+<p>To add support for more languages, create additional <code>values</code> directories inside
+<code>res/</code> that include a hyphen and the ISO country code at the end of the
+directory name. For example, <code>values-es/</code> is the directory containing simple
+resourcess for the Locales with the language code "es". Android loads the appropriate resources
+according to the locale settings of the device at run time.</p>
+
+<p>Once you’ve decided on the languages you will support, create the resource subdirectories and
+string resource files. For example:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ values/
+ strings.xml
+ values-es/
+ strings.xml
+ values-fr/
+ strings.xml
+</pre>
+
+<p>Add the string values for each locale into the appropriate file.</p>
+
+<p>At runtime, the Android system uses the appropriate set of string resources based on the
+locale currently set for the user's device.</p>
+
+<p>For example, the following are some different string resource files for different languages.</p>
+
+
+<p>English (default locale), <code>/values/strings.xml</code>:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title">My Application</string>
+ <string name="hello_world">Hello World!</string>
+</resources>
+</pre>
+
+
+<p>Spanish, <code>/values-es/strings.xml</code>:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title">Mi Aplicación</string>
+ <string name="hello_world">Hola Mundo!</string>
+</resources>
+</pre>
+
+
+<p>French, <code>/values-fr/strings.xml</code>:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title">Ma Application</string>
+ <string name="hello_world">Bonjour tout le Monde!</string>
+</resources>
+</pre>
+
+
+<h2 id="UseString">Use the String Resources</h2>
+
+<p>You can reference your string resources in your source code and other XML files using the
+resource name defined by the {@code <string>} element's {@code name} attribute.</p>
+
+<p>In your source code, you can refer to a string resource with the syntax {@code
+R.string.<string_name>}. There are a variety of methods that accept a string resource this
+way.</p>
+
+<p>For example:</p>
+
+<pre>
+// Get a string resource from your app's {@link android.content.res.Resources}
+String hello = {@link android.content.Context#getResources()}.getString(R.string.hello_world);
+
+// Or supply a string resource to a method that requires a string
+TextView textView = new TextView(this);
+textView.setText(R.string.hello_world);
+</pre>
+
+<p>In other XML files, you can refer to a string resource with the syntax {@code
+@string/<string_name>} whenever the XML attribute accepts a string value.</p>
+
+<p>For example:</p>
+
+<pre>
+<TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hello_world" />
+</pre>
+
+
+
diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd
new file mode 100644
index 0000000..0d4e7d9
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/platforms.jd
@@ -0,0 +1,138 @@
+page.title=Supporting Different Platform Versions
+parent.title=Supporting Different Devices
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Supporting Different Screens
+previous.link=screens.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#sdk-versions">Specify Minimum and Target API Levels</a></li>
+ <li><a href="#version-codes">Check System Version at Runtime</a></li>
+ <li><a href="#style-themes">Use Platform Styles and Themes</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a></li>
+ <li><a
+href="{@docRoot}sdk/compatibility-library.html">Android Support Library</a></li>
+ </ul>
+ </div>
+</div>
+
+<p>While the latest versions of Android often provide great APIs for your app, you should continue
+to support older versions of Android until more devices get updated. This
+lesson shows you how to take advantage of the latest APIs while continuing to support older
+versions as well.</p>
+
+<p>The dashboard for <a
+href="http://developer.android.com/resources/dashboard/platform-versions.html">Platform Versions</a>
+is updated regularly to show the distribution of active
+devices running each version of Android, based on the number of devices that visit the Google Play
+Store. Generally, it’s a good practice to support about 90% of the active devices, while
+targeting your app to the latest version.</p>
+
+<p class="note"><strong>Tip:</strong> In order to provide the best features and
+functionality across several Android versions, you should use the <a
+href="{@docRoot}sdk/compatibility-library.html">Android Support Library</a> in your app,
+which allows you to use several recent platform APIs on older versions.</p>
+
+
+
+<h2 id="sdk-versions">Specify Minimum and Target API Levels</h2>
+
+<p>The <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a> file
+describes details about your app and
+identifies which versions of Android it supports. Specifically, the <code>minSdkVersion</code>
+and <code>targetSdkVersion</code> attributes for the <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code <uses-sdk}</a> element
+identify the lowest API level with which your app is compatible and the highest API level against
+which you’ve designed and tested your app.</p>
+
+<p>For example:</p>
+
+<pre>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
+ <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />
+ ...
+</manifest>
+</pre>
+
+<p>As new versions of Android are released, some style and behaviors may change.
+To allow your app to take advantage of these changes and ensure that your app fits the style of
+each user's device, you should set the
+<a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
+value to match the latest Android version
+available.</p>
+
+
+
+<h2 id="version-codes">Check System Version at Runtime</h2>
+
+<p>Android provides a unique code for each platform version in the {@link android.os.Build}
+constants class. Use these codes within your app to build conditions that ensure the code that
+depends on higher API levels is executed only when those APIs are available on the system.</p>
+
+<pre>
+private void setUpActionBar() {
+ // Make sure we're running on Honeycomb or higher to use ActionBar APIs
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+}
+</pre>
+
+
+
+<p class="note"><strong>Note:</strong> When parsing XML resources, Android ignores XML
+attributes that aren’t supported by the current device. So you can safely use XML attributes that
+are only supported by newer versions without worrying about older versions breaking when they
+encounter that code. For example, if you set the
+<code>targetSdkVersion="11"</code>, your app includes the {@link android.app.ActionBar} by default
+on Android 3.0 and higher. To then add menu items to the action bar, you need to set
+<code>android:showAsAction="ifRoom"</code> in your menu resource XML. It's safe to do this
+in a cross-version XML file, because the older versions of Android simply ignore the
+<code>showAsAction</code> attribute (that is, you <em>do not</em> need a separate
+version in <code>res/menu-v11/</code>).</p>
+
+
+
+<h2 id="style-themes">Use Platform Styles and Themes</h2>
+
+<p>Android provides user experience themes that give apps the look and feel of the
+underlying operating system. These themes can be applied to your app within the
+manifest file. By using these built in styles and themes, your app will
+naturally follow the latest look and feel of Android with each new release.</p>
+
+<p>To make your activity look like a dialog box:</p>
+
+<pre><activity android:theme="@android:style/Theme.Dialog"></pre>
+
+<p>To make your activity have a transparent background:</p>
+
+<pre><activity android:theme="@android:style/Theme.Translucent"></pre>
+
+<p>To apply your own custom theme defined in <code>/res/values/styles.xml</code>:</p>
+
+<pre><activity android:theme="@style/CustomTheme"></pre>
+
+<p>To apply a theme to your entire app (all activities), add the <code>android:theme</code>
+attribute
+to the <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+<application>}</a> element:</p>
+
+<pre><application android:theme="@style/CustomTheme"></pre>
+
+<p>For more about creating and using themes, read the <a
+href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> guide.</p>
+
diff --git a/docs/html/training/basics/supporting-devices/screens.jd b/docs/html/training/basics/supporting-devices/screens.jd
new file mode 100644
index 0000000..8697cd5
--- /dev/null
+++ b/docs/html/training/basics/supporting-devices/screens.jd
@@ -0,0 +1,180 @@
+page.title=Supporting Different Screens
+parent.title=Supporting Different Devices
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Supporting Different Languages
+previous.link=languages.html
+next.title=Supporting Different Platform Versions
+next.link=platforms.html
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#create-layouts">Create Different Layouts</a></li>
+ <li><a href="#create-bitmaps">Create Different Bitmaps</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple
+Screens</a></li>
+ <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a></li>
+ <li><a href="{@docRoot}design/style/iconography.html">Iconography design guide</a></li>
+ </ul>
+ </div>
+</div>
+
+<p>Android categorizes device screens using two general properties: size and density. You should
+expect that your app will be installed on devices with screens that range in both size
+and density. As such, you should include some alternative resources that optimize your app’s
+appearance for different screen sizes and densities.</p>
+
+<ul>
+ <li>There are four generalized sizes: small, normal, large, xlarge</li>
+ <li>And four generalized densities: low (ldpi), medium (mdpi), high (hdpi), extra high
+(xhdpi)</li>
+</ul>
+
+<p>To declare different layouts and bitmaps you'd like to use for different screens, you must place
+these alternative resources in separate directories, similar to how you do for different language
+strings.</p>
+
+<p>Also be aware that the screens orientation (landscape or portrait) is considered a variation of
+screen size, so many apps should revise the layout to optimize the user experience in each
+orientation.</p>
+
+
+<h2 id="create-layouts">Create Different Layouts</h2>
+
+<p>To optimize your user experience on different screen sizes, you should create a unique layout XML
+file for each screen size you want to support. Each layout should be
+saved into the appropriate resources directory, named with a <code>-<screen_size></code>
+suffix. For example, a unique layout for large screens should be saved under
+<code>res/layout-large/</code>.</p>
+
+<p class="note"><strong>Note:</strong> Android automatically scales your layout in order to
+properly fit the screen. Thus, your layouts for different screen sizes don't
+need to worry about the absolute size of UI elements but instead focus on the layout structure that
+affects the user experience (such as the size or position of important views relative to sibling
+views).</p>
+
+<p>For example, this project includes a default layout and an alternative layout for <em>large</em>
+screens:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ layout/
+ main.xml
+ layout-large/
+ main.xml
+</pre>
+
+<p>The file names must be exactly the same, but their contents are different in order to provide
+an optimized UI for the corresponding screen size.</p>
+
+<p>Simply reference the layout file in your app as usual:</p>
+
+<pre>
+@Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+}
+</pre>
+
+<p>The system loads the layout file from the appropriate layout directory based on screen size of
+the device on which your app is running. More information about how Android selects the
+appropriate resource is available in the <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">Providing Resources</a>
+guide.</p>
+
+<p>As another example, here's a project with an alternative layout for landscape orientation:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ layout/
+ main.xml
+ layout-land/
+ main.xml
+</pre>
+
+<p>By default, the <code>layout/main.xml</code> file is used for portrait orientation.</p>
+
+<p>If you want a provide a special layout for landscape, including while on large screens, then
+you need to use both the <code>large</code> and <code>land</code> qualifier:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ layout/ # default (portrait)
+ main.xml
+ layout-land/ # landscape
+ main.xml
+ layout-large/ # large (portrait)
+ main.xml
+ layout-large-land/ # large landscape
+ main.xml
+</pre>
+
+<p class="note"><strong>Note:</strong> Android 3.2 and above supports an advanced method of
+defining screen sizes that allows you to specify resources for screen sizes based on
+the minimum width and height in terms of density-independent pixels. This lesson does not cover
+this new technique. For more information, read <a
+href="{@docRoot}training/multiscreen/index.html">Designing for Multiple
+Screens</a>.</p>
+
+
+
+<h2 id="create-bitmaps">Create Different Bitmaps</h2>
+
+<p>You should always provide bitmap resources that are properly scaled to each of the generalized
+density buckets: low, medium, high and extra-high density. This helps you achieve good graphical
+quality and performance on all screen densities.</p>
+
+<p>To generate these images, you should start with your raw resource in vector format and generate
+the images for each density using the following size scale:</p>
+<ul>
+<li>xhdpi: 2.0</li>
+<li>hdpi: 1.5</li>
+<li>mdpi: 1.0 (baseline)</li>
+<li>ldpi: 0.75</li>
+</ul>
+
+<p>This means that if you generate a 200x200 image for xhdpi devices, you should generate the same
+resource in 150x150 for hdpi, 100x100 for mdpi, and 75x75 for ldpi devices.</p>
+
+<p>Then, place the files in the appropriate drawable resource directory:</p>
+
+<pre class="classic no-pretty-print">
+MyProject/
+ res/
+ drawable-xhdpi/
+ awesomeimage.png
+ drawable-hdpi/
+ awesomeimage.png
+ drawable-mdpi/
+ awesomeimage.png
+ drawable-ldpi/
+ awesomeimage.png
+</pre>
+
+<p>Any time you reference <code>@drawable/awesomeimage</code>, the system selects the
+appropriate bitmap based on the screen's density.</p>
+
+<p class="note"><strong>Note:</strong> Low-density (ldpi) resources aren’t always necessary. When
+you provide hdpi assets, the system scales them down by one half to properly fit ldpi
+screens.</p>
+
+<p>For more tips and guidelines about creating icon assets for your app, see the
+<a href="{@docRoot}design/style/iconography.html">Iconography design guide</a>.</p>
+
+
+
diff --git a/docs/html/training/tv/optimizing-layouts-tv.jd b/docs/html/training/tv/optimizing-layouts-tv.jd
index 6eac6d3..e4a8e69 100644
--- a/docs/html/training/tv/optimizing-layouts-tv.jd
+++ b/docs/html/training/tv/optimizing-layouts-tv.jd
@@ -16,7 +16,7 @@
<li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li>
<li><a href="#MakeTextControlsEasyToSee">Make Text and Controls Easy to See</a></li>
<li><a href="#DesignForLargeScreens">Design for High-Density Large Screens</a></li>
- <li><a href="#HandleLargeBitmaps">Handle Large Bitmaps in Your Application</a></li>
+ <li><a href="#HandleLargeBitmaps">Design to Handle Large Bitmaps</a></li>
</ol>
<h2>You should also read</h2>
diff --git a/docs/html/training/tv/optimizing-navigation-tv.jd b/docs/html/training/tv/optimizing-navigation-tv.jd
index 8b5878e..bb78258 100644
--- a/docs/html/training/tv/optimizing-navigation-tv.jd
+++ b/docs/html/training/tv/optimizing-navigation-tv.jd
@@ -5,7 +5,7 @@
trainingnavtop=true
previous.title=Optimizing Layouts for TV
previous.link=optimizing-layouts-tv.html
-next.title=Handling features not supported on TV
+next.title=Handling Features Not Supported on TV
next.link=unsupported-features-tv.html
@jd:body
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ed5b2f6..c726d0e 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,11 +16,9 @@
package android.graphics;
-import android.os.Debug;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.DisplayMetrics;
-import android.util.Log;
import java.io.OutputStream;
import java.nio.Buffer;
@@ -183,7 +181,7 @@
/**
* Sets the layout bounds as an array of left, top, right, bottom integers
- * @param padding the array containing the padding values
+ * @param bounds the array containing the padding values
*
* @hide
*/
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 0521e69..e101581 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -161,7 +161,31 @@
public void updateTexImage() {
int err = nativeUpdateTexImage();
if (err != 0) {
- throw new RuntimeException("Error during updateTexImage (see logs)");
+ throw new RuntimeException("Error during updateTexImage (see logcat for details)");
+ }
+ }
+
+ /**
+ * Detach the SurfaceTexture from the OpenGL ES context with which it is currently associated.
+ * This can be used to change from one OpenGL ES context to another.
+ *
+ * @hide
+ */
+ public void detachFromGLContext() {
+ int err = nativeDetachFromGLContext();
+ if (err != 0) {
+ throw new RuntimeException("Error during detachFromGLContext (see logcat for details)");
+ }
+ }
+
+ /**
+ *
+ * @hide
+ */
+ public void attachToGLContext(int texName) {
+ int err = nativeAttachToGLContext(texName);
+ if (err != 0) {
+ throw new RuntimeException("Error during detachFromGLContext (see logcat for details)");
}
}
@@ -269,6 +293,8 @@
private native long nativeGetTimestamp();
private native void nativeSetDefaultBufferSize(int width, int height);
private native int nativeUpdateTexImage();
+ private native int nativeDetachFromGLContext();
+ private native int nativeAttachToGLContext(int texName);
private native int nativeGetQueuedCount();
private native void nativeRelease();
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
index a4ebd95..f8cbdde 100644
--- a/include/androidfw/Input.h
+++ b/include/androidfw/Input.h
@@ -811,6 +811,31 @@
VelocityTracker mVelocityTracker;
};
+/*
+ * Identifies a device.
+ */
+struct InputDeviceIdentifier {
+ inline InputDeviceIdentifier() :
+ bus(0), vendor(0), product(0), version(0) {
+ }
+
+ // Information provided by the kernel.
+ String8 name;
+ String8 location;
+ String8 uniqueId;
+ uint16_t bus;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+
+ // A composite input device descriptor string that uniquely identifies the device
+ // even across reboots or reconnections. The value of this field is used by
+ // upper layers of the input system to associate settings with individual devices.
+ // It is hashed from whatever kernel provided information is available.
+ // Ideally, the way this value is computed should not change between Android releases
+ // because that would invalidate persistent settings that rely on it.
+ String8 descriptor;
+};
/*
* Describes the characteristics and capabilities of an input device.
@@ -830,10 +855,11 @@
float fuzz;
};
- void initialize(int32_t id, const String8& name);
+ void initialize(int32_t id, const String8& name, const String8& descriptor);
inline int32_t getId() const { return mId; }
inline const String8 getName() const { return mName; }
+ inline const String8 getDescriptor() const { return mDescriptor; }
inline uint32_t getSources() const { return mSources; }
const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
@@ -856,6 +882,7 @@
private:
int32_t mId;
String8 mName;
+ String8 mDescriptor;
uint32_t mSources;
int32_t mKeyboardType;
String8 mKeyCharacterMapFile;
@@ -863,23 +890,6 @@
Vector<MotionRange> mMotionRanges;
};
-/*
- * Identifies a device.
- */
-struct InputDeviceIdentifier {
- inline InputDeviceIdentifier() :
- bus(0), vendor(0), product(0), version(0) {
- }
-
- String8 name;
- String8 location;
- String8 uniqueId;
- uint16_t bus;
- uint16_t vendor;
- uint16_t product;
- uint16_t version;
-};
-
/* Types of input device configuration files. */
enum InputDeviceConfigurationFileType {
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
diff --git a/libs/androidfw/Input.cpp b/libs/androidfw/Input.cpp
index da57839..2e4b26f 100644
--- a/libs/androidfw/Input.cpp
+++ b/libs/androidfw/Input.cpp
@@ -1226,21 +1226,24 @@
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, String8("uninitialized device info"));
+ initialize(-1, String8("uninitialized device info"), String8("unknown"));
}
InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
- mId(other.mId), mName(other.mName), mSources(other.mSources),
+ mId(other.mId), mName(other.mName), mDescriptor(other.mDescriptor),
+ mSources(other.mSources),
mKeyboardType(other.mKeyboardType),
+ mKeyCharacterMapFile(other.mKeyCharacterMapFile),
mMotionRanges(other.mMotionRanges) {
}
InputDeviceInfo::~InputDeviceInfo() {
}
-void InputDeviceInfo::initialize(int32_t id, const String8& name) {
+void InputDeviceInfo::initialize(int32_t id, const String8& name, const String8& descriptor) {
mId = id;
mName = name;
+ mDescriptor = descriptor;
mSources = 0;
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
mMotionRanges.clear();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 39d2e39..2a908ab 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -260,7 +260,7 @@
Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
dirty.unionWith(localDirty);
- if (result == DrawGlInfo::kStatusInvoke) {
+ if (result & DrawGlInfo::kStatusInvoke) {
mFunctors.push(f);
}
}
@@ -300,7 +300,7 @@
Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
dirty.unionWith(localDirty);
- if (result == DrawGlInfo::kStatusInvoke) {
+ if (result & DrawGlInfo::kStatusInvoke) {
mFunctors.push(functor);
}
}
diff --git a/libs/storage/Android.mk b/libs/storage/Android.mk
index b42c34f..7a9dd6c 100644
--- a/libs/storage/Android.mk
+++ b/libs/storage/Android.mk
@@ -7,10 +7,6 @@
IObbActionListener.cpp \
IMountService.cpp
-LOCAL_STATIC_LIBRARIES := \
- libutils \
- libbinder
-
LOCAL_MODULE:= libstorage
include $(BUILD_STATIC_LIBRARY)
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c7e71eb..41d5c32 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2237,6 +2237,14 @@
* docking station
*/
public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
+ /** {@hide} The audio output device code for a USB audio accessory. The accessory is in USB host
+ * mode and the Android device in USB device mode
+ */
+ public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
+ /** {@hide} The audio output device code for a USB audio device. The device is in USB device
+ * mode and the Android device in USB host mode
+ */
+ public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
/** {@hide} This is not used as a returned value from {@link #getDevicesForStream}, but could be
* used in the future in a set method to select whatever default device is chosen by the
* platform-specific implementation.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2e456f0..48d3712 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -389,9 +389,11 @@
intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
- intentFilter.addAction(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
- intentFilter.addAction(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+ intentFilter.addAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
+ intentFilter.addAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
intentFilter.addAction(Intent.ACTION_HDMI_AUDIO_PLUG);
+ intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
+ intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -2800,6 +2802,28 @@
}
}
+ private boolean handleDeviceConnection(boolean connected, int device, String params) {
+ synchronized (mConnectedDevices) {
+ boolean isConnected = (mConnectedDevices.containsKey(device) &&
+ mConnectedDevices.get(device).equals(params));
+
+ if (isConnected && !connected) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ params);
+ mConnectedDevices.remove(device);
+ return true;
+ } else if (!isConnected && connected) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ params);
+ mConnectedDevices.put(new Integer(device), params);
+ return true;
+ }
+ }
+ return false;
+ }
+
/* cache of the address of the last dock the device was connected to */
private String mDockAddress;
@@ -2810,6 +2834,8 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ int device;
+ int state;
if (action.equals(Intent.ACTION_DOCK_EVENT)) {
int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
@@ -2834,15 +2860,15 @@
}
AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
} else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
+ state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
handleA2dpConnectionStateChange(btDevice, state);
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
+ state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
- int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+ device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
String address = null;
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -2868,129 +2894,56 @@
address = "";
}
- synchronized (mConnectedDevices) {
- boolean isConnected = (mConnectedDevices.containsKey(device) &&
- mConnectedDevices.get(device).equals(address));
-
+ boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
+ if (handleDeviceConnection(connected, device, address)) {
synchronized (mScoClients) {
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- AudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- address);
- mConnectedDevices.remove(device);
+ if (connected) {
+ mBluetoothHeadsetDevice = btDevice;
+ } else {
mBluetoothHeadsetDevice = null;
resetBluetoothSco();
- } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
- AudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- address);
- mConnectedDevices.put(new Integer(device), address);
- mBluetoothHeadsetDevice = btDevice;
}
}
}
} else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", 0);
+ state = intent.getIntExtra("state", 0);
int microphone = intent.getIntExtra("microphone", 0);
- synchronized (mConnectedDevices) {
- if (microphone != 0) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), "");
- }
- } else {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
- }
- }
+ if (microphone != 0) {
+ device = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
+ } else {
+ device = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
}
- } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", 0);
- Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state);
- synchronized (mConnectedDevices) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), "");
- }
- }
+ handleDeviceConnection((state == 1), device, "");
+ } else if (action.equals(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+ Log.v(TAG, "Broadcast Receiver: Got ACTION_ANALOG_AUDIO_DOCK_PLUG, state = "+state);
+ handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, "");
} else if (action.equals(Intent.ACTION_HDMI_AUDIO_PLUG)) {
- int state = intent.getIntExtra("state", 0);
+ state = intent.getIntExtra("state", 0);
Log.v(TAG, "Broadcast Receiver: Got ACTION_HDMI_AUDIO_PLUG, state = "+state);
- synchronized (mConnectedDevices) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_AUX_DIGITAL);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_AUX_DIGITAL);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_AUX_DIGITAL,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_AUX_DIGITAL), "");
- }
- }
- } else if (action.equals(Intent.ACTION_USB_DGTL_HEADSET_PLUG)) {
- int state = intent.getIntExtra("state", 0);
- Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_DGTL_HEADSET_PLUG, state = "+state);
- synchronized (mConnectedDevices) {
- boolean isConnected =
- mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
- if (state == 0 && isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_UNAVAILABLE,
- "");
- mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
- } else if (state == 1 && !isConnected) {
- AudioSystem.setDeviceConnectionState(
- AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
- AudioSystem.DEVICE_STATE_AVAILABLE,
- "");
- mConnectedDevices.put(
- new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), "");
- }
- }
+ handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_AUX_DIGITAL, "");
+ } else if (action.equals(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+ Log.v(TAG,
+ "Broadcast Receiver Got ACTION_DIGITAL_AUDIO_DOCK_PLUG, state = " + state);
+ handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, "");
+ } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
+ action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
+ state = intent.getIntExtra("state", 0);
+ int alsaCard = intent.getIntExtra("card", -1);
+ int alsaDevice = intent.getIntExtra("device", -1);
+ String params = "card=" + alsaCard + ";device=" + alsaDevice;
+ device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
+ AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
+ Log.v(TAG, "Broadcast Receiver: Got "
+ + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
+ "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
+ + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
+ handleDeviceConnection((state == 1), device, params);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
boolean broadcast = false;
- int state = AudioManager.SCO_AUDIO_STATE_ERROR;
+ int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
synchronized (mScoClients) {
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
// broadcast intent if the connection was initated by AudioService
@@ -3002,7 +2955,7 @@
}
switch (btState) {
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- state = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
@@ -3010,7 +2963,7 @@
}
break;
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
mScoAudioState = SCO_STATE_INACTIVE;
clearAllScoClients(0, false);
break;
@@ -3027,11 +2980,11 @@
}
}
if (broadcast) {
- broadcastScoConnectionState(state);
+ broadcastScoConnectionState(scoAudioState);
//FIXME: this is to maintain compatibility with deprecated intent
// AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
- newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
+ newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
mContext.sendStickyBroadcast(newIntent);
}
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 18a00bc..9bafa5c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -202,6 +202,9 @@
public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
+ public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
+ public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
+
public static final int DEVICE_OUT_DEFAULT = 0x8000;
public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
DEVICE_OUT_SPEAKER |
@@ -216,10 +219,18 @@
DEVICE_OUT_AUX_DIGITAL |
DEVICE_OUT_ANLG_DOCK_HEADSET |
DEVICE_OUT_DGTL_DOCK_HEADSET |
+ DEVICE_OUT_USB_ACCESSORY |
+ DEVICE_OUT_USB_DEVICE |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO |
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
+ DEVICE_OUT_USB_DEVICE);
+
// input devices
public static final int DEVICE_IN_COMMUNICATION = 0x10000;
public static final int DEVICE_IN_AMBIENT = 0x20000;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 66cea9d4..410383d 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -45,10 +45,16 @@
public int mFlags;
};
+ // The follow flag constants MUST stay in sync with their equivalents
+ // in MediaCodec.h !
public static int FLAG_SYNCFRAME = 1;
public static int FLAG_CODECCONFIG = 2;
public static int FLAG_EOS = 4;
- public static int FLAG_ENCRYPTED = 8;
+
+ // The following mode constants MUST stay in sync with their equivalents
+ // in media/hardware/CryptoAPI.h !
+ public static int MODE_UNENCRYPTED = 0;
+ public static int MODE_AES_CTR = 1;
/** Instantiate a codec component by mime type. For decoder components
this is the mime type of media that this decoder should be able to
@@ -176,6 +182,36 @@
int index,
int offset, int size, long presentationTimeUs, int flags);
+ /** Similar to {@link queueInputBuffer} but submits a buffer that is
+ * potentially encrypted. The buffer's data is considered to be
+ * partitioned into "subSamples", each subSample starts with a
+ * (potentially empty) run of plain, unencrypted bytes followed
+ * by a (also potentially empty) run of encrypted bytes.
+ * @param numBytesOfClearData The number of leading unencrypted bytes in
+ * each subSample.
+ * @param numBytesOfEncryptedData The number of trailing encrypted bytes
+ * in each subSample.
+ * @param numSubSamples The number of subSamples that make up the
+ * buffer's contents.
+ * @param key A 16-byte opaque key
+ * @param iv A 16-byte initialization vector
+ * @param mode The type of encryption that has been applied
+ *
+ * Either numBytesOfClearData or numBytesOfEncryptedData (but not both)
+ * can be null to indicate that all respective sizes are 0.
+ */
+ public native final void queueSecureInputBuffer(
+ int index,
+ int offset,
+ int[] numBytesOfClearData,
+ int[] numBytesOfEncryptedData,
+ int numSubSamples,
+ byte[] key,
+ byte[] iv,
+ int mode,
+ long presentationTimeUs,
+ int flags);
+
// Returns the index of an input buffer to be filled with valid data
// or -1 if no such buffer is currently available.
// This method will return immediately if timeoutUs == 0, wait indefinitely
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 217216a..01d3833 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -126,6 +126,21 @@
return mCodec->queueInputBuffer(index, offset, size, timeUs, flags);
}
+status_t JMediaCodec::queueSecureInputBuffer(
+ size_t index,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const uint8_t key[16],
+ const uint8_t iv[16],
+ CryptoPlugin::Mode mode,
+ int64_t presentationTimeUs,
+ uint32_t flags) {
+ return mCodec->queueSecureInputBuffer(
+ index, offset, subSamples, numSubSamples, key, iv, mode,
+ presentationTimeUs, flags);
+}
+
status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
return mCodec->dequeueInputBuffer(index, timeoutUs);
}
@@ -367,6 +382,125 @@
throwExceptionAsNecessary(env, err);
}
+static void android_media_MediaCodec_queueSecureInputBuffer(
+ JNIEnv *env,
+ jobject thiz,
+ jint index,
+ jint offset,
+ jintArray numBytesOfClearDataObj,
+ jintArray numBytesOfEncryptedDataObj,
+ jint numSubSamples,
+ jbyteArray keyObj,
+ jbyteArray ivObj,
+ jint mode,
+ jlong timestampUs,
+ jint flags) {
+ ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
+
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ status_t err = OK;
+
+ CryptoPlugin::SubSample *subSamples = NULL;
+ jbyte *key = NULL;
+ jbyte *iv = NULL;
+
+ if (numSubSamples <= 0) {
+ err = -EINVAL;
+ } else if (numBytesOfClearDataObj == NULL
+ && numBytesOfEncryptedDataObj == NULL) {
+ err = -EINVAL;
+ } else if (numBytesOfEncryptedDataObj != NULL
+ && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
+ err = -ERANGE;
+ } else if (numBytesOfClearDataObj != NULL
+ && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
+ err = -ERANGE;
+ } else {
+ jboolean isCopy;
+
+ jint *numBytesOfClearData =
+ (numBytesOfClearDataObj == NULL)
+ ? NULL
+ : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
+
+ jint *numBytesOfEncryptedData =
+ (numBytesOfEncryptedDataObj == NULL)
+ ? NULL
+ : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
+
+ subSamples = new CryptoPlugin::SubSample[numSubSamples];
+
+ for (jint i = 0; i < numSubSamples; ++i) {
+ subSamples[i].mNumBytesOfClearData =
+ (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
+
+ subSamples[i].mNumBytesOfEncryptedData =
+ (numBytesOfEncryptedData == NULL)
+ ? 0 : numBytesOfEncryptedData[i];
+ }
+
+ if (numBytesOfEncryptedData != NULL) {
+ env->ReleaseIntArrayElements(
+ numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
+ numBytesOfEncryptedData = NULL;
+ }
+
+ if (numBytesOfClearData != NULL) {
+ env->ReleaseIntArrayElements(
+ numBytesOfClearDataObj, numBytesOfClearData, 0);
+ numBytesOfClearData = NULL;
+ }
+ }
+
+ if (err == OK && keyObj != NULL) {
+ if (env->GetArrayLength(keyObj) != 16) {
+ err = -EINVAL;
+ } else {
+ jboolean isCopy;
+ key = env->GetByteArrayElements(keyObj, &isCopy);
+ }
+ }
+
+ if (err == OK && ivObj != NULL) {
+ if (env->GetArrayLength(ivObj) != 16) {
+ err = -EINVAL;
+ } else {
+ jboolean isCopy;
+ iv = env->GetByteArrayElements(ivObj, &isCopy);
+ }
+ }
+
+ if (err == OK) {
+ err = codec->queueSecureInputBuffer(
+ index, offset,
+ subSamples, numSubSamples,
+ (const uint8_t *)key, (const uint8_t *)iv,
+ (CryptoPlugin::Mode)mode,
+ timestampUs, flags);
+ }
+
+ if (iv != NULL) {
+ env->ReleaseByteArrayElements(ivObj, iv, 0);
+ iv = NULL;
+ }
+
+ if (key != NULL) {
+ env->ReleaseByteArrayElements(keyObj, key, 0);
+ key = NULL;
+ }
+
+ delete[] subSamples;
+ subSamples = NULL;
+
+ throwExceptionAsNecessary(env, err);
+}
+
static jint android_media_MediaCodec_dequeueInputBuffer(
JNIEnv *env, jobject thiz, jlong timeoutUs) {
ALOGV("android_media_MediaCodec_dequeueInputBuffer");
@@ -532,6 +666,9 @@
{ "queueInputBuffer", "(IIIJI)V",
(void *)android_media_MediaCodec_queueInputBuffer },
+ { "queueSecureInputBuffer", "(II[I[II[B[BIJI)V",
+ (void *)android_media_MediaCodec_queueSecureInputBuffer },
+
{ "dequeueInputBuffer", "(J)I",
(void *)android_media_MediaCodec_dequeueInputBuffer },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 6bb4071..570c33b 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -19,6 +19,7 @@
#include "jni.h"
+#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -53,6 +54,17 @@
size_t index,
size_t offset, size_t size, int64_t timeUs, uint32_t flags);
+ status_t queueSecureInputBuffer(
+ size_t index,
+ size_t offset,
+ const CryptoPlugin::SubSample *subSamples,
+ size_t numSubSamples,
+ const uint8_t key[16],
+ const uint8_t iv[16],
+ CryptoPlugin::Mode mode,
+ int64_t presentationTimeUs,
+ uint32_t flags);
+
status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs);
status_t dequeueOutputBuffer(
diff --git a/obex/MODULE_LICENSE_BSD_LIKE b/obex/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/MODULE_LICENSE_BSD_LIKE
diff --git a/obex/NOTICE b/obex/NOTICE
new file mode 100644
index 0000000..92e8e59
--- /dev/null
+++ b/obex/NOTICE
@@ -0,0 +1,29 @@
+Copyright (c) 2008-2009, Motorola, Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+- Neither the name of the Motorola, Inc. nor the names of its contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index b1aaade..0ba8cce 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -26,6 +26,7 @@
android:orientation="vertical"
android:focusable="true"
android:descendantFocusability="afterDescendants"
+ android:fitsSystemWindows="true"
>
<LinearLayout android:id="@+id/icons"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5ba72c7..804ae06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -591,10 +591,14 @@
}
final StatusBarNotification oldNotification = oldEntry.notification;
- final RemoteViews oldContentView = oldNotification.notification.contentView;
- final RemoteViews contentView = notification.notification.contentView;
-
+ // XXX: modify when we do something more intelligent with the two content views
+ final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null)
+ ? oldNotification.notification.bigContentView
+ : oldNotification.notification.contentView;
+ final RemoteViews contentView = (notification.notification.bigContentView != null)
+ ? notification.notification.bigContentView
+ : notification.notification.contentView;
if (DEBUG) {
Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index cc07240..0c8208f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -23,6 +23,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.Canvas;
import android.graphics.RectF;
+import android.hardware.input.InputManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.ServiceManager;
@@ -47,7 +48,6 @@
final float GLOW_MAX_SCALE_FACTOR = 1.8f;
final float BUTTON_QUIESCENT_ALPHA = 0.6f;
- IWindowManager mWindowManager;
long mDownTime;
int mCode;
int mTouchSlop;
@@ -93,9 +93,6 @@
a.recycle();
- mWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
-
setClickable(true);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
@@ -276,12 +273,7 @@
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- try {
- //Slog.d(TAG, "injecting event " + ev);
- mWindowManager.injectInputEventNoWait(ev);
- } catch (RemoteException ex) {
- // System process is dead
- }
+ InputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 49b1a14..ba51108 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -867,9 +867,14 @@
}
final StatusBarNotification oldNotification = oldEntry.notification;
- final RemoteViews oldContentView = oldNotification.notification.contentView;
- final RemoteViews contentView = notification.notification.contentView;
+ // XXX: modify when we do something more intelligent with the two content views
+ final RemoteViews oldContentView = (oldNotification.notification.bigContentView != null)
+ ? oldNotification.notification.bigContentView
+ : oldNotification.notification.contentView;
+ final RemoteViews contentView = (notification.notification.bigContentView != null)
+ ? notification.notification.bigContentView
+ : notification.notification.contentView;
if (DEBUG) {
Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
@@ -1322,14 +1327,6 @@
}
}
- private void sendKey(KeyEvent key) {
- try {
- if (DEBUG) Slog.d(TAG, "injecting key event: " + key);
- mWindowManager.injectInputEventNoWait(key);
- } catch (RemoteException ex) {
- }
- }
-
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
public void onClick(View v) {
if (v == mRecentButton) {
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
new file mode 100644
index 0000000..2ae99e6
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import com.android.internal.R;
+import com.android.internal.policy.IFaceLockCallback;
+import com.android.internal.policy.IFaceLockInterface;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+
+public class FaceUnlock implements Handler.Callback {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "FULLockscreen";
+
+ private final Context mContext;
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+
+ private IFaceLockInterface mService;
+ private boolean mBoundToService = false;
+ private View mAreaView;
+
+ private Handler mHandler;
+ private final int MSG_SHOW_AREA_VIEW = 0;
+ private final int MSG_HIDE_AREA_VIEW = 1;
+
+ private boolean mServiceRunning = false;
+ private final Object mServiceRunningLock = new Object();
+
+ // Long enough to stay visible while dialer comes up
+ // Short enough to not be visible if the user goes back immediately
+ private final int VIEW_AREA_EMERGENCY_DIALER_TIMEOUT = 1000;
+
+ // Long enough to stay visible while the service starts
+ // Short enough to not have to wait long for backup if service fails to start or crashes
+ // The service can take a couple of seconds to start on the first try after boot
+ private final int VIEW_AREA_SERVICE_TIMEOUT = 3000;
+
+ // So the user has a consistent amount of time when brought to the backup method from FaceLock
+ private final int BACKUP_LOCK_TIMEOUT = 5000;
+
+ /**
+ * Used to lookup the state of the lock pattern
+ */
+ private final LockPatternUtils mLockPatternUtils;
+
+ KeyguardScreenCallback mKeyguardScreenCallback;
+
+ public FaceUnlock(Context context, KeyguardUpdateMonitor updateMonitor,
+ LockPatternUtils lockPatternUtils, KeyguardScreenCallback keyguardScreenCallback) {
+ mContext = context;
+ mUpdateMonitor = updateMonitor;
+ mLockPatternUtils = lockPatternUtils;
+ mKeyguardScreenCallback = keyguardScreenCallback;
+ mHandler = new Handler(this);
+ }
+
+ public void cleanUp() {
+ if (mService != null) {
+ try {
+ mService.unregisterCallback(mFaceLockCallback);
+ } catch (RemoteException e) {
+ // Not much we can do
+ }
+ stop();
+ mService = null;
+ }
+ }
+
+ /** When screen is turned on and focused, need to bind to FaceLock service if we are using
+ * FaceLock, but only if we're not dealing with a call
+ */
+ public void activateIfAble(boolean hasOverlay) {
+ final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached();
+ final int failedBackupAttempts = mUpdateMonitor.getFailedAttempts();
+ final boolean backupIsTimedOut =
+ (failedBackupAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
+ if (tooManyFaceUnlockTries) Log.i(TAG, "tooManyFaceUnlockTries: " + tooManyFaceUnlockTries);
+ if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
+ && installedAndSelected()
+ && !hasOverlay
+ && !tooManyFaceUnlockTries
+ && !backupIsTimedOut) {
+ bind();
+
+ // Show FaceLock area, but only for a little bit so lockpattern will become visible if
+ // FaceLock fails to start or crashes
+ showAreaWithTimeout(VIEW_AREA_SERVICE_TIMEOUT);
+
+ // When switching between portrait and landscape view while FaceLock is running, the
+ // screen will eventually go dark unless we poke the wakelock when FaceLock is
+ // restarted
+ mKeyguardScreenCallback.pokeWakelock();
+ } else {
+ hideArea();
+ }
+ }
+
+ public boolean isServiceRunning() {
+ return mServiceRunning;
+ }
+
+ public int viewAreaEmergencyDialerTimeout() {
+ return VIEW_AREA_EMERGENCY_DIALER_TIMEOUT;
+ }
+
+ // Indicates whether FaceLock is in use
+ public boolean installedAndSelected() {
+ return (mLockPatternUtils.usingBiometricWeak() &&
+ mLockPatternUtils.isBiometricWeakInstalled());
+ }
+
+ // Takes care of FaceLock area when layout is created
+ public void initializeAreaView(View view) {
+ if (installedAndSelected()) {
+ mAreaView = view.findViewById(R.id.faceLockAreaView);
+ if (mAreaView == null) {
+ Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
+ }
+ } else {
+ mAreaView = null; // Set to null if not using FaceLock
+ }
+ }
+
+ // Stops FaceLock if it is running and reports back whether it was running or not
+ public boolean stopIfRunning() {
+ if (installedAndSelected() && mBoundToService) {
+ stopAndUnbind();
+ return true;
+ }
+ return false;
+ }
+
+ // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
+ // This needs to be done in a handler because the call could be coming from a callback from the
+ // FaceLock service that is in a thread that can't modify the UI
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SHOW_AREA_VIEW:
+ if (mAreaView != null) {
+ mAreaView.setVisibility(View.VISIBLE);
+ }
+ break;
+ case MSG_HIDE_AREA_VIEW:
+ if (mAreaView != null) {
+ mAreaView.setVisibility(View.INVISIBLE);
+ }
+ break;
+ default:
+ Log.w(TAG, "Unhandled message");
+ return false;
+ }
+ return true;
+ }
+
+ // Removes show and hide messages from the message queue
+ private void removeAreaDisplayMessages() {
+ mHandler.removeMessages(MSG_SHOW_AREA_VIEW);
+ mHandler.removeMessages(MSG_HIDE_AREA_VIEW);
+ }
+
+ // Shows the FaceLock area immediately
+ public void showArea() {
+ // Remove messages to prevent a delayed hide message from undo-ing the show
+ removeAreaDisplayMessages();
+ mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
+ }
+
+ // Hides the FaceLock area immediately
+ public void hideArea() {
+ // Remove messages to prevent a delayed show message from undo-ing the hide
+ removeAreaDisplayMessages();
+ mHandler.sendEmptyMessage(MSG_HIDE_AREA_VIEW);
+ }
+
+ // Shows the FaceLock area for a period of time
+ public void showAreaWithTimeout(long timeoutMillis) {
+ showArea();
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_AREA_VIEW, timeoutMillis);
+ }
+
+ // Binds to FaceLock service. This call does not tell it to start, but it causes the service
+ // to call the onServiceConnected callback, which then starts FaceLock.
+ public void bind() {
+ if (installedAndSelected()) {
+ if (!mBoundToService) {
+ if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
+ mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
+ mConnection,
+ Context.BIND_AUTO_CREATE);
+ if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
+ mBoundToService = true;
+ } else {
+ Log.w(TAG, "Attempt to bind to FaceLock when already bound");
+ }
+ }
+ }
+
+ // Tells FaceLock to stop and then unbinds from the FaceLock service
+ public void stopAndUnbind() {
+ if (installedAndSelected()) {
+ stop();
+
+ if (mBoundToService) {
+ if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
+ if (mService != null) {
+ try {
+ mService.unregisterCallback(mFaceLockCallback);
+ } catch (RemoteException e) {
+ // Not much we can do
+ }
+ }
+ mContext.unbindService(mConnection);
+ if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
+ mBoundToService = false;
+ } else {
+ // This is usually not an error when this happens. Sometimes we will tell it to
+ // unbind multiple times because it's called from both onWindowFocusChanged and
+ // onDetachedFromWindow.
+ if (DEBUG) Log.d(TAG, "Attempt to unbind from FaceLock when not bound");
+ }
+ }
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ // Completes connection, registers callback and starts FaceLock when service is bound
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder iservice) {
+ mService = IFaceLockInterface.Stub.asInterface(iservice);
+ if (DEBUG) Log.d(TAG, "Connected to FaceLock service");
+ try {
+ mService.registerCallback(mFaceLockCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught exception connecting to FaceLock: " + e.toString());
+ mService = null;
+ mBoundToService = false;
+ return;
+ }
+
+ if (mAreaView != null) {
+ int[] position;
+ position = new int[2];
+ mAreaView.getLocationInWindow(position);
+ start(mAreaView.getWindowToken(), position[0], position[1],
+ mAreaView.getWidth(), mAreaView.getHeight());
+ }
+ }
+
+ // Cleans up if FaceLock service unexpectedly disconnects
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ synchronized(mServiceRunningLock) {
+ mService = null;
+ mServiceRunning = false;
+ }
+ mBoundToService = false;
+ Log.w(TAG, "Unexpected disconnect from FaceLock service");
+ }
+ };
+
+ // Tells the FaceLock service to start displaying its UI and perform recognition
+ public void start(IBinder windowToken, int x, int y, int w, int h) {
+ if (installedAndSelected()) {
+ synchronized (mServiceRunningLock) {
+ if (!mServiceRunning) {
+ if (DEBUG) Log.d(TAG, "Starting FaceLock");
+ try {
+ mService.startUi(windowToken, x, y, w, h);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
+ return;
+ }
+ mServiceRunning = true;
+ } else {
+ if (DEBUG) Log.w(TAG, "start() attempted while running");
+ }
+ }
+ }
+ }
+
+ // Tells the FaceLock service to stop displaying its UI and stop recognition
+ public void stop() {
+ if (installedAndSelected()) {
+ // Note that attempting to stop FaceLock when it's not running is not an issue.
+ // FaceLock can return, which stops it and then we try to stop it when the
+ // screen is turned off. That's why we check.
+ synchronized (mServiceRunningLock) {
+ if (mServiceRunning) {
+ try {
+ if (DEBUG) Log.d(TAG, "Stopping FaceLock");
+ mService.stopUi();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught exception stopping FaceLock: " + e.toString());
+ }
+ mServiceRunning = false;
+ }
+ }
+ }
+ }
+
+ // Implements the FaceLock service callback interface defined in AIDL
+ private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() {
+ // Stops the FaceLock UI and indicates that the phone should be unlocked
+ @Override
+ public void unlock() {
+ if (DEBUG) Log.d(TAG, "FaceLock unlock()");
+ showArea(); // Keep fallback covered
+ stopAndUnbind();
+
+ mKeyguardScreenCallback.keyguardDone(true);
+ mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
+ }
+
+ // Stops the FaceLock UI and exposes the backup method without unlocking
+ // This means the user has cancelled out
+ @Override
+ public void cancel() {
+ if (DEBUG) Log.d(TAG, "FaceLock cancel()");
+ hideArea(); // Expose fallback
+ stopAndUnbind();
+ mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
+ }
+
+ // Stops the FaceLock UI and exposes the backup method without unlocking
+ // This means FaceLock failed to recognize them
+ @Override
+ public void reportFailedAttempt() {
+ if (DEBUG) Log.d(TAG, "FaceLock reportFailedAttempt()");
+ mUpdateMonitor.reportFailedFaceUnlockAttempt();
+ hideArea(); // Expose fallback
+ stopAndUnbind();
+ mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
+ }
+
+ // Removes the black area that covers the backup unlock method
+ @Override
+ public void exposeFallback() {
+ if (DEBUG) Log.d(TAG, "FaceLock exposeFallback()");
+ hideArea(); // Expose fallback
+ }
+
+ // Allows the Face Unlock service to poke the wake lock to keep the lockscreen alive
+ @Override
+ public void pokeWakelock() {
+ if (DEBUG) Log.d(TAG, "FaceLock pokeWakelock()");
+ mKeyguardScreenCallback.pokeWakelock();
+ }
+ };
+}
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 404dc6f..596040c 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -20,8 +20,6 @@
import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallback;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
-import com.android.internal.policy.IFaceLockCallback;
-import com.android.internal.policy.IFaceLockInterface;
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockScreenWidgetCallback;
@@ -36,12 +34,10 @@
import android.accounts.OperationCanceledException;
import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -50,12 +46,8 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.IBinder;
import android.os.Parcelable;
import android.os.PowerManager;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.telephony.TelephonyManager;
@@ -82,7 +74,7 @@
* {@link com.android.internal.policy.impl.KeyguardViewManager}
* via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
*/
-public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback {
+public class LockPatternKeyguardView extends KeyguardViewBase {
private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000;
@@ -110,30 +102,9 @@
private boolean mShowLockBeforeUnlock = false;
// The following were added to support FaceLock
- private IFaceLockInterface mFaceLockService;
- private boolean mBoundToFaceLockService = false;
- private View mFaceLockAreaView;
-
- private boolean mFaceLockServiceRunning = false;
- private final Object mFaceLockServiceRunningLock = new Object();
+ private FaceUnlock mFaceUnlock;
private final Object mFaceLockStartupLock = new Object();
- private Handler mHandler;
- private final int MSG_SHOW_FACELOCK_AREA_VIEW = 0;
- private final int MSG_HIDE_FACELOCK_AREA_VIEW = 1;
-
- // Long enough to stay visible while dialer comes up
- // Short enough to not be visible if the user goes back immediately
- private final int FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT = 1000;
-
- // Long enough to stay visible while the service starts
- // Short enough to not have to wait long for backup if service fails to start or crashes
- // The service can take a couple of seconds to start on the first try after boot
- private final int FACELOCK_VIEW_AREA_SERVICE_TIMEOUT = 3000;
-
- // So the user has a consistent amount of time when brought to the backup method from FaceLock
- private final int BACKUP_LOCK_TIMEOUT = 5000;
-
private boolean mRequiresSim;
//True if we have some sort of overlay on top of the Lockscreen
//Also true if we've activated a phone call, either emergency dialing or incoming
@@ -340,12 +311,12 @@
mHasOverlay = true;
// Continue showing FaceLock area until dialer comes up or call is resumed
- if (usingFaceLock() && mFaceLockServiceRunning) {
- showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT);
+ if (mFaceUnlock.installedAndSelected() && mFaceUnlock.isServiceRunning()) {
+ mFaceUnlock.showAreaWithTimeout(mFaceUnlock.viewAreaEmergencyDialerTimeout());
}
// FaceLock must be stopped if it is running when emergency call is pressed
- stopAndUnbindFromFaceLock();
+ mFaceUnlock.stopAndUnbind();
pokeWakelock(EMERGENCY_CALL_TIMEOUT);
if (TelephonyManager.getDefault().getCallState()
@@ -450,7 +421,8 @@
LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
super(context, callback);
- mHandler = new Handler(this);
+ mFaceUnlock = new FaceUnlock(context, updateMonitor, lockPatternUtils,
+ mKeyguardScreenCallback);
mConfiguration = context.getResources().getConfiguration();
mEnableFallback = false;
mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
@@ -570,36 +542,7 @@
saveWidgetState();
// When screen is turned off, need to unbind from FaceLock service if using FaceLock
- stopAndUnbindFromFaceLock();
- }
-
- /** When screen is turned on and focused, need to bind to FaceLock service if we are using
- * FaceLock, but only if we're not dealing with a call
- */
- private void activateFaceLockIfAble() {
- final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached();
- final int failedBackupAttempts = mUpdateMonitor.getFailedAttempts();
- final boolean backupIsTimedOut =
- (failedBackupAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
- if (tooManyFaceUnlockTries) Log.i(TAG, "tooManyFaceUnlockTries: " + tooManyFaceUnlockTries);
- if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
- && usingFaceLock()
- && !mHasOverlay
- && !tooManyFaceUnlockTries
- && !backupIsTimedOut) {
- bindToFaceLock();
-
- // Show FaceLock area, but only for a little bit so lockpattern will become visible if
- // FaceLock fails to start or crashes
- showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_SERVICE_TIMEOUT);
-
- // When switching between portrait and landscape view while FaceLock is running, the
- // screen will eventually go dark unless we poke the wakelock when FaceLock is
- // restarted
- mKeyguardScreenCallback.pokeWakelock();
- } else {
- hideFaceLockArea();
- }
+ mFaceUnlock.stopAndUnbind();
}
@Override
@@ -616,7 +559,7 @@
restoreWidgetState();
- if (runFaceLock) activateFaceLockIfAble();
+ if (runFaceLock) mFaceUnlock.activateIfAble(mHasOverlay);
}
private void saveWidgetState() {
@@ -647,13 +590,13 @@
if(mScreenOn && !mWindowFocused) runFaceLock = hasWindowFocus;
mWindowFocused = hasWindowFocus;
}
- if(!hasWindowFocus) {
+ if (!hasWindowFocus) {
mHasOverlay = true;
- stopAndUnbindFromFaceLock();
- hideFaceLockArea();
+ mFaceUnlock.stopAndUnbind();
+ mFaceUnlock.hideArea();
} else {
mHasDialog = false;
- if (runFaceLock) activateFaceLockIfAble();
+ if (runFaceLock) mFaceUnlock.activateIfAble(mHasOverlay);
}
}
@@ -667,14 +610,14 @@
((KeyguardScreen) mUnlockScreen).onResume();
}
- if (usingFaceLock() && !mHasOverlay) {
+ if (mFaceUnlock.installedAndSelected() && !mHasOverlay) {
// Note that show() gets called before the screen turns off to set it up for next time
// it is turned on. We don't want to set a timeout on the FaceLock area here because it
// may be gone by the time the screen is turned on again. We set the timeout when the
// screen turns on instead.
- showFaceLockArea();
+ mFaceUnlock.showArea();
} else {
- hideFaceLockArea();
+ mFaceUnlock.hideArea();
}
}
@@ -710,7 +653,7 @@
// When view is hidden, need to unbind from FaceLock service if we are using FaceLock
// e.g., when device becomes unlocked
- stopAndUnbindFromFaceLock();
+ mFaceUnlock.stopAndUnbind();
super.onDetachedFromWindow();
}
@@ -734,9 +677,9 @@
mHasOverlay |= mPluggedIn != pluggedIn;
mPluggedIn = pluggedIn;
//If it's already running, don't close it down: the unplug didn't start it
- if (!mFaceLockServiceRunning) {
- stopAndUnbindFromFaceLock();
- hideFaceLockArea();
+ if (!mFaceUnlock.isServiceRunning()) {
+ mFaceUnlock.stopAndUnbind();
+ mFaceUnlock.hideArea();
}
}
@@ -753,8 +696,8 @@
if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
mHasOverlay = true;
- stopAndUnbindFromFaceLock();
- hideFaceLockArea();
+ mFaceUnlock.stopAndUnbind();
+ mFaceUnlock.hideArea();
}
}
@@ -822,15 +765,7 @@
mUnlockScreen = null;
}
mUpdateMonitor.removeCallback(this);
- if (mFaceLockService != null) {
- try {
- mFaceLockService.unregisterCallback(mFaceLockCallback);
- } catch (RemoteException e) {
- // Not much we can do
- }
- stopFaceLock();
- mFaceLockService = null;
- }
+ mFaceUnlock.cleanUp();
}
private boolean isSecure() {
@@ -880,9 +815,9 @@
final UnlockMode unlockMode = getUnlockMode();
if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
- boolean restartFaceLock = stopFaceLockIfRunning();
+ boolean restartFaceLock = mFaceUnlock.stopIfRunning();
recreateUnlockScreen(unlockMode);
- if (restartFaceLock) activateFaceLockIfAble();
+ if (restartFaceLock) mFaceUnlock.activateIfAble(mHasOverlay);
}
}
@@ -995,7 +930,7 @@
throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
}
initializeTransportControlView(unlockView);
- initializeFaceLockAreaView(unlockView); // Only shows view if FaceLock is enabled
+ mFaceUnlock.initializeAreaView(unlockView); // Only shows view if FaceLock is enabled
mUnlockScreenMode = unlockMode;
return unlockView;
@@ -1177,254 +1112,4 @@
return mBitmap.getHeight();
}
}
-
- // Everything below pertains to FaceLock - might want to separate this out
-
- // Indicates whether FaceLock is in use
- private boolean usingFaceLock() {
- return (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled());
- }
-
- // Takes care of FaceLock area when layout is created
- private void initializeFaceLockAreaView(View view) {
- if (usingFaceLock()) {
- mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView);
- if (mFaceLockAreaView == null) {
- Log.e(TAG, "Layout does not have faceLockAreaView and FaceLock is enabled");
- }
- } else {
- mFaceLockAreaView = null; // Set to null if not using FaceLock
- }
- }
-
- // Stops FaceLock if it is running and reports back whether it was running or not
- private boolean stopFaceLockIfRunning() {
- if (usingFaceLock() && mBoundToFaceLockService) {
- stopAndUnbindFromFaceLock();
- return true;
- }
- return false;
- }
-
- // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
- // This needs to be done in a handler because the call could be coming from a callback from the
- // FaceLock service that is in a thread that can't modify the UI
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SHOW_FACELOCK_AREA_VIEW:
- if (mFaceLockAreaView != null) {
- mFaceLockAreaView.setVisibility(View.VISIBLE);
- }
- break;
- case MSG_HIDE_FACELOCK_AREA_VIEW:
- if (mFaceLockAreaView != null) {
- mFaceLockAreaView.setVisibility(View.INVISIBLE);
- }
- break;
- default:
- Log.w(TAG, "Unhandled message");
- return false;
- }
- return true;
- }
-
- // Removes show and hide messages from the message queue
- private void removeFaceLockAreaDisplayMessages() {
- mHandler.removeMessages(MSG_SHOW_FACELOCK_AREA_VIEW);
- mHandler.removeMessages(MSG_HIDE_FACELOCK_AREA_VIEW);
- }
-
- // Shows the FaceLock area immediately
- private void showFaceLockArea() {
- // Remove messages to prevent a delayed hide message from undo-ing the show
- removeFaceLockAreaDisplayMessages();
- mHandler.sendEmptyMessage(MSG_SHOW_FACELOCK_AREA_VIEW);
- }
-
- // Hides the FaceLock area immediately
- private void hideFaceLockArea() {
- // Remove messages to prevent a delayed show message from undo-ing the hide
- removeFaceLockAreaDisplayMessages();
- mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW);
- }
-
- // Shows the FaceLock area for a period of time
- private void showFaceLockAreaWithTimeout(long timeoutMillis) {
- showFaceLockArea();
- mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACELOCK_AREA_VIEW, timeoutMillis);
- }
-
- // Binds to FaceLock service. This call does not tell it to start, but it causes the service
- // to call the onServiceConnected callback, which then starts FaceLock.
- public void bindToFaceLock() {
- if (usingFaceLock()) {
- if (!mBoundToFaceLockService) {
- if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
- mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
- mFaceLockConnection,
- Context.BIND_AUTO_CREATE);
- if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
- mBoundToFaceLockService = true;
- } else {
- Log.w(TAG, "Attempt to bind to FaceLock when already bound");
- }
- }
- }
-
- // Tells FaceLock to stop and then unbinds from the FaceLock service
- public void stopAndUnbindFromFaceLock() {
- if (usingFaceLock()) {
- stopFaceLock();
-
- if (mBoundToFaceLockService) {
- if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
- if (mFaceLockService != null) {
- try {
- mFaceLockService.unregisterCallback(mFaceLockCallback);
- } catch (RemoteException e) {
- // Not much we can do
- }
- }
- mContext.unbindService(mFaceLockConnection);
- if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
- mBoundToFaceLockService = false;
- } else {
- // This is usually not an error when this happens. Sometimes we will tell it to
- // unbind multiple times because it's called from both onWindowFocusChanged and
- // onDetachedFromWindow.
- if (DEBUG) Log.d(TAG, "Attempt to unbind from FaceLock when not bound");
- }
- }
- }
-
- private ServiceConnection mFaceLockConnection = new ServiceConnection() {
- // Completes connection, registers callback and starts FaceLock when service is bound
- @Override
- public void onServiceConnected(ComponentName className, IBinder iservice) {
- mFaceLockService = IFaceLockInterface.Stub.asInterface(iservice);
- if (DEBUG) Log.d(TAG, "Connected to FaceLock service");
- try {
- mFaceLockService.registerCallback(mFaceLockCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught exception connecting to FaceLock: " + e.toString());
- mFaceLockService = null;
- mBoundToFaceLockService = false;
- return;
- }
-
- if (mFaceLockAreaView != null) {
- int[] faceLockPosition;
- faceLockPosition = new int[2];
- mFaceLockAreaView.getLocationInWindow(faceLockPosition);
- startFaceLock(mFaceLockAreaView.getWindowToken(),
- faceLockPosition[0], faceLockPosition[1],
- mFaceLockAreaView.getWidth(), mFaceLockAreaView.getHeight());
- }
- }
-
- // Cleans up if FaceLock service unexpectedly disconnects
- @Override
- public void onServiceDisconnected(ComponentName className) {
- synchronized(mFaceLockServiceRunningLock) {
- mFaceLockService = null;
- mFaceLockServiceRunning = false;
- }
- mBoundToFaceLockService = false;
- Log.w(TAG, "Unexpected disconnect from FaceLock service");
- }
- };
-
- // Tells the FaceLock service to start displaying its UI and perform recognition
- public void startFaceLock(IBinder windowToken, int x, int y, int w, int h)
- {
- if (usingFaceLock()) {
- synchronized (mFaceLockServiceRunningLock) {
- if (!mFaceLockServiceRunning) {
- if (DEBUG) Log.d(TAG, "Starting FaceLock");
- try {
- mFaceLockService.startUi(windowToken, x, y, w, h);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
- return;
- }
- mFaceLockServiceRunning = true;
- } else {
- if (DEBUG) Log.w(TAG, "startFaceLock() attempted while running");
- }
- }
- }
- }
-
- // Tells the FaceLock service to stop displaying its UI and stop recognition
- public void stopFaceLock()
- {
- if (usingFaceLock()) {
- // Note that attempting to stop FaceLock when it's not running is not an issue.
- // FaceLock can return, which stops it and then we try to stop it when the
- // screen is turned off. That's why we check.
- synchronized (mFaceLockServiceRunningLock) {
- if (mFaceLockServiceRunning) {
- try {
- if (DEBUG) Log.d(TAG, "Stopping FaceLock");
- mFaceLockService.stopUi();
- } catch (RemoteException e) {
- Log.e(TAG, "Caught exception stopping FaceLock: " + e.toString());
- }
- mFaceLockServiceRunning = false;
- }
- }
- }
- }
-
- // Implements the FaceLock service callback interface defined in AIDL
- private final IFaceLockCallback mFaceLockCallback = new IFaceLockCallback.Stub() {
-
- // Stops the FaceLock UI and indicates that the phone should be unlocked
- @Override
- public void unlock() {
- if (DEBUG) Log.d(TAG, "FaceLock unlock()");
- showFaceLockArea(); // Keep fallback covered
- stopAndUnbindFromFaceLock();
-
- mKeyguardScreenCallback.keyguardDone(true);
- mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
- }
-
- // Stops the FaceLock UI and exposes the backup method without unlocking
- // This means the user has cancelled out
- @Override
- public void cancel() {
- if (DEBUG) Log.d(TAG, "FaceLock cancel()");
- hideFaceLockArea(); // Expose fallback
- stopAndUnbindFromFaceLock();
- mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
- }
-
- // Stops the FaceLock UI and exposes the backup method without unlocking
- // This means FaceLock failed to recognize them
- @Override
- public void reportFailedAttempt() {
- if (DEBUG) Log.d(TAG, "FaceLock reportFailedAttempt()");
- mUpdateMonitor.reportFailedFaceUnlockAttempt();
- hideFaceLockArea(); // Expose fallback
- stopAndUnbindFromFaceLock();
- mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
- }
-
- // Removes the black area that covers the backup unlock method
- @Override
- public void exposeFallback() {
- if (DEBUG) Log.d(TAG, "FaceLock exposeFallback()");
- hideFaceLockArea(); // Expose fallback
- }
-
- // Allows the Face Unlock service to poke the wake lock to keep the lockscreen alive
- @Override
- public void pokeWakelock() {
- if (DEBUG) Log.d(TAG, "FaceLock pokeWakelock()");
- mKeyguardScreenCallback.pokeWakelock();
- }
- };
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c3cac6e..f3622ef 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -132,6 +132,9 @@
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import android.view.KeyCharacterMap.FallbackAction;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Animation;
@@ -237,8 +240,6 @@
static final int SYSTEM_UI_CHANGING_LAYOUT =
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
- // Useful scan codes.
- private static final int SW_LID = 0x00;
private static final int BTN_MOUSE = 0x110;
/* Table of Application Launch keys. Maps from key codes to intent categories.
@@ -322,10 +323,6 @@
RecentApplicationsDialog mRecentAppsDialog;
int mRecentAppsDialogHeldModifiers;
- private static final int LID_ABSENT = -1;
- private static final int LID_CLOSED = 0;
- private static final int LID_OPEN = 1;
-
int mLidOpen = LID_ABSENT;
boolean mSystemReady;
@@ -976,12 +973,13 @@
com.android.internal.R.dimen.navigation_bar_width);
// Determine whether the status bar can hide based on the size
- // of the screen. We assume sizes > 600dp are tablets where we
+ // of the screen. We assume sizes >= 600dp are tablets where we
// will use the system bar.
+ // XXX: This will change to 720dp soon.
int shortSizeDp = shortSize
* DisplayMetrics.DENSITY_DEFAULT
/ DisplayMetrics.DENSITY_DEVICE;
- mHasSystemNavBar = shortSizeDp > 600;
+ mHasSystemNavBar = shortSizeDp >= 600;
if (!mHasSystemNavBar) {
mHasNavigationBar = mContext.getResources().getBoolean(
@@ -1120,16 +1118,11 @@
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
wm.addView(mPointerLocationView, lp);
- try {
- mPointerLocationInputChannel =
- mWindowManager.monitorInput("PointerLocationView");
- mPointerLocationInputEventReceiver =
- new PointerLocationInputEventReceiver(mPointerLocationInputChannel,
- Looper.myLooper(), mPointerLocationView);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.",
- ex);
- }
+ mPointerLocationInputChannel =
+ mWindowManagerFuncs.monitorInput("PointerLocationView");
+ mPointerLocationInputEventReceiver =
+ new PointerLocationInputEventReceiver(mPointerLocationInputChannel,
+ Looper.myLooper(), mPointerLocationView);
}
}
@@ -1223,18 +1216,7 @@
}
void readLidState() {
- try {
- int sw = mWindowManager.getSwitchState(SW_LID);
- if (sw > 0) {
- mLidOpen = LID_OPEN;
- } else if (sw == 0) {
- mLidOpen = LID_CLOSED;
- } else {
- mLidOpen = LID_ABSENT;
- }
- } catch (RemoteException e) {
- // Ignore
- }
+ mLidOpen = mWindowManagerFuncs.getLidState();
}
private int determineHiddenState(int mode, int hiddenValue, int visibleValue) {
@@ -1358,18 +1340,29 @@
}
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
- // Assumes that the navigation bar appears on the side of the display in landscape.
- if (mHasNavigationBar && fullWidth > fullHeight) {
- return fullWidth - mNavigationBarWidth;
+ if (mHasNavigationBar) {
+ // For a basic navigation bar, when we are in landscape mode we place
+ // the navigation bar to the side.
+ if (fullWidth > fullHeight) {
+ return fullWidth - mNavigationBarWidth;
+ }
}
return fullWidth;
}
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
- // Assumes the navigation bar appears on the bottom of the display in portrait.
- return fullHeight
- - (mHasSystemNavBar ? mNavigationBarHeight : 0)
- - ((mHasNavigationBar && fullWidth > fullHeight) ? 0 : mNavigationBarHeight);
+ if (mHasSystemNavBar) {
+ // For the system navigation bar, we always place it at the bottom.
+ return fullHeight - mNavigationBarHeight;
+ }
+ if (mHasNavigationBar) {
+ // For a basic navigation bar, when we are in portrait mode we place
+ // the navigation bar to the bottom.
+ if (fullWidth < fullHeight) {
+ return fullHeight - mNavigationBarHeight;
+ }
+ }
+ return fullHeight;
}
public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
@@ -1377,13 +1370,15 @@
}
public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
- // This is the same as getNonDecorDisplayHeight, unless the status bar
- // can hide. If the status bar can hide, we don't count that as part
- // of the decor; however for purposes of configurations, we do want to
- // exclude it since applications can't generally use that part of the
- // screen.
- return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation)
- - (mHasSystemNavBar ? 0 : mStatusBarHeight);
+ // If we don't have a system nav bar, then there is a separate status
+ // bar at the top of the display. We don't count that as part of the
+ // fixed decor, since it can hide; however, for purposes of configurations,
+ // we do want to exclude it since applications can't generally use that part
+ // of the screen.
+ if (!mHasSystemNavBar) {
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
+ }
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation);
}
public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
@@ -2230,10 +2225,14 @@
// decide where the status bar goes ahead of time
if (mStatusBar != null) {
// apply any navigation bar insets
- pf.left = df.left = vf.left = mDockLeft;
- pf.top = df.top = vf.top = mDockTop;
- pf.right = df.right = vf.right = mDockRight;
- pf.bottom = df.bottom = vf.bottom = mDockBottom;
+ pf.left = df.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = mUnrestrictedScreenTop;
+ pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft;
+ pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop;
+ vf.left = mStableLeft;
+ vf.top = mStableTop;
+ vf.right = mStableRight;
+ vf.bottom = mStableBottom;
mStatusBar.computeFrameLw(pf, df, vf, vf);
final Rect r = mStatusBar.getFrameLw();
@@ -3644,29 +3643,11 @@
}
}
- public boolean detectSafeMode() {
- try {
- int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
- int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
- int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
- int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
- int volumeDownState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_VOLUME_DOWN);
- mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
- || volumeDownState > 0;
- performHapticFeedbackLw(null, mSafeMode
- ? HapticFeedbackConstants.SAFE_MODE_ENABLED
- : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
- if (mSafeMode) {
- Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
- + " dpad=" + dpadState + " trackball=" + trackballState + ")");
- } else {
- Log.i(TAG, "SAFE MODE not enabled");
- }
- return mSafeMode;
- } catch (RemoteException e) {
- // Doom! (it's also local)
- throw new RuntimeException("window manager dead");
- }
+ public void setSafeMode(boolean safeMode) {
+ mSafeMode = safeMode;
+ performHapticFeedbackLw(null, safeMode
+ ? HapticFeedbackConstants.SAFE_MODE_ENABLED
+ : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
}
static long[] getLongIntArray(Resources r, int resid) {
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
index ef7fa168..7a4986b 100644
--- a/services/common_time/common_time_server.cpp
+++ b/services/common_time/common_time_server.cpp
@@ -80,14 +80,14 @@
// number of sync requests that can fail before a client assumes its master
// is dead
-const int CommonTimeServer::kClient_NumSyncRequestRetries = 5;
+const int CommonTimeServer::kClient_NumSyncRequestRetries = 10;
/*** Master state constants ***/
/*** Ronin state constants ***/
// number of WhoIsMaster attempts sent before declaring ourselves master
-const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 4;
+const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 20;
// timeout used when waiting for a response to a WhoIsMaster request
const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500;
@@ -96,7 +96,7 @@
// how long do we wait for an announcement from a master before
// trying another election?
-const int CommonTimeServer::kWaitForElection_TimeoutMs = 5000;
+const int CommonTimeServer::kWaitForElection_TimeoutMs = 12500;
CommonTimeServer::CommonTimeServer()
: Thread(false)
@@ -279,10 +279,14 @@
// If we were in the master state, then either we were the
// master in a no-network situation, or we were the master
// of a different network and have moved to a new interface.
- // In either case, immediately send out a master
- // announcement at low priority.
+ // In either case, immediately transition to Ronin at low
+ // priority. If there is no one in the network we just
+ // joined, we will become master soon enough. If there is,
+ // we want to be certain to defer master status to the
+ // existing timeline currently running on the network.
+ //
case CommonClockService::STATE_MASTER:
- sendMasterAnnouncement();
+ becomeRonin("leaving networkless mode");
break;
// If we were in any other state (CLIENT, RONIN, or
@@ -1072,6 +1076,12 @@
mMasterEP = masterEP;
mMasterEPValid = true;
+
+ // If we are on a real network as a client of a real master, then we should
+ // no longer force low priority. If our master disappears, we should have
+ // the high priority bit set during the election to replace the master
+ // because this group was a real group and not a singleton created in
+ // networkless mode.
setForceLowPriority(false);
mClient_MasterDeviceID = masterDeviceID;
@@ -1113,7 +1123,6 @@
memset(&mMasterEP, 0, sizeof(mMasterEP));
mMasterEPValid = false;
- setForceLowPriority(false);
mClient_MasterDevicePriority = effectivePriority();
mClient_MasterDeviceID = mDeviceID;
mClockRecovery.reset(false, true);
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 1b74aa6..7060ae2 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -40,6 +40,7 @@
#include <androidfw/KeyCharacterMap.h>
#include <androidfw/VirtualKeyMap.h>
+#include <sha1.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
@@ -78,6 +79,20 @@
return value ? "true" : "false";
}
+static String8 sha1(const String8& in) {
+ SHA1_CTX ctx;
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
+ u_char digest[SHA1_DIGEST_LENGTH];
+ SHA1Final(digest, &ctx);
+
+ String8 out;
+ for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+ out.appendFormat("%02x", digest[i]);
+ }
+ return out;
+}
+
// --- Global Functions ---
uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
@@ -209,11 +224,11 @@
release_wake_lock(WAKE_LOCK_ID);
}
-String8 EventHub::getDeviceName(int32_t deviceId) const {
+InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device == NULL) return String8();
- return device->identifier.name;
+ if (device == NULL) return InputDeviceIdentifier();
+ return device->identifier;
}
uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
@@ -893,6 +908,30 @@
identifier.uniqueId.setTo(buffer);
}
+ // Compute a device descriptor that uniquely identifies the device.
+ // The descriptor is assumed to be a stable identifier. Its value should not
+ // change between reboots, reconnections, firmware updates or new releases of Android.
+ // Ideally, we also want the descriptor to be short and relatively opaque.
+ String8 rawDescriptor;
+ rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product);
+ if (!identifier.uniqueId.isEmpty()) {
+ rawDescriptor.append("uniqueId:");
+ rawDescriptor.append(identifier.uniqueId);
+ } if (identifier.vendor == 0 && identifier.product == 0) {
+ // If we don't know the vendor and product id, then the device is probably
+ // built-in so we need to rely on other information to uniquely identify
+ // the input device. Usually we try to avoid relying on the device name or
+ // location but for built-in input device, they are unlikely to ever change.
+ if (!identifier.name.isEmpty()) {
+ rawDescriptor.append("name:");
+ rawDescriptor.append(identifier.name);
+ } else if (!identifier.location.isEmpty()) {
+ rawDescriptor.append("location:");
+ rawDescriptor.append(identifier.location);
+ }
+ }
+ identifier.descriptor = sha1(rawDescriptor);
+
// Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
ALOGE("Error %d making device file descriptor non-blocking.", errno);
@@ -904,19 +943,18 @@
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
-#if 0
- ALOGI("add device %d: %s\n", deviceId, devicePath);
- ALOGI(" bus: %04x\n"
- " vendor %04x\n"
- " product %04x\n"
- " version %04x\n",
+ ALOGV("add device %d: %s\n", deviceId, devicePath);
+ ALOGV(" bus: %04x\n"
+ " vendor %04x\n"
+ " product %04x\n"
+ " version %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
- ALOGI(" name: \"%s\"\n", identifier.name.string());
- ALOGI(" location: \"%s\"\n", identifier.location.string());
- ALOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
- ALOGI(" driver: v%d.%d.%d\n",
+ ALOGV(" name: \"%s\"\n", identifier.name.string());
+ ALOGV(" location: \"%s\"\n", identifier.location.string());
+ ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string());
+ ALOGV(" descriptor: \"%s\" (%s)\n", identifier.descriptor.string(), rawDescriptor.string());
+ ALOGV(" driver: v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
-#endif
// Load the configuration file for the device.
loadConfigurationLocked(device);
@@ -1065,18 +1103,35 @@
// Enable wake-lock behavior on kernels that support it.
// TODO: Only need this for devices that can really wake the system.
- bool usingSuspendBlock = ioctl(fd, EVIOCSSUSPENDBLOCK, 1) == 0;
+ bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1);
+
+ // Tell the kernel that we want to use the monotonic clock for reporting timestamps
+ // associated with input events. This is important because the input system
+ // uses the timestamps extensively and assumes they were recorded using the monotonic
+ // clock.
+ //
+ // In older kernel, before Linux 3.4, there was no way to tell the kernel which
+ // clock to use to input event timestamps. The standard kernel behavior was to
+ // record a real time timestamp, which isn't what we want. Android kernels therefore
+ // contained a patch to the evdev_event() function in drivers/input/evdev.c to
+ // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
+ // clock to be used instead of the real time clock.
+ //
+ // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
+ // Therefore, we no longer require the Android-specific kernel patch described above
+ // as long as we make sure to set select the monotonic clock. We do that here.
+ bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, CLOCK_MONOTONIC);
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
- "usingSuspendBlock=%s",
+ "usingSuspendBlockIoctl=%s, usingClockIoctl=%s",
deviceId, fd, devicePath, device->identifier.name.string(),
device->classes,
device->configurationFile.string(),
device->keyMap.keyLayoutFile.string(),
device->keyMap.keyCharacterMapFile.string(),
toString(mBuiltInKeyboardId == deviceId),
- toString(usingSuspendBlock));
+ toString(usingSuspendBlockIoctl), toString(usingClockIoctl));
mDevices.add(deviceId, device);
@@ -1303,6 +1358,7 @@
}
dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
+ dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 4eb47c6..bd21a3d 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -151,7 +151,7 @@
virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
- virtual String8 getDeviceName(int32_t deviceId) const = 0;
+ virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0;
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
@@ -230,7 +230,7 @@
virtual uint32_t getDeviceClasses(int32_t deviceId) const;
- virtual String8 getDeviceName(int32_t deviceId) const;
+ virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const;
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index eccce292..ddd870d 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -344,18 +344,19 @@
}
void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
- String8 name = mEventHub->getDeviceName(deviceId);
+ InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- InputDevice* device = createDeviceLocked(deviceId, name, classes);
+ InputDevice* device = createDeviceLocked(deviceId, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
if (device->isIgnored()) {
- ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string());
+ ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
+ identifier.name.string());
} else {
- ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(),
- device->getSources());
+ ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
+ identifier.name.string(), device->getSources());
}
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
@@ -392,8 +393,8 @@
}
InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
- const String8& name, uint32_t classes) {
- InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);
+ const InputDeviceIdentifier& identifier, uint32_t classes) {
+ InputDevice* device = new InputDevice(&mContext, deviceId, identifier, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
@@ -851,9 +852,9 @@
// --- InputDevice ---
-InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name,
- uint32_t classes) :
- mContext(context), mId(id), mName(name), mClasses(classes),
+InputDevice::InputDevice(InputReaderContext* context, int32_t id,
+ const InputDeviceIdentifier& identifier, uint32_t classes) :
+ mContext(context), mId(id), mIdentifier(identifier), mClasses(classes),
mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
}
@@ -961,7 +962,7 @@
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) {
- ALOGI("Detected input event buffer overrun for device %s.", mName.string());
+ ALOGI("Detected input event buffer overrun for device %s.", getName().string());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
@@ -982,7 +983,7 @@
}
void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
- outDeviceInfo->initialize(mId, mName);
+ outDeviceInfo->initialize(mId, mIdentifier.name, mIdentifier.descriptor);
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 9bbe49c..8520a75 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -338,7 +338,7 @@
protected:
// These members are protected so they can be instrumented by test cases.
virtual InputDevice* createDeviceLocked(int32_t deviceId,
- const String8& name, uint32_t classes);
+ const InputDeviceIdentifier& identifier, uint32_t classes);
class ContextImpl : public InputReaderContext {
InputReader* mReader;
@@ -432,12 +432,13 @@
/* Represents the state of a single input device. */
class InputDevice {
public:
- InputDevice(InputReaderContext* context, int32_t id, const String8& name, uint32_t classes);
+ InputDevice(InputReaderContext* context, int32_t id,
+ const InputDeviceIdentifier& identifier, uint32_t classes);
~InputDevice();
inline InputReaderContext* getContext() { return mContext; }
inline int32_t getId() { return mId; }
- inline const String8& getName() { return mName; }
+ inline const String8& getName() { return mIdentifier.name; }
inline uint32_t getClasses() { return mClasses; }
inline uint32_t getSources() { return mSources; }
@@ -486,7 +487,7 @@
private:
InputReaderContext* mContext;
int32_t mId;
- String8 mName;
+ InputDeviceIdentifier mIdentifier;
uint32_t mClasses;
Vector<InputMapper*> mMappers;
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 08efe7d..2cccf9f 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -274,7 +274,7 @@
};
struct Device {
- String8 name;
+ InputDeviceIdentifier identifier;
uint32_t classes;
PropertyMap configuration;
KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
@@ -287,8 +287,8 @@
KeyedVector<int32_t, bool> leds;
Vector<VirtualKeyDefinition> virtualKeys;
- Device(const String8& name, uint32_t classes) :
- name(name), classes(classes) {
+ Device(uint32_t classes) :
+ classes(classes) {
}
};
@@ -307,7 +307,8 @@
FakeEventHub() { }
void addDevice(int32_t deviceId, const String8& name, uint32_t classes) {
- Device* device = new Device(name, classes);
+ Device* device = new Device(classes);
+ device->identifier.name = name;
mDevices.add(deviceId, device);
enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0, 0, 0);
@@ -433,9 +434,9 @@
return device ? device->classes : 0;
}
- virtual String8 getDeviceName(int32_t deviceId) const {
+ virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const {
Device* device = getDevice(deviceId);
- return device ? device->name : String8("unknown");
+ return device ? device->identifier : InputDeviceIdentifier();
}
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
@@ -857,18 +858,20 @@
}
InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) {
- return new InputDevice(&mContext, deviceId, name, classes);
+ InputDeviceIdentifier identifier;
+ identifier.name = name;
+ return new InputDevice(&mContext, deviceId, identifier, classes);
}
protected:
virtual InputDevice* createDeviceLocked(int32_t deviceId,
- const String8& name, uint32_t classes) {
+ const InputDeviceIdentifier& identifier, uint32_t classes) {
if (mNextDevice) {
InputDevice* device = mNextDevice;
mNextDevice = NULL;
return device;
}
- return InputReader::createDeviceLocked(deviceId, name, classes);
+ return InputReader::createDeviceLocked(deviceId, identifier, classes);
}
friend class InputReaderTest;
@@ -1231,7 +1234,9 @@
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
- mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME), DEVICE_CLASSES);
+ InputDeviceIdentifier identifier;
+ identifier.name = DEVICE_NAME;
+ mDevice = new InputDevice(mFakeContext, DEVICE_ID, identifier, DEVICE_CLASSES);
}
virtual void TearDown() {
@@ -1411,7 +1416,9 @@
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new FakeInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
- mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME), DEVICE_CLASSES);
+ InputDeviceIdentifier identifier;
+ identifier.name = DEVICE_NAME;
+ mDevice = new InputDevice(mFakeContext, DEVICE_ID, identifier, DEVICE_CLASSES);
mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
}
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 0574405..32ac8e1 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -34,9 +34,9 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.WorkSource;
import android.text.TextUtils;
import android.text.format.Time;
-import android.util.EventLog;
import android.util.Slog;
import android.util.TimeUtils;
@@ -50,6 +50,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.Map;
import java.util.TimeZone;
@@ -89,6 +90,7 @@
private int mDescriptor;
private int mBroadcastRefCount = 0;
private PowerManager.WakeLock mWakeLock;
+ private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>();
private final AlarmThread mWaitThread = new AlarmThread();
private final AlarmHandler mHandler = new AlarmHandler();
private ClockReceiver mClockReceiver;
@@ -668,10 +670,12 @@
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
- // we have an active broadcast so stay awake.
+ // we have an active broadcast so stay awake.
if (mBroadcastRefCount == 0) {
+ setWakelockWorkSource(alarm.operation);
mWakeLock.acquire();
}
+ mInFlight.add(alarm.operation);
mBroadcastRefCount++;
BroadcastStats bs = getStatsLocked(alarm.operation);
@@ -700,7 +704,22 @@
}
}
}
-
+
+ void setWakelockWorkSource(PendingIntent pi) {
+ try {
+ final int uid = ActivityManagerNative.getDefault()
+ .getUidForIntentSender(pi.getTarget());
+ if (uid >= 0) {
+ mWakeLock.setWorkSource(new WorkSource(uid));
+ return;
+ }
+ } catch (Exception e) {
+ }
+
+ // Something went wrong; fall back to attributing the lock to the OS
+ mWakeLock.setWorkSource(null);
+ }
+
private class AlarmHandler extends Handler {
public static final int ALARM_EVENT = 1;
public static final int MINUTE_CHANGE_EVENT = 2;
@@ -876,9 +895,20 @@
fs.count++;
}
}
+ mInFlight.removeFirst();
mBroadcastRefCount--;
if (mBroadcastRefCount == 0) {
mWakeLock.release();
+ } else {
+ // the next of our alarms is now in flight. reattribute the wakelock.
+ final PendingIntent nowInFlight = mInFlight.peekFirst();
+ if (nowInFlight != null) {
+ setWakelockWorkSource(nowInFlight);
+ } else {
+ // should never happen
+ Slog.e(TAG, "Alarm wakelock still held but sent queue empty");
+ mWakeLock.setWorkSource(null);
+ }
}
}
}
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 9b4eddc..53d1f0e 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -301,13 +301,13 @@
// Pack up the values and broadcast them to everyone
if (headset == BIT_USB_HEADSET_ANLG) {
- intent = new Intent(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+ intent = new Intent(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("state", state);
intent.putExtra("name", headsetName);
ActivityManagerNative.broadcastStickyIntent(intent, null);
} else if (headset == BIT_USB_HEADSET_DGTL) {
- intent = new Intent(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+ intent = new Intent(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra("state", state);
intent.putExtra("name", headsetName);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2da827e..80e59cd 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4444,6 +4444,17 @@
return null;
}
+ public int getUidForIntentSender(IIntentSender sender) {
+ if (sender instanceof PendingIntentRecord) {
+ try {
+ PendingIntentRecord res = (PendingIntentRecord)sender;
+ return res.uid;
+ } catch (ClassCastException e) {
+ }
+ }
+ return -1;
+ }
+
public boolean isIntentSenderTargetedToPackage(IIntentSender pendingResult) {
if (!(pendingResult instanceof PendingIntentRecord)) {
return false;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index d60ff2b..a098f18 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import com.android.internal.app.ResolverActivity;
import com.android.server.AttributeCache;
import com.android.server.am.ActivityStack.ActivityState;
@@ -382,7 +383,7 @@
_intent.getData() == null &&
_intent.getType() == null &&
(intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
- !"android".equals(realActivity.getClassName())) {
+ !ResolverActivity.class.getName().equals(realActivity.getClassName())) {
// This sure looks like a home activity!
// Note the last check is so we don't count the resolver
// activity as being home... really, we don't care about
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 6a566ae..b8cc65e 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -28,11 +28,13 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.hardware.input.IInputManager;
+import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
+import android.os.Process;
import android.os.SystemProperties;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -108,18 +110,16 @@
private static native void nativeSetShowTouches(int ptr, boolean enabled);
private static native String nativeDump(int ptr);
private static native void nativeMonitor(int ptr);
-
- // Input event injection constants defined in InputDispatcher.h.
- public static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
- public static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
- public static final int INPUT_EVENT_INJECTION_FAILED = 2;
- public static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
- // Input event injection synchronization modes defined in InputDispatcher.h
- public static final int INPUT_EVENT_INJECTION_SYNC_NONE = 0;
- public static final int INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1;
- public static final int INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH = 2;
-
+ // Input event injection constants defined in InputDispatcher.h.
+ private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
+ private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
+ private static final int INPUT_EVENT_INJECTION_FAILED = 2;
+ private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
+
+ // Maximum number of milliseconds to wait for input event injection.
+ private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
+
// Key states (may be returned by queries about the current state of a
// particular key code, scan code or switch).
@@ -194,7 +194,7 @@
nativeGetInputConfiguration(mPtr, config);
}
-
+
/**
* Gets the current state of a key or button by key code.
* @param deviceId The input device id, or -1 to consult all devices.
@@ -246,6 +246,7 @@
* key codes.
* @return True if the lookup was successful, false otherwise.
*/
+ @Override
public boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists) {
if (keyCodes == null) {
throw new IllegalArgumentException("keyCodes must not be null.");
@@ -336,43 +337,42 @@
}
}
- /**
- * Injects an input event into the event system on behalf of an application.
- * The synchronization mode determines whether the method blocks while waiting for
- * input injection to proceed.
- *
- * {@link #INPUT_EVENT_INJECTION_SYNC_NONE} never blocks. Injection is asynchronous and
- * is assumed always to be successful.
- *
- * {@link #INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT} waits for previous events to be
- * dispatched so that the input dispatcher can determine whether input event injection will
- * be permitted based on the current input focus. Does not wait for the input event to
- * finish processing.
- *
- * {@link #INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH} waits for the input event to
- * be completely processed.
- *
- * @param event The event to inject.
- * @param injectorPid The pid of the injecting application.
- * @param injectorUid The uid of the injecting application.
- * @param syncMode The synchronization mode.
- * @param timeoutMillis The injection timeout in milliseconds.
- * @return One of the INPUT_EVENT_INJECTION_XXX constants.
- */
- public int injectInputEvent(InputEvent event, int injectorPid, int injectorUid,
- int syncMode, int timeoutMillis) {
+ @Override
+ public boolean injectInputEvent(InputEvent event, int mode) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
- if (injectorPid < 0 || injectorUid < 0) {
- throw new IllegalArgumentException("injectorPid and injectorUid must not be negative.");
- }
- if (timeoutMillis <= 0) {
- throw new IllegalArgumentException("timeoutMillis must be positive");
+ if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
+ && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
+ && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
+ throw new IllegalArgumentException("mode is invalid");
}
- return nativeInjectInputEvent(mPtr, event, injectorPid, injectorUid, syncMode,
- timeoutMillis, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ final int result;
+ try {
+ result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
+ INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ switch (result) {
+ case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+ Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
+ throw new SecurityException(
+ "Injecting to another application requires INJECT_EVENTS permission");
+ case INPUT_EVENT_INJECTION_SUCCEEDED:
+ return true;
+ case INPUT_EVENT_INJECTION_TIMED_OUT:
+ Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
+ return false;
+ case INPUT_EVENT_INJECTION_FAILED:
+ default:
+ Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
+ return false;
+ }
}
/**
@@ -380,6 +380,7 @@
* @param id The device id.
* @return The input device or null if not found.
*/
+ @Override
public InputDevice getInputDevice(int deviceId) {
return nativeGetInputDevice(mPtr, deviceId);
}
@@ -388,6 +389,7 @@
* Gets the ids of all input devices in the system.
* @return The input device ids.
*/
+ @Override
public int[] getInputDeviceIds() {
return nativeGetInputDeviceIds(mPtr);
}
@@ -436,14 +438,25 @@
* @param speed The pointer speed as a value between -7 (slowest) and 7 (fastest)
* where 0 is the default speed.
*/
- public void setPointerSpeed(int speed) {
- speed = Math.min(Math.max(speed, -7), 7);
- nativeSetPointerSpeed(mPtr, speed);
+ @Override
+ public void tryPointerSpeed(int speed) {
+ if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
+ "tryPointerSpeed()")) {
+ throw new SecurityException("Requires SET_POINTER_SPEED permission");
+ }
+
+ setPointerSpeedUnchecked(speed);
}
public void updatePointerSpeedFromSettings() {
- int speed = getPointerSpeedSetting(0);
- setPointerSpeed(speed);
+ int speed = getPointerSpeedSetting();
+ setPointerSpeedUnchecked(speed);
+ }
+
+ private void setPointerSpeedUnchecked(int speed) {
+ speed = Math.min(Math.max(speed, InputManager.MIN_POINTER_SPEED),
+ InputManager.MAX_POINTER_SPEED);
+ nativeSetPointerSpeed(mPtr, speed);
}
private void registerPointerSpeedSettingObserver() {
@@ -457,8 +470,8 @@
});
}
- private int getPointerSpeedSetting(int defaultValue) {
- int speed = defaultValue;
+ private int getPointerSpeedSetting() {
+ int speed = InputManager.DEFAULT_POINTER_SPEED;
try {
speed = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.POINTER_SPEED);
@@ -510,6 +523,23 @@
}
}
+ private boolean checkCallingPermission(String permission, String func) {
+ // Quick check: if the calling permission is me, it's all okay.
+ if (Binder.getCallingPid() == Process.myPid()) {
+ return true;
+ }
+
+ if (mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ String msg = "Permission Denial: " + func + " from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + permission;
+ Slog.w(TAG, msg);
+ return false;
+ }
+
// Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection).
public void monitor() {
synchronized (mInputFilterLock) { }
@@ -703,7 +733,8 @@
synchronized (mInputFilterLock) {
if (!mDisconnected) {
- nativeInjectInputEvent(mPtr, event, 0, 0, INPUT_EVENT_INJECTION_SYNC_NONE, 0,
+ nativeInjectInputEvent(mPtr, event, 0, 0,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
policyFlags | WindowManagerPolicy.FLAG_FILTERED);
}
}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index b0657a6..fa62e497 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1588,7 +1588,7 @@
}
private Handler.Callback mHandlerCallback = new Handler.Callback() {
- /** {@inheritDoc} */
+ @Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_RULES_CHANGED: {
@@ -1740,7 +1740,7 @@
private long getTotalBytes(NetworkTemplate template, long start, long end) {
try {
- return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes();
+ return mNetworkStats.getNetworkTotalBytes(template, start, end);
} catch (RuntimeException e) {
Slog.w(TAG, "problem reading network stats: " + e);
return 0;
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
index 70038d9..2892a74 100644
--- a/services/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -57,8 +57,6 @@
* {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
*/
public class NetworkStatsCollection implements FileRotator.Reader {
- private static final String TAG = "NetworkStatsCollection";
-
/** File header magic number: "ANET" */
private static final int FILE_MAGIC = 0x414E4554;
@@ -173,7 +171,7 @@
}
/**
- * Record given {@link NetworkStats.Entry} into this collection.
+ * Record given {@link android.net.NetworkStats.Entry} into this collection.
*/
public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
long end, NetworkStats.Entry entry) {
@@ -227,7 +225,7 @@
}
}
- /** {@inheritDoc} */
+ @Override
public void read(InputStream in) throws IOException {
read(new DataInputStream(in));
}
@@ -502,7 +500,7 @@
return false;
}
- /** {@inheritDoc} */
+ @Override
public int compareTo(Key another) {
return Integer.compare(uid, another.uid);
}
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index 290bd2c..57ad158 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -221,6 +221,11 @@
if (mLastSnapshot != null) {
mLastSnapshot = mLastSnapshot.withoutUid(uid);
}
+
+ final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+ if (complete != null) {
+ complete.removeUid(uid);
+ }
}
/**
@@ -235,22 +240,22 @@
mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
}
- /** {@inheritDoc} */
+ @Override
public void reset() {
// ignored
}
- /** {@inheritDoc} */
+ @Override
public void read(InputStream in) throws IOException {
mCollection.read(in);
}
- /** {@inheritDoc} */
+ @Override
public boolean shouldWrite() {
return true;
}
- /** {@inheritDoc} */
+ @Override
public void write(OutputStream out) throws IOException {
mCollection.write(new DataOutputStream(out));
mCollection.reset();
@@ -270,24 +275,24 @@
mUid = uid;
}
- /** {@inheritDoc} */
+ @Override
public void reset() {
mTemp.reset();
}
- /** {@inheritDoc} */
+ @Override
public void read(InputStream in) throws IOException {
mTemp.read(in);
mTemp.clearDirty();
mTemp.removeUid(mUid);
}
- /** {@inheritDoc} */
+ @Override
public boolean shouldWrite() {
return mTemp.isDirty();
}
- /** {@inheritDoc} */
+ @Override
public void write(OutputStream out) throws IOException {
mTemp.write(new DataOutputStream(out));
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index b847673..4382a03 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -70,6 +70,7 @@
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
import android.net.LinkProperties;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
@@ -412,40 +413,75 @@
}
@Override
- public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
- return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+ public INetworkStatsSession openSession() {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+
+ // return an IBinder which holds strong references to any loaded stats
+ // for its lifetime; when caller closes only weak references remain.
+
+ return new INetworkStatsSession.Stub() {
+ private NetworkStatsCollection mUidComplete;
+ private NetworkStatsCollection mUidTagComplete;
+
+ private NetworkStatsCollection getUidComplete() {
+ if (mUidComplete == null) {
+ mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
+ }
+ return mUidComplete;
+ }
+
+ private NetworkStatsCollection getUidTagComplete() {
+ if (mUidTagComplete == null) {
+ mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
+ }
+ return mUidTagComplete;
+ }
+
+ @Override
+ public NetworkStats getSummaryForNetwork(
+ NetworkTemplate template, long start, long end) {
+ return mDevStatsCached.getSummary(template, start, end);
+ }
+
+ @Override
+ public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
+ return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+ }
+
+ @Override
+ public NetworkStats getSummaryForAllUid(
+ NetworkTemplate template, long start, long end, boolean includeTags) {
+ final NetworkStats stats = getUidComplete().getSummary(template, start, end);
+ if (includeTags) {
+ final NetworkStats tagStats = getUidTagComplete()
+ .getSummary(template, start, end);
+ stats.combineAllValues(tagStats);
+ }
+ return stats;
+ }
+
+ @Override
+ public NetworkStatsHistory getHistoryForUid(
+ NetworkTemplate template, int uid, int set, int tag, int fields) {
+ if (tag == TAG_NONE) {
+ return getUidComplete().getHistory(template, uid, set, tag, fields);
+ } else {
+ return getUidTagComplete().getHistory(template, uid, set, tag, fields);
+ }
+ }
+
+ @Override
+ public void close() {
+ mUidComplete = null;
+ mUidTagComplete = null;
+ }
+ };
}
@Override
- public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
- return mDevStatsCached.getSummary(template, start, end);
- }
-
- @Override
- public NetworkStatsHistory getHistoryForUid(
- NetworkTemplate template, int uid, int set, int tag, int fields) {
- // TODO: transition to stats sessions to avoid WeakReferences
- if (tag == TAG_NONE) {
- return mUidRecorder.getOrLoadCompleteLocked().getHistory(
- template, uid, set, tag, fields);
- } else {
- return mUidTagRecorder.getOrLoadCompleteLocked().getHistory(
- template, uid, set, tag, fields);
- }
- }
-
- @Override
- public NetworkStats getSummaryForAllUid(
- NetworkTemplate template, long start, long end, boolean includeTags) {
- // TODO: transition to stats sessions to avoid WeakReferences
- final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary(
- template, start, end);
- if (includeTags) {
- final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary(
- template, start, end);
- stats.combineAllValues(tagStats);
- }
- return stats;
+ public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ return mDevStatsCached.getSummary(template, start, end).getTotalBytes();
}
@Override
@@ -464,6 +500,9 @@
Binder.restoreCallingIdentity(token);
}
+ // splice in operation counts
+ networkLayer.spliceOperationsFrom(mUidOperations);
+
final NetworkStats dataLayer = new NetworkStats(
networkLayer.getElapsedRealtime(), networkLayer.size());
@@ -474,8 +513,6 @@
dataLayer.combineValues(entry);
}
- // splice in operation counts
- dataLayer.spliceOperationsFrom(mUidOperations);
return dataLayer;
}
@@ -962,7 +999,7 @@
}
private Handler.Callback mHandlerCallback = new Handler.Callback() {
- /** {@inheritDoc} */
+ @Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERFORM_POLL: {
@@ -1001,7 +1038,7 @@
}
private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
- /** {@inheritDoc} */
+ @Override
public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
int rightIndex, String cookie) {
Log.w(TAG, "found non-monotonic values; saving to dropbox");
@@ -1020,7 +1057,8 @@
}
/**
- * Default external settings that read from {@link Settings.Secure}.
+ * Default external settings that read from
+ * {@link android.provider.Settings.Secure}.
*/
private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
private final ContentResolver mResolver;
@@ -1038,19 +1076,24 @@
return Settings.Secure.getInt(mResolver, name, defInt) != 0;
}
+ @Override
public long getPollInterval() {
return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
}
+ @Override
public long getTimeCacheMaxAge() {
return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
}
+ @Override
public long getGlobalAlertBytes() {
return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES);
}
+ @Override
public boolean getSampleEnabled() {
return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true);
}
+ @Override
public Config getDevConfig() {
return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES),
@@ -1058,6 +1101,7 @@
getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS));
}
+ @Override
public Config getUidConfig() {
return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
@@ -1065,6 +1109,7 @@
getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS));
}
+ @Override
public Config getUidTagConfig() {
return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 4bea5e40..1bd15f6 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -60,6 +60,7 @@
import java.util.List;
import java.util.HashMap;
import java.util.Map;
+import java.util.Scanner;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -81,6 +82,8 @@
"/sys/class/android_usb/android0/f_mass_storage/lun/file";
private static final String RNDIS_ETH_ADDR_PATH =
"/sys/class/android_usb/android0/f_rndis/ethaddr";
+ private static final String AUDIO_SOURCE_PCM_PATH =
+ "/sys/class/android_usb/android0/f_audio_source/pcm";
private static final int MSG_UPDATE_STATE = 0;
private static final int MSG_ENABLE_ADB = 1;
@@ -105,6 +108,7 @@
private final boolean mHasUsbAccessory;
private boolean mUseUsbNotification;
private boolean mAdbEnabled;
+ private boolean mAudioSourceEnabled;
private Map<String, List<Pair<String, String>>> mOemModeMap;
private class AdbSettingsObserver extends ContentObserver {
@@ -291,6 +295,8 @@
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+ mAudioSourceEnabled = containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_AUDIO_SOURCE);
// Upgrade step for previous versions that used persist.service.adb.enable
String value = SystemProperties.get("persist.service.adb.enable", "");
@@ -504,6 +510,28 @@
mContext.sendStickyBroadcast(intent);
}
+ private void updateAudioSourceFunction(boolean enabled) {
+ // send a sticky broadcast containing current USB state
+ Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra("state", (enabled ? 1 : 0));
+ if (enabled) {
+ try {
+ Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
+ int card = scanner.nextInt();
+ int device = scanner.nextInt();
+ intent.putExtra("card", card);
+ intent.putExtra("device", device);
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "could not open audio source PCM file", e);
+ }
+ }
+
+ mContext.sendStickyBroadcast(intent);
+ mAudioSourceEnabled = enabled;
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -523,6 +551,11 @@
}
if (mBootCompleted) {
updateUsbState();
+ boolean audioSourceEnabled = containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_AUDIO_SOURCE);
+ if (audioSourceEnabled != mAudioSourceEnabled) {
+ updateAudioSourceFunction(audioSourceEnabled);
+ }
}
break;
case MSG_ENABLE_ADB:
@@ -543,6 +576,7 @@
if (mCurrentAccessory != null) {
mSettingsManager.accessoryAttached(mCurrentAccessory);
}
+ updateAudioSourceFunction(mAudioSourceEnabled);
break;
}
}
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 6ba4c35..c3b5465d 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -224,7 +224,7 @@
hasTransformation = false;
- if (!animating) {
+ if (!animating && animation == null) {
return false;
}
@@ -259,6 +259,19 @@
return false;
}
+ boolean showAllWindowsLocked() {
+ boolean isAnimating = false;
+ final int NW = mAppToken.allAppWindows.size();
+ for (int i=0; i<NW; i++) {
+ WindowStateAnimator winAnimator = mAppToken.allAppWindows.get(i).mWinAnimator;
+ if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
+ "performing show on: " + winAnimator);
+ winAnimator.performShowLocked();
+ isAnimating |= winAnimator.isAnimating();
+ }
+ return isAnimating;
+ }
+
void dump(PrintWriter pw, String prefix) {
if (freezingScreen) {
pw.print(prefix); pw.print(" freezingScreen="); pw.println(freezingScreen);
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 1f8348d..bf35154 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -124,19 +124,6 @@
}
}
- boolean showAllWindowsLocked() {
- boolean isAnimating = false;
- final int NW = allAppWindows.size();
- for (int i=0; i<NW; i++) {
- WindowStateAnimator winAnimator = allAppWindows.get(i).mWinAnimator;
- if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
- "performing show on: " + winAnimator);
- winAnimator.performShowLocked();
- isAnimating |= winAnimator.isAnimating();
- }
- return isAnimating;
- }
-
void updateReportedVisibilityLocked() {
if (appToken == null) {
return;
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 405dd04..b08c864 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -41,14 +41,14 @@
DimAnimator (SurfaceSession session) {
if (mDimSurface == null) {
- if (WindowManagerService.SHOW_TRANSACTIONS ||
- WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
- " DIM " + mDimSurface + ": CREATE");
try {
mDimSurface = new Surface(session, 0,
"DimAnimator",
-1, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
+ if (WindowManagerService.SHOW_TRANSACTIONS ||
+ WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+ " DIM " + mDimSurface + ": CREATE");
mDimSurface.setAlpha(0.0f);
} catch (Exception e) {
Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index dc6cc0d..c1dbb36a 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -32,14 +32,14 @@
DimSurface(SurfaceSession session) {
if (mDimSurface == null) {
- if (WindowManagerService.SHOW_TRANSACTIONS ||
- WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
- " DIM " + mDimSurface + ": CREATE");
try {
mDimSurface = new Surface(session, 0,
"DimSurface",
-1, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
+ if (WindowManagerService.SHOW_TRANSACTIONS ||
+ WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+ " DIM " + mDimSurface + ": CREATE");
mDimSurface.setAlpha(0.0f);
} catch (Exception e) {
Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 9b196cc..0d64b68 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -22,6 +22,7 @@
import com.android.internal.policy.impl.PhoneWindowManager;
import java.io.PrintWriter;
+import java.util.HashSet;
/**
* Singleton class that carries out the animations and Surface operations in a separate task
@@ -34,6 +35,9 @@
final Context mContext;
final WindowManagerPolicy mPolicy;
+ HashSet<WindowStateAnimator> mWinAnimators = new HashSet<WindowStateAnimator>();
+ HashSet<WindowStateAnimator> mFinished = new HashSet<WindowStateAnimator>();
+
boolean mAnimating;
boolean mTokenMayBeDrawn;
boolean mForceHiding;
@@ -171,16 +175,16 @@
++mTransactionSequence;
for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
- WindowState w = mService.mWindows.get(i);
- WindowStateAnimator winAnimator = w.mWinAnimator;
- final WindowManager.LayoutParams attrs = w.mAttrs;
+ WindowState win = mService.mWindows.get(i);
+ WindowStateAnimator winAnimator = win.mWinAnimator;
+ final int flags = winAnimator.mAttrFlags;
if (winAnimator.mSurface != null) {
final boolean wasAnimating = winAnimator.mWasAnimating;
final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
if (WindowManagerService.DEBUG_WALLPAPER) {
- Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
+ Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +
", nowAnimating=" + nowAnimating);
}
@@ -189,16 +193,16 @@
// a detached wallpaper animation.
if (nowAnimating) {
if (winAnimator.mAnimation != null) {
- if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0
&& winAnimator.mAnimation.getDetachWallpaper()) {
- mDetachedWallpaper = w;
+ mDetachedWallpaper = win;
}
final int backgroundColor = winAnimator.mAnimation.getBackgroundColor();
if (backgroundColor != 0) {
if (mWindowAnimationBackground == null
|| (winAnimator.mAnimLayer <
mWindowAnimationBackground.mWinAnimator.mAnimLayer)) {
- mWindowAnimationBackground = w;
+ mWindowAnimationBackground = win;
mWindowAnimationBackgroundColor = backgroundColor;
}
}
@@ -210,25 +214,25 @@
// animation, make a note so we can ensure the wallpaper is
// displayed behind it.
final AppWindowAnimator appAnimator =
- w.mAppToken == null ? null : w.mAppToken.mAppAnimator;
+ win.mAppToken == null ? null : win.mAppToken.mAppAnimator;
if (appAnimator != null && appAnimator.animation != null
&& appAnimator.animating) {
- if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0
&& appAnimator.animation.getDetachWallpaper()) {
- mDetachedWallpaper = w;
+ mDetachedWallpaper = win;
}
final int backgroundColor = appAnimator.animation.getBackgroundColor();
if (backgroundColor != 0) {
if (mWindowAnimationBackground == null
|| (winAnimator.mAnimLayer <
mWindowAnimationBackground.mWinAnimator.mAnimLayer)) {
- mWindowAnimationBackground = w;
+ mWindowAnimationBackground = win;
mWindowAnimationBackgroundColor = backgroundColor;
}
}
}
- if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == w) {
+ if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -237,11 +241,11 @@
}
}
- if (mPolicy.doesForceHide(w, attrs)) {
+ if (mPolicy.doesForceHide(win, win.mAttrs)) {
if (!wasAnimating && nowAnimating) {
if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
"Animation started that could impact force hide: "
- + w);
+ + win);
mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -249,22 +253,22 @@
mPendingLayoutChanges);
}
mService.mFocusMayChange = true;
- } else if (w.isReadyForDisplay() && winAnimator.mAnimation == null) {
+ } else if (win.isReadyForDisplay() && winAnimator.mAnimation == null) {
mForceHiding = true;
}
- } else if (mPolicy.canBeForceHidden(w, attrs)) {
+ } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
final boolean changed;
if (mForceHiding) {
- changed = w.hideLw(false, false);
+ changed = win.hideLw(false, false);
if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
- "Now policy hidden: " + w);
+ "Now policy hidden: " + win);
} else {
- changed = w.showLw(false, false);
+ changed = win.showLw(false, false);
if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
- "Now policy shown: " + w);
+ "Now policy shown: " + win);
if (changed) {
if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
- && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
+ && win.isVisibleNow() /*w.isReadyForDisplay()*/) {
// Assume we will need to animate. If
// we don't (because the wallpaper will
// stay with the lock screen), then we will
@@ -274,7 +278,7 @@
winAnimator.setAnimation(a);
}
}
- if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) {
+ if (mCurrentFocus == null || mCurrentFocus.mLayer < win.mLayer) {
// We are showing on to of the current
// focus, so re-evaluate focus to make
// sure it is correct.
@@ -282,8 +286,7 @@
}
}
}
- if (changed && (attrs.flags
- & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+ if (changed && (flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -294,44 +297,43 @@
}
}
- final AppWindowToken atoken = w.mAppToken;
+ final AppWindowToken atoken = win.mAppToken;
if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
if (atoken.lastTransactionSequence != mTransactionSequence) {
atoken.lastTransactionSequence = mTransactionSequence;
atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
atoken.startingDisplayed = false;
}
- if ((w.isOnScreen() || w.mAttrs.type
+ if ((win.isOnScreen() || winAnimator.mAttrType
== WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
- && !w.mExiting && !w.mDestroying) {
+ && !win.mExiting && !win.mDestroying) {
if (WindowManagerService.DEBUG_VISIBILITY ||
WindowManagerService.DEBUG_ORIENTATION) {
- Slog.v(TAG, "Eval win " + w + ": isDrawn="
- + w.isDrawnLw()
+ Slog.v(TAG, "Eval win " + win + ": isDrawn=" + win.isDrawnLw()
+ ", isAnimating=" + winAnimator.isAnimating());
- if (!w.isDrawnLw()) {
+ if (!win.isDrawnLw()) {
Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
- + " pv=" + w.mPolicyVisibility
+ + " pv=" + win.mPolicyVisibility
+ " mDrawState=" + winAnimator.mDrawState
- + " ah=" + w.mAttachedHidden
+ + " ah=" + win.mAttachedHidden
+ " th=" + atoken.hiddenRequested
+ " a=" + winAnimator.mAnimating);
}
}
- if (w != atoken.startingWindow) {
- if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
+ if (win != atoken.startingWindow) {
+ if (!atoken.mAppAnimator.freezingScreen || !win.mAppFreezing) {
atoken.numInterestingWindows++;
- if (w.isDrawnLw()) {
+ if (win.isDrawnLw()) {
atoken.numDrawnWindows++;
if (WindowManagerService.DEBUG_VISIBILITY ||
WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
"tokenMayBeDrawn: " + atoken
+ " freezingScreen=" + atoken.mAppAnimator.freezingScreen
- + " mAppFreezing=" + w.mAppFreezing);
+ + " mAppFreezing=" + win.mAppFreezing);
mTokenMayBeDrawn = true;
}
}
- } else if (w.isDrawnLw()) {
+ } else if (win.isDrawnLw()) {
atoken.startingDisplayed = true;
}
}
@@ -371,7 +373,7 @@
"allDrawn: " + wtoken
+ " interesting=" + numInteresting
+ " drawn=" + wtoken.numDrawnWindows);
- wtoken.showAllWindowsLocked();
+ wtoken.mAppAnimator.showAllWindowsLocked();
mService.unsetAppFreezingScreenLocked(wtoken, false, true);
if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
"Setting mOrientationChangeComplete=true because wtoken "
@@ -394,7 +396,7 @@
// We can now show all of the drawn windows!
if (!mService.mOpeningApps.contains(wtoken)) {
- mAnimating |= wtoken.showAllWindowsLocked();
+ mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
}
}
}
@@ -435,14 +437,24 @@
mScreenRotationAnimation.updateSurfaces();
}
- for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
- WindowState w = mService.mWindows.get(i);
- w.mWinAnimator.prepareSurfaceLocked(true);
+ mFinished.clear();
+ for (final WindowStateAnimator winAnimator : mWinAnimators) {
+ if (winAnimator.mSurface == null) {
+ mFinished.add(winAnimator);
+ } else {
+ winAnimator.prepareSurfaceLocked(true);
+ }
+ }
+ for (final WindowStateAnimator winAnimator : mFinished) {
+ mWinAnimators.remove(winAnimator);
}
+ if (mDimParams != null) {
+ mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime);
+ }
if (mDimAnimator != null && mDimAnimator.mDimShown) {
- mAnimating |= mDimAnimator.updateSurface(mService.mInnerFields.mDimming,
- mCurrentTime, !mService.okToDisplay());
+ mAnimating |= mDimAnimator.updateSurface(mDimParams != null, mCurrentTime,
+ !mService.okToDisplay());
}
if (mService.mBlackFrame != null) {
@@ -453,10 +465,6 @@
mService.mBlackFrame.clearMatrix();
}
}
-
- if (mDimParams != null) {
- mDimAnimator.updateParameters(mContext.getResources(), mDimParams, mCurrentTime);
- }
} catch (RuntimeException e) {
Log.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
@@ -510,4 +518,18 @@
pw.println( " no DimAnimator ");
}
}
+
+ static class SetAnimationParams {
+ final WindowStateAnimator mWinAnimator;
+ final Animation mAnimation;
+ final int mAnimDw;
+ final int mAnimDh;
+ public SetAnimationParams(final WindowStateAnimator winAnimator,
+ final Animation animation, final int animDw, final int animDh) {
+ mWinAnimator = winAnimator;
+ mAnimation = animation;
+ mAnimDw = animDw;
+ mAnimDh = animDh;
+ }
+ }
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3d6c9f0..a7af8fb 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -245,10 +245,6 @@
*/
static final boolean CUSTOM_SCREEN_ROTATION = true;
- // Maximum number of milliseconds to wait for input event injection.
- // FIXME is this value reasonable?
- private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
-
// Maximum number of milliseconds to wait for input devices to be enumerated before
// proceding with safe mode detection.
private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000;
@@ -355,32 +351,7 @@
* controlling the ordering of windows in different applications. This
* contains AppWindowToken objects.
*/
- final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>() {
- @Override
- public void add(int index, AppWindowToken object) {
- synchronized (mAnimator) {
- super.add(index, object);
- }
- };
- @Override
- public boolean add(AppWindowToken object) {
- synchronized (mAnimator) {
- return super.add(object);
- }
- };
- @Override
- public AppWindowToken remove(int index) {
- synchronized (mAnimator) {
- return super.remove(index);
- }
- };
- @Override
- public boolean remove(Object object) {
- synchronized (mAnimator) {
- return super.remove(object);
- }
- };
- };
+ final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
/**
* Application tokens that are in the process of exiting, but still
@@ -397,32 +368,7 @@
/**
* Z-ordered (bottom-most first) list of all Window objects.
*/
- final ArrayList<WindowState> mWindows = new ArrayList<WindowState>() {
- @Override
- public void add(int index, WindowState object) {
- synchronized (mAnimator) {
- super.add(index, object);
- }
- };
- @Override
- public boolean add(WindowState object) {
- synchronized (mAnimator) {
- return super.add(object);
- }
- };
- @Override
- public WindowState remove(int index) {
- synchronized (mAnimator) {
- return super.remove(index);
- }
- };
- @Override
- public boolean remove(Object object) {
- synchronized (mAnimator) {
- return super.remove(object);
- }
- };
- };
+ final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();
/**
* Fake windows added to the window manager. Note: ordered from top to
@@ -4855,95 +4801,26 @@
mAnimatorDurationScale };
}
- public int getSwitchState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getSwitchState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
+ // Called by window manager policy. Not exposed externally.
+ @Override
+ public int getLidState() {
+ final int SW_LID = 0x00;
+ int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LID);
+ if (sw > 0) {
+ // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL.
+ return LID_CLOSED;
+ } else if (sw == 0) {
+ // Switch state: AKEY_STATE_UP.
+ return LID_OPEN;
+ } else {
+ // Switch state: AKEY_STATE_UNKNOWN.
+ return LID_ABSENT;
}
- return mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, sw);
}
- public int getSwitchStateForDevice(int devid, int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getSwitchStateForDevice()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getSwitchState(devid, InputDevice.SOURCE_ANY, sw);
- }
-
- public int getScancodeState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getScancodeState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_ANY, sw);
- }
-
- public int getScancodeStateForDevice(int devid, int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getScancodeStateForDevice()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getScanCodeState(devid, InputDevice.SOURCE_ANY, sw);
- }
-
- public int getTrackballScancodeState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getTrackballScancodeState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL, sw);
- }
-
- public int getDPadScancodeState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getDPadScancodeState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getScanCodeState(-1, InputDevice.SOURCE_DPAD, sw);
- }
-
- public int getKeycodeState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getKeycodeState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, sw);
- }
-
- public int getKeycodeStateForDevice(int devid, int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getKeycodeStateForDevice()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getKeyCodeState(devid, InputDevice.SOURCE_ANY, sw);
- }
-
- public int getTrackballKeycodeState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getTrackballKeycodeState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_TRACKBALL, sw);
- }
-
- public int getDPadKeycodeState(int sw) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "getDPadKeycodeState()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
- return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, sw);
- }
-
- public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
- return mInputManager.hasKeys(-1, InputDevice.SOURCE_ANY, keycodes, keyExists);
- }
-
+ // Called by window manager policy. Not exposed externally.
+ @Override
public InputChannel monitorInput(String inputChannelName) {
- if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
- "monitorInput()")) {
- throw new SecurityException("Requires READ_INPUT_STATE permission");
- }
return mInputManager.monitorInput(inputChannelName);
}
@@ -4951,14 +4828,6 @@
mInputManager.setInputFilter(filter);
}
- public InputDevice getInputDevice(int deviceId) {
- return mInputManager.getInputDevice(deviceId);
- }
-
- public int[] getInputDeviceIds() {
- return mInputManager.getInputDeviceIds();
- }
-
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) {
@@ -6444,164 +6313,6 @@
sendScreenStatusToClients();
}
- /**
- * Injects a keystroke event into the UI.
- * Even when sync is false, this method may block while waiting for current
- * input events to be dispatched.
- *
- * @param ev A motion event describing the keystroke action. (Be sure to use
- * {@link SystemClock#uptimeMillis()} as the timebase.)
- * @param sync If true, wait for the event to be completed before returning to the caller.
- * @return Returns true if event was dispatched, false if it was dropped for any reason
- */
- public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
- long downTime = ev.getDownTime();
- long eventTime = ev.getEventTime();
-
- int action = ev.getAction();
- int code = ev.getKeyCode();
- int repeatCount = ev.getRepeatCount();
- int metaState = ev.getMetaState();
- int deviceId = ev.getDeviceId();
- int scancode = ev.getScanCode();
- int source = ev.getSource();
- int flags = ev.getFlags();
-
- if (source == InputDevice.SOURCE_UNKNOWN) {
- source = InputDevice.SOURCE_KEYBOARD;
- }
-
- if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
- if (downTime == 0) downTime = eventTime;
-
- KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
- deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long ident = Binder.clearCallingIdentity();
-
- final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
- sync ? InputManagerService.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
- : InputManagerService.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
- INJECTION_TIMEOUT_MILLIS);
-
- Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result, pid);
- }
-
- /**
- * Inject a pointer (touch) event into the UI.
- * Even when sync is false, this method may block while waiting for current
- * input events to be dispatched.
- *
- * @param ev A motion event describing the pointer (touch) action. (As noted in
- * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
- * {@link SystemClock#uptimeMillis()} as the timebase.)
- * @param sync If true, wait for the event to be completed before returning to the caller.
- * @return Returns true if event was dispatched, false if it was dropped for any reason
- */
- public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long ident = Binder.clearCallingIdentity();
-
- MotionEvent newEvent = MotionEvent.obtain(ev);
- if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
- newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- }
-
- final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
- sync ? InputManagerService.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
- : InputManagerService.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
- INJECTION_TIMEOUT_MILLIS);
-
- Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result, pid);
- }
-
- /**
- * Inject a trackball (navigation device) event into the UI.
- * Even when sync is false, this method may block while waiting for current
- * input events to be dispatched.
- *
- * @param ev A motion event describing the trackball action. (As noted in
- * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
- * {@link SystemClock#uptimeMillis()} as the timebase.)
- * @param sync If true, wait for the event to be completed before returning to the caller.
- * @return Returns true if event was dispatched, false if it was dropped for any reason
- */
- public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long ident = Binder.clearCallingIdentity();
-
- MotionEvent newEvent = MotionEvent.obtain(ev);
- if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
- newEvent.setSource(InputDevice.SOURCE_TRACKBALL);
- }
-
- final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
- sync ? InputManagerService.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
- : InputManagerService.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
- INJECTION_TIMEOUT_MILLIS);
-
- Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result, pid);
- }
-
- /**
- * Inject an input event into the UI without waiting for dispatch to commence.
- * This variant is useful for fire-and-forget input event injection. It does not
- * block any longer than it takes to enqueue the input event.
- *
- * @param ev An input event. (Be sure to set the input source correctly.)
- * @return Returns true if event was dispatched, false if it was dropped for any reason
- */
- public boolean injectInputEventNoWait(InputEvent ev) {
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long ident = Binder.clearCallingIdentity();
-
- final int result = mInputManager.injectInputEvent(ev, pid, uid,
- InputManagerService.INPUT_EVENT_INJECTION_SYNC_NONE,
- INJECTION_TIMEOUT_MILLIS);
-
- Binder.restoreCallingIdentity(ident);
- return reportInjectionResult(result, pid);
- }
-
- private boolean reportInjectionResult(int result, int pid) {
- switch (result) {
- case InputManagerService.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
- Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
- throw new SecurityException(
- "Injecting to another application requires INJECT_EVENTS permission");
- case InputManagerService.INPUT_EVENT_INJECTION_SUCCEEDED:
- return true;
- case InputManagerService.INPUT_EVENT_INJECTION_TIMED_OUT:
- Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
- return false;
- case InputManagerService.INPUT_EVENT_INJECTION_FAILED:
- default:
- Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
- return false;
- }
- }
-
- /**
- * Temporarily set the pointer speed. Does not save the new setting.
- * Used by the settings application.
- */
- public void setPointerSpeed(int speed) {
- if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
- "setPointerSpeed()")) {
- throw new SecurityException("Requires SET_POINTER_SPEED permission");
- }
-
- mInputManager.setPointerSpeed(speed);
- }
-
private WindowState getFocusedWindow() {
synchronized (mWindowMap) {
return getFocusedWindowLocked();
@@ -6616,11 +6327,29 @@
if (!mInputMonitor.waitForInputDevicesReady(
INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
Slog.w(TAG, "Devices still not ready after waiting "
- + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
- + " milliseconds before attempting to detect safe mode.");
+ + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
+ + " milliseconds before attempting to detect safe mode.");
}
- mSafeMode = mPolicy.detectSafeMode();
+ final int BTN_MOUSE = 0x110;
+ int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
+ KeyEvent.KEYCODE_MENU);
+ int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
+ int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
+ KeyEvent.KEYCODE_DPAD_CENTER);
+ int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
+ BTN_MOUSE);
+ int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
+ KeyEvent.KEYCODE_VOLUME_DOWN);
+ mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
+ || volumeDownState > 0;
+ if (mSafeMode) {
+ Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
+ + " dpad=" + dpadState + " trackball=" + trackballState + ")");
+ } else {
+ Log.i(TAG, "SAFE MODE not enabled");
+ }
+ mPolicy.setSafeMode(mSafeMode);
return mSafeMode;
}
@@ -6724,6 +6453,7 @@
public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2;
public static final int SET_DIM_PARAMETERS = ANIMATOR_WHAT_OFFSET + 3;
+ public static final int SET_MOVE_ANIMATION = ANIMATOR_WHAT_OFFSET + 4;
private Session mLastReportedHold;
@@ -7162,33 +6892,37 @@
// Animation messages. Move to Window{State}Animator
case SET_TRANSPARENT_REGION: {
- // TODO(cmautner): Remove sync.
- synchronized (mAnimator) {
- Pair<WindowStateAnimator, Region> pair =
+ Pair<WindowStateAnimator, Region> pair =
(Pair<WindowStateAnimator, Region>) msg.obj;
- final WindowStateAnimator winAnimator = pair.first;
- winAnimator.setTransparentRegionHint(pair.second);
- }
+ final WindowStateAnimator winAnimator = pair.first;
+ winAnimator.setTransparentRegionHint(pair.second);
scheduleAnimationLocked();
break;
}
case SET_WALLPAPER_OFFSET: {
- // TODO(cmautner): Remove sync.
- synchronized (mAnimator) {
- final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
- winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
- }
+ final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
+ winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
scheduleAnimationLocked();
break;
}
case SET_DIM_PARAMETERS: {
- synchronized (mAnimator) {
- mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
- }
+ mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
+
+ scheduleAnimationLocked();
+ break;
+ }
+
+ case SET_MOVE_ANIMATION: {
+ WindowAnimator.SetAnimationParams params =
+ (WindowAnimator.SetAnimationParams) msg.obj;
+ WindowStateAnimator winAnimator = params.mWinAnimator;
+ winAnimator.setAnimation(params.mAnimation);
+ winAnimator.mAnimDw = params.mAnimDw;
+ winAnimator.mAnimDh = params.mAnimDh;
scheduleAnimationLocked();
break;
@@ -7972,20 +7706,19 @@
AppWindowToken topOpeningApp = null;
int topOpeningLayer = 0;
+ // TODO(cmautner): Move to animation side.
NN = mOpeningApps.size();
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mOpeningApps.get(i);
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Now opening app" + wtoken);
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
wtoken.mAppAnimator.clearThumbnail();
wtoken.reportedVisible = false;
wtoken.inPendingTransaction = false;
wtoken.mAppAnimator.animation = null;
- setTokenVisibilityLocked(wtoken, animLp, true,
- transit, false);
+ setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
- mAnimator.mAnimating |= wtoken.showAllWindowsLocked();
+ mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
if (animLp != null) {
int layer = -1;
for (int j=0; j<wtoken.windows.size(); j++) {
@@ -8406,8 +8139,6 @@
final int N = mWindows.size();
for (i=N-1; i>=0; i--) {
WindowState w = mWindows.get(i);
- //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
- w.mContentChanged = false;
if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
focusDisplayed = true;
@@ -8428,7 +8159,7 @@
updateWallpaperVisibilityLocked();
}
}
- if (!mInnerFields.mDimming) {
+ if (!mInnerFields.mDimming && mAnimator.mDimParams != null) {
mAnimator.stopDimming();
}
} catch (RuntimeException e) {
@@ -8509,6 +8240,27 @@
for (i=N-1; i>=0; i--) {
final WindowState w = mWindows.get(i);
final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+ // If the window has moved due to its containing
+ // content frame changing, then we'd like to animate
+ // it.
+ if (w.mHasSurface && w.shouldAnimateMove()) {
+ // Frame has moved, containing content frame
+ // has also moved, and we're not currently animating...
+ // let's do something.
+ Animation a = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.window_move_from_decor);
+ winAnimator.setAnimation(a);
+ winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
+ winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+ } else {
+ winAnimator.mAnimDw = innerDw;
+ winAnimator.mAnimDh = innerDh;
+ }
+
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+ w.mContentChanged = false;
+
// TODO(cmautner): Can this move up to the loop at the end of try/catch above?
updateResizingWindows(w);
@@ -8528,24 +8280,6 @@
}
}
}
-
- // If the window has moved due to its containing
- // content frame changing, then we'd like to animate
- // it. The checks here are ordered by what is least
- // likely to be true first.
- if (w.shouldAnimateMove()) {
- // Frame has moved, containing content frame
- // has also moved, and we're not currently animating...
- // let's do something.
- Animation a = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.window_move_from_decor);
- winAnimator.setAnimation(a);
- winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
- winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
- } else {
- winAnimator.mAnimDw = innerDw;
- winAnimator.mAnimDh = innerDh;
- }
}
}
@@ -8843,6 +8577,7 @@
wsa.mSurfaceShown = false;
wsa.mSurface = null;
ws.mHasSurface = false;
+ mAnimator.mWinAnimators.remove(wsa);
mForceRemoves.add(ws);
i--;
N--;
@@ -8856,6 +8591,7 @@
wsa.mSurfaceShown = false;
wsa.mSurface = null;
ws.mHasSurface = false;
+ mAnimator.mWinAnimators.remove(wsa);
leakedSurface = true;
}
}
@@ -8895,6 +8631,7 @@
winAnimator.mSurfaceShown = false;
winAnimator.mSurface = null;
winAnimator.mWin.mHasSurface = false;
+ mAnimator.mWinAnimators.remove(winAnimator);
}
try {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 6d0921e..220f5e0 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -121,6 +121,9 @@
/** Was this window last hidden? */
boolean mLastHidden;
+ int mAttrFlags;
+ int mAttrType;
+
public WindowStateAnimator(final WindowManagerService service, final WindowState win,
final WindowState attachedWindow) {
mService = service;
@@ -130,11 +133,12 @@
mSession = win.mSession;
mPolicy = mService.mPolicy;
mContext = mService.mContext;
+ mAttrFlags = win.mAttrs.flags;
+ mAttrType = win.mAttrs.type;
}
public void setAnimation(Animation anim) {
- if (localLOGV) Slog.v(
- TAG, "Setting animation in " + this + ": " + anim);
+ if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
mLocalAnimating = false;
mAnimation = anim;
@@ -453,6 +457,7 @@
attrs.getTitle().toString(),
0, w, h, format, flags);
mWin.mHasSurface = true;
+ mAnimator.mWinAnimators.add(this);
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
" CREATE SURFACE "
+ mSurface + " IN SESSION "
@@ -463,12 +468,14 @@
+ " / " + this);
} catch (Surface.OutOfResourcesException e) {
mWin.mHasSurface = false;
+ mAnimator.mWinAnimators.remove(this);
Slog.w(TAG, "OutOfResourcesException creating surface");
mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
mDrawState = NO_SURFACE;
return null;
} catch (Exception e) {
mWin.mHasSurface = false;
+ mAnimator.mWinAnimators.remove(this);
Slog.e(TAG, "Exception creating surface", e);
mDrawState = NO_SURFACE;
return null;
@@ -586,6 +593,7 @@
mSurfaceShown = false;
mSurface = null;
mWin.mHasSurface =false;
+ mAnimator.mWinAnimators.remove(this);
}
}
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 22795bf..c137a78 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -95,6 +95,7 @@
jfieldID mId;
jfieldID mName;
+ jfieldID mDescriptor;
jfieldID mSources;
jfieldID mKeyboardType;
jfieldID mKeyCharacterMapFile;
@@ -509,8 +510,9 @@
switch (switchCode) {
case SW_LID:
+ // When switch value is set indicates lid is closed.
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyLidSwitchChanged,
- when, switchValue == 0);
+ when, switchValue == 0 /*lidOpen*/);
checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
break;
}
@@ -949,8 +951,9 @@
static jint nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
- sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
- NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, looper);
+ sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
+ NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
+ messageQueue->getLooper());
im->incStrong(serviceObj);
return reinterpret_cast<jint>(im);
}
@@ -1169,12 +1172,17 @@
}
jobject deviceObj = env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor);
- if (! deviceObj) {
+ if (!deviceObj) {
return NULL;
}
jstring deviceNameObj = env->NewStringUTF(deviceInfo.getName().string());
- if (! deviceNameObj) {
+ if (!deviceNameObj) {
+ return NULL;
+ }
+
+ jstring deviceDescriptorObj = env->NewStringUTF(deviceInfo.getDescriptor().string());
+ if (!deviceDescriptorObj) {
return NULL;
}
@@ -1185,6 +1193,7 @@
env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId());
env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj);
+ env->SetObjectField(deviceObj, gInputDeviceClassInfo.mDescriptor, deviceDescriptorObj);
env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
env->SetObjectField(deviceObj, gInputDeviceClassInfo.mKeyCharacterMapFile, fileStr);
@@ -1445,6 +1454,9 @@
GET_FIELD_ID(gInputDeviceClassInfo.mName, gInputDeviceClassInfo.clazz,
"mName", "Ljava/lang/String;");
+ GET_FIELD_ID(gInputDeviceClassInfo.mDescriptor, gInputDeviceClassInfo.clazz,
+ "mDescriptor", "Ljava/lang/String;");
+
GET_FIELD_ID(gInputDeviceClassInfo.mSources, gInputDeviceClassInfo.clazz,
"mSources", "I");
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 1773e33..ba3fd3c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -70,7 +70,6 @@
import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.os.MessageQueue.IdleHandler;
-import android.os.SystemClock;
import android.os.UserId;
import android.test.AndroidTestCase;
import android.test.mock.MockPackageManager;
@@ -628,8 +627,8 @@
// pretend that 512 bytes total have happened
stats = new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, true);
// TODO: consider making strongly ordered mock
@@ -699,8 +698,8 @@
{
expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, true);
expectClearNotifications();
@@ -722,8 +721,8 @@
{
expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, true);
expectRemoveInterfaceQuota(TEST_IFACE);
@@ -745,8 +744,8 @@
{
expectCurrentTime();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, true);
expectForceUpdate();
@@ -766,8 +765,8 @@
{
expectCurrentTime();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, false);
expectForceUpdate();
@@ -786,8 +785,8 @@
{
expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, true);
// snoozed interface still has high quota so background data is
@@ -827,8 +826,8 @@
{
expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
- .andReturn(stats).atLeastOnce();
+ expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats.getTotalBytes()).atLeastOnce();
expectPolicyDataEnable(TYPE_WIFI, true);
expectRemoveInterfaceQuota(TEST_IFACE);
@@ -982,7 +981,7 @@
}
}
- /** {@inheritDoc} */
+ @Override
public boolean queueIdle() {
set(null);
return false;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 103d8e1..6d9bb29 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -54,6 +54,7 @@
import android.content.Intent;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
+import android.net.INetworkStatsSession;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -84,7 +85,7 @@
*/
@LargeTest
public class NetworkStatsServiceTest extends AndroidTestCase {
- private static final String TAG = "NetworkStatsServiceTest";
+ private static final String TAG = "NetworkStatsServiceTest";
private static final String TEST_IFACE = "test0";
private static final String TEST_IFACE2 = "test1";
@@ -113,6 +114,7 @@
private IConnectivityManager mConnManager;
private NetworkStatsService mService;
+ private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
@Override
@@ -134,6 +136,7 @@
mService = new NetworkStatsService(
mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings);
mService.bindConnectivityManager(mConnManager);
+ mSession = mService.openSession();
mElapsedRealtime = 0L;
@@ -172,6 +175,7 @@
mSettings = null;
mConnManager = null;
+ mSession.close();
mService = null;
super.tearDown();
@@ -349,7 +353,7 @@
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// verify service recorded history
- history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
+ history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
assertEquals(2, history.size());
@@ -367,7 +371,7 @@
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// verify identical stats, but spread across 4 buckets now
- history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
+ history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
assertEquals(4, history.size());
@@ -652,7 +656,7 @@
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// first verify entire history present
- NetworkStats stats = mService.getSummaryForAllUid(
+ NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(3, stats.size());
assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 1);
@@ -661,7 +665,7 @@
// now verify that recent history only contains one uid
final long currentTime = currentTimeMillis();
- stats = mService.getSummaryForAllUid(
+ stats = mSession.getSummaryForAllUid(
sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
assertEquals(1, stats.size());
assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0);
@@ -723,7 +727,7 @@
assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
// verify entire history present
- final NetworkStats stats = mService.getSummaryForAllUid(
+ final NetworkStats stats = mSession.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
assertEquals(4, stats.size());
assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 1);
@@ -775,20 +779,20 @@
}
private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) {
- final NetworkStatsHistory history = mService.getHistoryForNetwork(template, FIELD_ALL);
+ long txBytes, long txPackets, int operations) throws Exception {
+ final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
txPackets, operations);
}
private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) {
+ long txBytes, long txPackets, int operations) throws Exception {
assertUidTotal(template, uid, SET_ALL, rxBytes, rxPackets, txBytes, txPackets, operations);
}
private void assertUidTotal(NetworkTemplate template, int uid, int set, long rxBytes,
- long rxPackets, long txBytes, long txPackets, int operations) {
- final NetworkStatsHistory history = mService.getHistoryForUid(
+ long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
+ final NetworkStatsHistory history = mSession.getHistoryForUid(
template, uid, set, TAG_NONE, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
txPackets, operations);
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 2139917..92024cd 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -580,7 +580,9 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));
}
- if (oldState != State.READY && newState == State.READY) {
+ // Call onReady only when SIM or RUIM card becomes ready (not NV)
+ if (oldState != State.READY && newState == State.READY &&
+ (is3gpp || isSubscriptionFromIccCard)) {
mIccFileHandler.setAid(getAid());
mIccRecords.onReady();
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index ed0081b..9f6ec71 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -205,6 +205,8 @@
// Sets operator numeric property by retrieving from build-time system property
String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
+ log("CDMAPhone: init set 'gsm.sim.operator.numeric' to operator='" +
+ operatorNumeric + "'");
setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
// Sets iso country property by retrieving from build-time system property
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 3855515..2fefa3f 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -329,11 +329,11 @@
@Override
protected void onAllRecordsLoaded() {
- log("RuimRecords: record load complete");
-
// Further records that can be inserted are Operator/OEM dependent
String operator = getRUIMOperatorNumeric();
+ log("RuimRecords: onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
+ operator + "'");
SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
if (mImsi != null) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index b88af2c..80988fd 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -228,6 +228,7 @@
adnCache.reset();
+ log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null");
SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, null);
SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, null);
SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
@@ -1254,12 +1255,12 @@
}
protected void onAllRecordsLoaded() {
- log("record load complete");
-
String operator = getOperatorNumeric();
// Some fields require more than one SIM record to set
+ log("SIMRecords: onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
+ operator + "'");
SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
if (imsi != null) {
diff --git a/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
index b7e80d4..919e2b3 100644
--- a/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
+++ b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
@@ -17,15 +17,16 @@
import android.content.Context;
import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.NetworkTemplate;
-import android.net.NetworkStats;
+import android.net.TrafficStats;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.TelephonyManager;
import android.test.InstrumentationTestCase;
-import android.test.InstrumentationTestRunner;
import android.util.Log;
/**
@@ -71,13 +72,17 @@
* @param template {link {@link NetworkTemplate} to match.
*/
private void fetchStats(NetworkTemplate template) {
+ INetworkStatsSession session = null;
try {
mStatsService.forceUpdate();
- NetworkStats stats = mStatsService.getSummaryForAllUid(template, Long.MIN_VALUE,
- Long.MAX_VALUE, false);
+ session = mStatsService.openSession();
+ final NetworkStats stats = session.getSummaryForAllUid(
+ template, Long.MIN_VALUE, Long.MAX_VALUE, false);
reportStats(stats);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Failed to fetch network stats.");
+ } finally {
+ TrafficStats.closeQuietly(session);
}
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 58f65be..1f6279c 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -255,41 +255,6 @@
}
@SmallTest
- public void testINJECT_EVENTS() {
- try {
- mWm.injectKeyEvent(new KeyEvent(0, 0), false);
- fail("IWindowManager.injectKeyEvent did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.injectPointerEvent(MotionEvent.obtain(0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0), false);
- fail("IWindowManager.injectPointerEvent did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.injectTrackballEvent(MotionEvent.obtain(0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0), false);
- fail("IWindowManager.injectTrackballEvent did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
- }
-
- @SmallTest
public void testDISABLE_KEYGUARD() {
Binder token = new Binder();
try {
@@ -347,73 +312,9 @@
}
@SmallTest
- public void testREAD_INPUT_STATE() {
- try {
- mWm.getSwitchState(0);
- fail("IWindowManager.getSwitchState did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.getSwitchStateForDevice(0, 0);
- fail("IWindowManager.getSwitchStateForDevice did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.getScancodeState(0);
- fail("IWindowManager.getScancodeState did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.getScancodeStateForDevice(0, 0);
- fail("IWindowManager.getScancodeStateForDevice did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.getKeycodeState(0);
- fail("IWindowManager.getKeycodeState did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.getKeycodeStateForDevice(0, 0);
- fail("IWindowManager.getKeycodeStateForDevice did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
- }
-
- @SmallTest
public void testSET_ORIENTATION() {
try {
mWm.updateRotation(true, false);
- mWm.getSwitchState(0);
fail("IWindowManager.updateRotation did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -424,7 +325,6 @@
try {
mWm.freezeRotation(-1);
- mWm.getSwitchState(0);
fail("IWindowManager.freezeRotation did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -435,7 +335,6 @@
try {
mWm.thawRotation();
- mWm.getSwitchState(0);
fail("IWindowManager.thawRotation did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 198fce4..689aa8e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -639,6 +639,12 @@
// If an app requests write storage, they will also get read storage.
bool hasReadExternalStoragePermission = false;
+ // Implement transition to read and write call log.
+ bool hasReadContactsPermission = false;
+ bool hasWriteContactsPermission = false;
+ bool hasReadCallLogPermission = false;
+ bool hasWriteCallLogPermission = false;
+
// This next group of variables is used to implement a group of
// backward-compatibility heuristics necessitated by the addition of
// some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -1006,6 +1012,14 @@
hasReadExternalStoragePermission = true;
} else if (name == "android.permission.READ_PHONE_STATE") {
hasReadPhoneStatePermission = true;
+ } else if (name == "android.permission.READ_CONTACTS") {
+ hasReadContactsPermission = true;
+ } else if (name == "android.permission.WRITE_CONTACTS") {
+ hasWriteContactsPermission = true;
+ } else if (name == "android.permission.READ_CALL_LOG") {
+ hasReadCallLogPermission = true;
+ } else if (name == "android.permission.WRITE_CALL_LOG") {
+ hasWriteCallLogPermission = true;
}
printf("uses-permission:'%s'\n", name.string());
} else {
@@ -1181,6 +1195,16 @@
printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
}
+ // Pre-JellyBean call log permission compatibility.
+ if (targetSdk < 16) {
+ if (!hasReadCallLogPermission && hasReadContactsPermission) {
+ printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
+ }
+ if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
+ printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
+ }
+ }
+
/* The following blocks handle printing "inferred" uses-features, based
* on whether related features or permissions are used by the app.
* Note that the various spec*Feature variables denote whether the
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 0755670..e6c9351 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -161,92 +161,11 @@
}
@Override
- public int getDPadKeycodeState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getDPadScancodeState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
-
- @Override
- public InputDevice getInputDevice(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int[] getInputDeviceIds() throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public int getKeycodeState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getKeycodeStateForDevice(int arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
-
- @Override
public int getPendingAppTransition() throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
-
- @Override
- public int getScancodeState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getScancodeStateForDevice(int arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getSwitchState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getSwitchStateForDevice(int arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getTrackballKeycodeState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public int getTrackballScancodeState(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public boolean hasKeys(int[] arg0, boolean[] arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
@Override
public boolean inKeyguardRestrictedInputMode() throws RemoteException {
// TODO Auto-generated method stub
@@ -254,30 +173,6 @@
}
@Override
- public boolean injectInputEventNoWait(InputEvent arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean injectKeyEvent(KeyEvent arg0, boolean arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean injectPointerEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean injectTrackballEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
public boolean inputMethodClientHasFocus(IInputMethodClient arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
@@ -302,12 +197,6 @@
}
@Override
- public InputChannel monitorInput(String arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
// TODO Auto-generated method stub
@@ -462,12 +351,6 @@
}
@Override
- public void setPointerSpeed(int arg0) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
public void updateRotation(boolean arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index c11d082..db73ea8 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -396,11 +396,25 @@
}
}
+ public boolean startWpsPbc(String iface, String bssid) {
+ if (TextUtils.isEmpty(bssid)) {
+ return doBooleanCommand("WPS_PBC interface=" + iface);
+ } else {
+ return doBooleanCommand("WPS_PBC interface=" + iface + " " + bssid);
+ }
+ }
+
public boolean startWpsPinKeypad(String pin) {
if (TextUtils.isEmpty(pin)) return false;
return doBooleanCommand("WPS_PIN any " + pin);
}
+ public boolean startWpsPinKeypad(String iface, String pin) {
+ if (TextUtils.isEmpty(pin)) return false;
+ return doBooleanCommand("WPS_PIN interface=" + iface + " any " + pin);
+ }
+
+
public String startWpsPinDisplay(String bssid) {
if (TextUtils.isEmpty(bssid)) {
return doStringCommand("WPS_PIN any");
@@ -409,6 +423,14 @@
}
}
+ public String startWpsPinDisplay(String iface, String bssid) {
+ if (TextUtils.isEmpty(bssid)) {
+ return doStringCommand("WPS_PIN interface=" + iface + " any");
+ } else {
+ return doStringCommand("WPS_PIN interface=" + iface + " " + bssid);
+ }
+ }
+
/* Configures an access point connection */
public boolean startWpsRegistrar(String bssid, String pin) {
if (TextUtils.isEmpty(bssid) || TextUtils.isEmpty(pin)) return false;
@@ -440,6 +462,26 @@
return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
}
+ public boolean setP2pGroupIdle(String iface, int time) {
+ return doBooleanCommand("SET interface=" + iface + " p2p_group_idle " + time);
+ }
+
+ public boolean setP2pPowerSave(String iface, boolean enabled) {
+ if (enabled) {
+ return doBooleanCommand("P2P_SET interface=" + iface + " ps 1");
+ } else {
+ return doBooleanCommand("P2P_SET interface=" + iface + " ps 0");
+ }
+ }
+
+ /**
+ * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
+ * P2P connection over STA
+ */
+ public boolean setConcurrencyPriority(String s) {
+ return doBooleanCommand("P2P_SET conc_priority " + s);
+ }
+
public boolean p2pFind() {
return doBooleanCommand("P2P_FIND");
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 3d3a746..32e1053 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -109,6 +109,9 @@
/* Set a two minute discover timeout to avoid STA scans from being blocked */
private static final int DISCOVER_TIMEOUT_S = 120;
+ /* Idle time after a peer is gone when the group is torn down */
+ private static final int GROUP_IDLE_TIME_S = 2;
+
/**
* Delay between restarts upon failure to setup connection with supplicant
*/
@@ -343,10 +346,21 @@
case WifiMonitor.NETWORK_CONNECTION_EVENT:
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
+ case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
case PEER_CONNECTION_USER_ACCEPT:
case PEER_CONNECTION_USER_REJECT:
case GROUP_CREATING_TIMED_OUT:
break;
+ /* unexpected group created, remove */
+ case WifiMonitor.P2P_GROUP_STARTED_EVENT:
+ mGroup = (WifiP2pGroup) message.obj;
+ loge("Unexpected group creation, remove " + mGroup);
+ mWifiNative.p2pGroupRemove(mGroup.getInterface());
+ break;
+ case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
+ loge("Unexpected group failure, flush peers");
+ mWifiNative.p2pFlush();
+ break;
default:
loge("Unhandled message " + message);
return NOT_HANDLED;
@@ -476,6 +490,7 @@
if (DBG) logd(getName());
sendP2pStateChangedBroadcast(true);
mNetworkInfo.setIsAvailable(true);
+ sendP2pConnectionChangedBroadcast();
initializeP2pSettings();
}
@@ -561,9 +576,11 @@
//If peer is a GO, we do not need to send provisional discovery,
//the supplicant takes care of it.
if (mWifiNative.isGroupOwner(mSavedPeerConfig.deviceAddress)) {
+ if (DBG) logd("Sending join to GO");
p2pConnectWithPinDisplay(mSavedPeerConfig, JOIN_GROUP);
transitionTo(mGroupNegotiationState);
} else {
+ if (DBG) logd("Sending prov disc");
transitionTo(mProvisionDiscoveryState);
}
}
@@ -651,9 +668,7 @@
case GROUP_CREATING_TIMED_OUT:
if (mGroupCreatingTimeoutIndex == message.arg1) {
if (DBG) logd("Group negotiation timed out");
- updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.FAILED);
- mSavedPeerConfig = null;
- sendP2pPeersChangedBroadcast();
+ handleGroupCreationFailure();
transitionTo(mInactiveState);
}
break;
@@ -663,12 +678,15 @@
WifiP2pManager.BUSY);
break;
case WifiP2pManager.CANCEL_CONNECT:
- if (mWifiNative.p2pCancelConnect()) {
- replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
- } else {
- replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
- WifiP2pManager.ERROR);
- }
+ //Do a supplicant p2p_cancel which only cancels an ongoing
+ //group negotiation. This will fail for a pending provision
+ //discovery or for a pending user action, but at the framework
+ //level, we always treat cancel as succeded and enter
+ //an inactive state
+ mWifiNative.p2pCancelConnect();
+ handleGroupCreationFailure();
+ transitionTo(mInactiveState);
+ replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
break;
default:
return NOT_HANDLED;
@@ -811,9 +829,7 @@
case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
if (DBG) logd(getName() + " go failure");
- updateDeviceStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.FAILED);
- mSavedPeerConfig = null;
- sendP2pPeersChangedBroadcast();
+ handleGroupCreationFailure();
transitionTo(mInactiveState);
break;
default:
@@ -838,6 +854,10 @@
setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
sendP2pConnectionChangedBroadcast();
}
+
+ if (!mPersistGroup) {
+ mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
+ }
}
@Override
@@ -886,6 +906,8 @@
if (DBG) logd("DhcpInfo: " + dhcpInfo);
setWifiP2pInfoOnGroupFormation(dhcpInfo.serverAddress);
sendP2pConnectionChangedBroadcast();
+ //Turn on power save on client
+ mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
} else {
loge("DHCP failed");
mWifiNative.p2pGroupRemove(mGroup.getInterface());
@@ -1258,6 +1280,8 @@
//The supplicant default is to support everything, but a bug necessitates
//the framework to specify this explicitly
mWifiNative.setConfigMethods("keypad display push_button");
+ //STA has higher priority over P2P
+ mWifiNative.setConcurrencyPriority("sta");
mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
updateThisDevice(WifiP2pDevice.AVAILABLE);
@@ -1269,6 +1293,14 @@
sendThisDeviceChangedBroadcast();
}
+ private void handleGroupCreationFailure() {
+ mSavedPeerConfig = null;
+ /* After cancelling group formation, new connections on existing peers can fail
+ * at supplicant. Flush and restart discovery */
+ mWifiNative.p2pFlush();
+ sendMessage(WifiP2pManager.DISCOVER_PEERS);
+ }
+
//State machine initiated requests can have replyTo set to null indicating
//there are no recepients, we ignore those reply actions
private void replyToMessage(Message msg, int what) {