diff options
97 files changed, 1027 insertions, 315 deletions
@@ -118,6 +118,7 @@ LOCAL_SRC_FILES += \ 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/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_SHARED_LIBRARIES := \ 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/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 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ class ActivityManagerProxy implements IActivityManager 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/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 interface IActivityManager extends IInterface { 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 @@ public interface IActivityManager extends IInterface { 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/content/Intent.java b/core/java/android/content/Intent.java index 2a9f1af..736dd24 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2034,6 +2034,38 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.HDMI_AUDIO_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"; + + /** + * 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"; + + /** * <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 class PackageParser { 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 class PackageParser { 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 @@ public class PackageParser { 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/InputManager.java b/core/java/android/hardware/input/InputManager.java index ba64035..5ead1f4 100755 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -39,12 +39,9 @@ import android.os.ServiceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Log; -import android.view.Display; -import android.view.IWindowManager; import android.view.InputDevice; import android.view.InputEvent; import android.view.KeyCharacterMap; -import android.view.WindowManagerPolicy; import android.view.KeyCharacterMap.UnavailableException; import java.util.ArrayList; diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 93f93c7..c40504a 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -66,6 +66,8 @@ public class UsbManager { * 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 class UsbManager { 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 @@ import android.net.NetworkTemplate; /** {@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/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 @@ public class TrafficStats { } } + /** {@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/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.net.wifi.WifiManager; 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 @@ public final class Settings { 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 @@ public final class Settings { 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..f7a7eb8 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -50,8 +50,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable 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; @@ -155,7 +153,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (where == mGapStart) return; - boolean atEnd = (where == length()); + boolean atend = (where == length()); if (where < mGapStart) { int overlap = mGapStart - where; @@ -181,7 +179,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable 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 +190,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (end == where) { int flag = (mSpanFlags[i] & END_MASK); - if (flag == POINT || (atEnd && flag == PARAGRAPH)) + if (flag == POINT || (atend && flag == PARAGRAPH)) end += mGapLength; } @@ -399,7 +397,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable // 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 +419,53 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable 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! + + checkRange("replace", start, end); + moveGapTo(end); + + if (mGapLength < 2) + resizeFor(length() + 1); - change(start, end, tb, tbstart, tbend); + 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(); + } - if (adjustSelection) { + 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 +474,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable 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); diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index d1af397..b0399fd 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -526,7 +526,7 @@ public abstract class HardwareRenderer { 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; diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 93a0185..6f8d09b 100755 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -41,6 +41,7 @@ import java.util.List; public final class InputDevice implements Parcelable { private int mId; private String mName; + private String mDescriptor; private int mSources; private int mKeyboardType; private String mKeyCharacterMapFile; @@ -334,12 +335,24 @@ public final class InputDevice implements Parcelable { * 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; } /** @@ -548,6 +561,7 @@ public final class InputDevice implements Parcelable { private void readFromParcel(Parcel in) { mId = in.readInt(); mName = in.readString(); + mDescriptor = in.readString(); mSources = in.readInt(); mKeyboardType = in.readInt(); mKeyCharacterMapFile = in.readString(); @@ -566,6 +580,7 @@ public final class InputDevice implements Parcelable { 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); @@ -592,7 +607,8 @@ public final class InputDevice implements Parcelable { 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/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index d6073e3..e649904 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..0203d82 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/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-ar/strings.xml b/core/res/res/values-ar/strings.xml index 9c3ef5e..f0800c0 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/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-be/strings.xml b/core/res/res/values-be/strings.xml index dcb8f05..b286a25 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/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">"Каб праслухаць парол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..365e63a 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..3560e3d 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..66b87c0 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..942a40a 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/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-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..e863aba 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- 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-et/strings.xml b/core/res/res/values-et/strings.xml index 890dd7b..5303a13 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..92cb595 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/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-fi/strings.xml b/core/res/res/values-fi/strings.xml index 54e1a1b..e3db295 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..60eed61 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..5120648 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/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-hr/strings.xml b/core/res/res/values-hr/strings.xml index b0ebc8a..b00cbab 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..0fa59fc 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/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">"Suara hidup"</string> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..fc9ab19 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..c8d1d6b 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/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-ja/strings.xml b/core/res/res/values-ja/strings.xml index 526535f..5d3e1c6 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/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">"サウンドON"</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-ko/strings.xml b/core/res/res/values-ko/strings.xml index b38b988..6be9465 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/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-lt/strings.xml b/core/res/res/values-lt/strings.xml index 4d67940..da81e3e 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..5489714 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..28fc1a8 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..51e62e8 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..97391bf 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/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-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..da7a0f2 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/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-sv/strings.xml b/core/res/res/values-sv/strings.xml index 7ba32ce..1c916f9 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..88fc3b6 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/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-tl/strings.xml b/core/res/res/values-tl/strings.xml index fd88fc1..2addf86 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..7c01fa3 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..4b3fb11 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/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-vi/strings.xml b/core/res/res/values-vi/strings.xml index 609452d..faa0092 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1230,6 +1230,8 @@ <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> + <!-- no translation found for description_target_search (3091587249776033139) --> + <skip /> <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..9418e38 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/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-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index aa8eda1..57d3f7e 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/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-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/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 @@ English language interface:</p> <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 @@ attribute to help users understand what content is expected.</p> <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 @@ option is not available.</p> <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/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 @@ private: 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 @@ public: 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 @@ public: private: int32_t mId; String8 mName; + String8 mDescriptor; uint32_t mSources; int32_t mKeyboardType; String8 mKeyCharacterMapFile; @@ -863,23 +890,6 @@ private: 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 @@ void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { // --- 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 @@ status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { 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 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { 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 @@ LOCAL_SRC_FILES:= \ IObbActionListener.cpp \ IMountService.cpp -LOCAL_STATIC_LIBRARIES := \ - libutils \ - libbinder - LOCAL_MODULE:= libstorage include $(BUILD_STATIC_LIBRARY) 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 @@ final public class MediaCodec { 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 @@ final public class MediaCodec { 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 @@ status_t JMediaCodec::queueInputBuffer( 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 @@ static void android_media_MediaCodec_queueInputBuffer( 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 @@ static JNINativeMethod gMethods[] = { { "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 @@ struct JMediaCodec : public RefBase { 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/services/input/EventHub.cpp b/services/input/EventHub.cpp index 1b74aa6..665d711 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 @@ static inline const char* toString(bool value) { 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 @@ EventHub::~EventHub(void) { 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 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { 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 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { 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); @@ -1303,6 +1341,7 @@ void EventHub::dump(String8& dump) { } 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 @@ public: 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 @@ public: 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 eccce29..ddd870d 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -344,18 +344,19 @@ void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { } 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 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { } 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 @@ bool InputReaderThread::threadLoop() { // --- 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 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) { #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::timeoutExpired(nsecs_t when) { } 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 @@ public: 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 @@ private: /* 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 @@ public: 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 @@ class FakeEventHub : public EventHubInterface { }; struct Device { - String8 name; + InputDeviceIdentifier identifier; uint32_t classes; PropertyMap configuration; KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes; @@ -287,8 +287,8 @@ class FakeEventHub : public EventHubInterface { 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 @@ public: 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 @@ private: 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 @@ public: } 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 @@ protected: 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 @@ protected: 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.Message; 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.Comparator; 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } } } - + + 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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/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 @@ public final class ActivityManagerService extends ActivityManagerNative 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/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index b0657a6..77addd6 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1740,7 +1740,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 290bd2c..540f606 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -221,6 +221,11 @@ public class NetworkStatsRecorder { if (mLastSnapshot != null) { mLastSnapshot = mLastSnapshot.withoutUid(uid); } + + final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; + if (complete != null) { + complete.removeUid(uid); + } } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index b847673..f7ba329 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.content.IntentFilter; 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @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); - @Override - public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { - return mDevStatsCached.getSummary(template, start, end); - } + // return an IBinder which holds strong references to any loaded stats + // for its lifetime; when caller closes only weak references remain. - @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); - } + 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 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 diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index 4bea5e4..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.LinkedList; 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 @@ public class UsbDeviceManager { "/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 @@ public class UsbDeviceManager { 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 @@ public class UsbDeviceManager { 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 @@ public class UsbDeviceManager { 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 @@ public class UsbDeviceManager { } 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 @@ public class UsbDeviceManager { 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..003dc17 100644 --- a/services/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/java/com/android/server/wm/AppWindowAnimator.java @@ -259,6 +259,19 @@ public class AppWindowAnimator { 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 @@ class AppWindowToken extends WindowToken { } } - 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 @@ class DimAnimator { 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..c1dbb36 100644 --- a/services/java/com/android/server/wm/DimSurface.java +++ b/services/java/com/android/server/wm/DimSurface.java @@ -32,14 +32,14 @@ class DimSurface { 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 67e057e..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 android.view.animation.Animation; 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 @@ public class WindowAnimator { 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 @@ public class WindowAnimator { ++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 @@ public class WindowAnimator { // 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 @@ public class WindowAnimator { // 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 @@ public class WindowAnimator { } } - 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 @@ public class WindowAnimator { 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 @@ public class WindowAnimator { 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 @@ public class WindowAnimator { } } } - 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 @@ public class WindowAnimator { } } - 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 @@ public class WindowAnimator { "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 @@ public class WindowAnimator { // We can now show all of the drawn windows! if (!mService.mOpeningApps.contains(wtoken)) { - mAnimating |= wtoken.showAllWindowsLocked(); + mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked(); } } } @@ -435,9 +437,16 @@ public class WindowAnimator { 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) { @@ -509,4 +518,18 @@ public class WindowAnimator { 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 716b7b1..6f7852d 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -351,32 +351,7 @@ public class WindowManagerService extends IWindowManager.Stub * 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 @@ -393,32 +368,7 @@ public class WindowManagerService extends IWindowManager.Stub /** * 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 @@ -6504,6 +6454,7 @@ public class WindowManagerService extends IWindowManager.Stub 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; @@ -6942,33 +6893,37 @@ public class WindowManagerService extends IWindowManager.Stub // 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; @@ -7752,20 +7707,19 @@ public class WindowManagerService extends IWindowManager.Stub 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++) { @@ -8624,6 +8578,7 @@ public class WindowManagerService extends IWindowManager.Stub wsa.mSurfaceShown = false; wsa.mSurface = null; ws.mHasSurface = false; + mAnimator.mWinAnimators.remove(wsa); mForceRemoves.add(ws); i--; N--; @@ -8637,6 +8592,7 @@ public class WindowManagerService extends IWindowManager.Stub wsa.mSurfaceShown = false; wsa.mSurface = null; ws.mHasSurface = false; + mAnimator.mWinAnimators.remove(wsa); leakedSurface = true; } } @@ -8676,6 +8632,7 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ class WindowStateAnimator { /** 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 @@ class WindowStateAnimator { 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 @@ class WindowStateAnimator { 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 @@ class WindowStateAnimator { + " / " + 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 @@ class WindowStateAnimator { 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..c57402f 100644 --- a/services/jni/com_android_server_input_InputManagerService.cpp +++ b/services/jni/com_android_server_input_InputManagerService.cpp @@ -95,6 +95,7 @@ static struct { jfieldID mId; jfieldID mName; + jfieldID mDescriptor; jfieldID mSources; jfieldID mKeyboardType; jfieldID mKeyCharacterMapFile; @@ -1169,12 +1170,17 @@ static jobject nativeGetInputDevice(JNIEnv* env, } 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 +1191,7 @@ static jobject nativeGetInputDevice(JNIEnv* env, 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 +1452,9 @@ int register_android_server_InputManager(JNIEnv* env) { 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..2033db6 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.Binder; 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { 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 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { 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); 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.app.PendingIntent; 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 @@ import libcore.io.IoUtils; */ @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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { private IConnectivityManager mConnManager; private NetworkStatsService mService; + private INetworkStatsSession mSession; private INetworkManagementEventObserver mNetworkObserver; @Override @@ -134,6 +136,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mService = new NetworkStatsService( mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings); mService.bindConnectivityManager(mConnManager); + mSession = mService.openSession(); mElapsedRealtime = 0L; @@ -172,6 +175,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mSettings = null; mConnManager = null; + mSession.close(); mService = null; super.tearDown(); @@ -349,7 +353,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } 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/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 @@ package com.android.tests.dataidle; 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 @@ public class DataIdleTest extends InstrumentationTestCase { * @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/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 @@ int doDump(Bundle* bundle) // 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 @@ int doDump(Bundle* bundle) 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 @@ int doDump(Bundle* bundle) 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 |
