Merge "AAPT2: Process <java-symbols> and private symbol package"
diff --git a/api/current.txt b/api/current.txt
index 4a1a458..55b5d52 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30532,6 +30532,8 @@
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+ field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
+ field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -35330,8 +35332,10 @@
field public static final int KEYCODE_CLEAR = 28; // 0x1c
field public static final int KEYCODE_COMMA = 55; // 0x37
field public static final int KEYCODE_CONTACTS = 207; // 0xcf
+ field public static final int KEYCODE_COPY = 278; // 0x116
field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
+ field public static final int KEYCODE_CUT = 277; // 0x115
field public static final int KEYCODE_D = 32; // 0x20
field public static final int KEYCODE_DEL = 67; // 0x43
field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
@@ -35449,6 +35453,7 @@
field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
field public static final int KEYCODE_PAIRING = 225; // 0xe1
+ field public static final int KEYCODE_PASTE = 279; // 0x117
field public static final int KEYCODE_PERIOD = 56; // 0x38
field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
field public static final int KEYCODE_PLUS = 81; // 0x51
diff --git a/api/system-current.txt b/api/system-current.txt
index ecea9b0..06cbfa7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9536,6 +9536,7 @@
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
method public void setGrantedRuntimePermissions(java.lang.String[]);
+ method public void setInstallFlagsQuick();
method public void setInstallLocation(int);
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
@@ -32733,6 +32734,8 @@
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+ field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
+ field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -37626,8 +37629,10 @@
field public static final int KEYCODE_CLEAR = 28; // 0x1c
field public static final int KEYCODE_COMMA = 55; // 0x37
field public static final int KEYCODE_CONTACTS = 207; // 0xcf
+ field public static final int KEYCODE_COPY = 278; // 0x116
field public static final int KEYCODE_CTRL_LEFT = 113; // 0x71
field public static final int KEYCODE_CTRL_RIGHT = 114; // 0x72
+ field public static final int KEYCODE_CUT = 277; // 0x115
field public static final int KEYCODE_D = 32; // 0x20
field public static final int KEYCODE_DEL = 67; // 0x43
field public static final int KEYCODE_DPAD_CENTER = 23; // 0x17
@@ -37745,6 +37750,7 @@
field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
field public static final int KEYCODE_PAIRING = 225; // 0xe1
+ field public static final int KEYCODE_PASTE = 279; // 0x117
field public static final int KEYCODE_PERIOD = 56; // 0x38
field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
field public static final int KEYCODE_PLUS = 81; // 0x51
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index 9d60ee1..6b2f460 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -57,7 +57,7 @@
int write_idmap(int fd, const uint32_t *data, size_t size)
{
- if (lseek(fd, SEEK_SET, 0) < 0) {
+ if (lseek(fd, 0, SEEK_SET) < 0) {
return -1;
}
size_t bytesLeft = size;
@@ -86,7 +86,7 @@
char buf[N];
size_t bytesLeft = N;
- if (lseek(idmap_fd, SEEK_SET, 0) < 0) {
+ if (lseek(idmap_fd, 0, SEEK_SET) < 0) {
return true;
}
for (;;) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index b44aab7..e038a72 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -465,9 +465,6 @@
// If set this fragment is being retained across the current config change.
boolean mRetaining;
- // If set this fragment's loaders are being retained across the current config change.
- boolean mRetainLoader;
-
// If set this fragment has menu items to contribute.
boolean mHasMenu;
@@ -2415,7 +2412,7 @@
mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
- if (mRetainLoader) {
+ if (mHost.getRetainLoaders()) {
mLoaderManager.doRetain();
} else {
mLoaderManager.doStop();
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index 1b45137..28dadfa 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -341,7 +341,6 @@
*/
public void doLoaderStop(boolean retain) {
mHost.doLoaderStop(retain);
- mHost.mFragmentManager.setRetainLoader(retain);
}
/**
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 7b01307..13517e6 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -42,9 +42,14 @@
private final Handler mHandler;
final int mWindowAnimations;
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
+ /** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
private ArrayMap<String, LoaderManager> mAllLoaderManagers;
+ /** Whether or not fragment loaders should retain their state */
+ private boolean mRetainLoaders;
+ /** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
private LoaderManagerImpl mLoaderManager;
private boolean mCheckedForLoaderManager;
+ /** Whether or not the fragment host loader manager was started */
private boolean mLoadersStarted;
public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
@@ -166,6 +171,10 @@
return true;
}
+ boolean getRetainLoaders() {
+ return mRetainLoaders;
+ }
+
Activity getActivity() {
return mActivity;
}
@@ -217,6 +226,8 @@
}
void doLoaderStop(boolean retain) {
+ mRetainLoaders = retain;
+
if (mLoaderManager == null) {
return;
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 046c87a..696ccdb 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -869,17 +869,6 @@
}
}
- void setRetainLoader(boolean retain) {
- if (mActive != null) {
- for (int i=0; i<mActive.size(); i++) {
- Fragment f = mActive.get(i);
- if (f != null) {
- f.mRetainLoader = retain;
- }
- }
- }
- }
-
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
if (DEBUG && false) Log.v(TAG, "moveToState: " + f
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3283005..d6d395b 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1042,6 +1042,12 @@
}
/** {@hide} */
+ @SystemApi
+ public void setInstallFlagsQuick() {
+ installFlags |= PackageManager.INSTALL_QUICK;
+ }
+
+ /** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 82cbbbe..aed1a0b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -43,12 +43,10 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
-import android.text.TextUtils;
import android.util.AndroidException;
import com.android.internal.util.ArrayUtils;
@@ -431,6 +429,14 @@
public static final int INSTALL_FORCE_PERMISSION_PROMPT = 0x00000400;
/**
+ * Flag parameter for {@link #installPackage} to indicate that this package is
+ * to be installed quickly.
+ *
+ * @hide
+ */
+ public static final int INSTALL_QUICK = 0x00000800;
+
+ /**
* Flag parameter for
* {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
* that you don't want to kill the app containing the component. Be careful when you set this
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bf54415..1e85dfb 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -24,6 +24,7 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.app.ActivityManager;
import android.content.ComponentName;
@@ -39,6 +40,7 @@
import android.os.Environment;
import android.os.FileUtils;
import android.os.PatternMatcher;
+import android.os.Trace;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -622,6 +624,8 @@
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
public final static int PARSE_ENFORCE_CODE = 1<<10;
+ // TODO: fix b/25118622; remove this entirely once signature processing is quick
+ public final static int PARSE_SKIP_VERIFICATION = 1<<11;
private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
@@ -902,6 +906,7 @@
}
pkg.volumeUuid = volumeUuid;
+ pkg.applicationInfo.volumeUuid = volumeUuid;
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
@@ -920,7 +925,6 @@
private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = pkg.splitCodePaths[splitIndex];
- final File apkFile = new File(apkPath);
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkPath;
@@ -1054,33 +1058,38 @@
/**
* Collect certificates from all the APKs described in the given package,
- * populating {@link Package#mSignatures}. This also asserts that all APK
+ * populating {@link Package#mSignatures}.
+ * <p>Depending upon the parser flags, this may also asserts that all APK
* contents are signed correctly and consistently.
*/
- public void collectCertificates(Package pkg, int flags) throws PackageParserException {
+ public void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
pkg.mCertificates = null;
pkg.mSignatures = null;
pkg.mSigningKeys = null;
- collectCertificates(pkg, new File(pkg.baseCodePath), flags);
+ collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (String splitCodePath : pkg.splitCodePaths) {
- collectCertificates(pkg, new File(splitCodePath), flags);
+ collectCertificates(pkg, new File(splitCodePath), parseFlags);
}
}
}
- private static void collectCertificates(Package pkg, File apkFile, int flags)
+ private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
throws PackageParserException {
- final boolean requireCode = ((flags & PARSE_ENFORCE_CODE) != 0)
+ final boolean requireCode = ((parseFlags & PARSE_ENFORCE_CODE) != 0)
&& ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
final String apkPath = apkFile.getAbsolutePath();
+ final boolean skipVerification = Build.IS_DEBUGGABLE
+ && ((parseFlags & PARSE_SKIP_VERIFICATION) != 0);
- boolean codeFound = false;
+ boolean codeFound = skipVerification;
StrictJarFile jarFile = null;
try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
jarFile = new StrictJarFile(apkPath);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Always verify manifest, regardless of source
final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
@@ -1089,11 +1098,12 @@
"Package " + apkPath + " has no manifest");
}
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "buildVerifyList");
final List<ZipEntry> toVerify = new ArrayList<>();
toVerify.add(manifestEntry);
// If we're parsing an untrusted package, verify all contents
- if ((flags & PARSE_IS_SYSTEM) == 0) {
+ if (!skipVerification && (parseFlags & PARSE_IS_SYSTEM) == 0) {
final Iterator<ZipEntry> i = jarFile.iterator();
while (i.hasNext()) {
final ZipEntry entry = i.next();
@@ -1110,6 +1120,7 @@
toVerify.add(entry);
}
}
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (!codeFound && requireCode) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
@@ -1119,6 +1130,7 @@
// Verify that entries are signed consistently with the first entry
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyEntries");
for (ZipEntry entry : toVerify) {
final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
if (ArrayUtils.isEmpty(entryCerts)) {
@@ -1135,6 +1147,9 @@
for (int i=0; i < entryCerts.length; i++) {
pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
}
+ if (skipVerification) {
+ break;
+ }
} else {
if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
throw new PackageParserException(
@@ -1144,6 +1159,7 @@
}
}
}
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
} catch (GeneralSecurityException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
"Failed to collect certificates from " + apkPath, e);
@@ -1199,7 +1215,8 @@
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
// TODO: factor signature related items out of Package object
final Package tempPkg = new Package(null);
- collectCertificates(tempPkg, apkFile, 0);
+ // TODO: fix b/25118622; pass in '0' for parse flags
+ collectCertificates(tempPkg, apkFile, flags & PARSE_SKIP_VERIFICATION);
signatures = tempPkg.mSignatures;
} else {
signatures = null;
@@ -1906,8 +1923,7 @@
return pkg;
}
- private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs)
- throws XmlPullParserException, IOException {
+ private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
FeatureInfo fi = new FeatureInfo();
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestUsesFeature);
@@ -3960,7 +3976,7 @@
private boolean parseAllMetaData(Resources res,
XmlPullParser parser, AttributeSet attrs, String tag,
- Component outInfo, String[] outError)
+ Component<?> outInfo, String[] outError)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index c6ae14e..174291e 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -61,6 +61,8 @@
// Registers an input devices changed listener.
void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
+ // Queries whether the device is currently in tablet mode
+ int isInTabletMode();
// Registers a tablet mode change listener
void registerTabletModeChangedListener(ITabletModeChangedListener listener);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 3949d97..201afee 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -19,6 +19,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
+import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
@@ -39,6 +40,8 @@
import android.view.InputDevice;
import android.view.InputEvent;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -105,13 +108,14 @@
* of a key character map for a particular keyboard layout. The label on the receiver
* is used to name the collection of keyboard layouts provided by this receiver in the
* keyboard layout settings.
- * <pre></code>
+ * <pre><code>
* <?xml version="1.0" encoding="utf-8"?>
* <keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
* <keyboard-layout android:name="keyboard_layout_english_us"
* android:label="@string/keyboard_layout_english_us_label"
* android:keyboardLayout="@raw/keyboard_layout_english_us" />
* </keyboard-layouts>
+ * </pre></code>
* </p><p>
* The <code>android:name</code> attribute specifies an identifier by which
* the keyboard layout will be known in the package.
@@ -179,6 +183,31 @@
*/
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; // see InputDispatcher.h
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SWITCH_STATE_UNKNOWN, SWITCH_STATE_OFF, SWITCH_STATE_ON})
+ public @interface SwitchState {}
+
+ /**
+ * Switch State: Unknown.
+ *
+ * The system has yet to report a valid value for the switch.
+ * @hide
+ */
+ public static final int SWITCH_STATE_UNKNOWN = -1;
+
+ /**
+ * Switch State: Off.
+ * @hide
+ */
+ public static final int SWITCH_STATE_OFF = 0;
+
+ /**
+ * Switch State: On.
+ * @hide
+ */
+ public static final int SWITCH_STATE_ON = 1;
+
private InputManager(IInputManager im) {
mIm = im;
}
@@ -340,6 +369,23 @@
}
/**
+ * Queries whether the device is in tablet mode.
+ *
+ * @return The tablet switch state which is one of {@link #SWITCH_STATE_UNKNOWN},
+ * {@link #SWITCH_STATE_OFF} or {@link #SWITCH_STATE_ON}.
+ * @hide
+ */
+ @SwitchState
+ public int isInTabletMode() {
+ try {
+ return mIm.isInTabletMode();
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not get tablet mode state", ex);
+ return SWITCH_STATE_UNKNOWN;
+ }
+ }
+
+ /**
* Register a tablet mode changed listener.
*
* @param listener The listener to register.
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index b777e8c..dc2aa3a 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2008-2009 Google Inc.
- *
+ *
* 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
@@ -57,7 +57,7 @@
/**
* A view that renders a virtual {@link Keyboard}. It handles rendering of keys and
* detecting key presses and touch movements.
- *
+ *
* @attr ref android.R.styleable#KeyboardView_keyBackground
* @attr ref android.R.styleable#KeyboardView_keyPreviewLayout
* @attr ref android.R.styleable#KeyboardView_keyPreviewOffset
@@ -73,7 +73,7 @@
* Listener for virtual keyboard events.
*/
public interface OnKeyboardActionListener {
-
+
/**
* Called when the user presses a key. This is sent before the {@link #onKey} is called.
* For keys that repeat, this is only called once.
@@ -81,7 +81,7 @@
* key, the value will be zero.
*/
void onPress(int primaryCode);
-
+
/**
* Called when the user releases a key. This is sent after the {@link #onKey} is called.
* For keys that repeat, this is only called once.
@@ -106,22 +106,22 @@
* @param text the sequence of characters to be displayed.
*/
void onText(CharSequence text);
-
+
/**
* Called when the user quickly moves the finger from right to left.
*/
void swipeLeft();
-
+
/**
* Called when the user quickly moves the finger from left to right.
*/
void swipeRight();
-
+
/**
* Called when the user quickly moves the finger from up to down.
*/
void swipeDown();
-
+
/**
* Called when the user quickly moves the finger from down to up.
*/
@@ -131,8 +131,8 @@
private static final boolean DEBUG = false;
private static final int NOT_A_KEY = -1;
private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE };
- private static final int[] LONG_PRESSABLE_STATE_SET = { R.attr.state_long_pressable };
-
+ private static final int[] LONG_PRESSABLE_STATE_SET = { R.attr.state_long_pressable };
+
private Keyboard mKeyboard;
private int mCurrentKeyIndex = NOT_A_KEY;
private int mLabelTextSize;
@@ -141,7 +141,7 @@
private float mShadowRadius;
private int mShadowColor;
private float mBackgroundDimAmount;
-
+
private TextView mPreviewText;
private PopupWindow mPreviewPopup;
private int mPreviewTextSizeLarge;
@@ -162,7 +162,7 @@
/** Listener for {@link OnKeyboardActionListener}. */
private OnKeyboardActionListener mKeyboardActionListener;
-
+
private static final int MSG_SHOW_PREVIEW = 1;
private static final int MSG_REMOVE_PREVIEW = 2;
private static final int MSG_REPEAT = 3;
@@ -171,7 +171,7 @@
private static final int DELAY_BEFORE_PREVIEW = 0;
private static final int DELAY_AFTER_PREVIEW = 70;
private static final int DEBOUNCE_TIME = 70;
-
+
private int mVerticalCorrection;
private int mProximityThreshold;
@@ -187,10 +187,10 @@
private int mStartY;
private boolean mProximityCorrectOn;
-
+
private Paint mPaint;
private Rect mPadding;
-
+
private long mDownTime;
private long mLastMoveTime;
private int mLastKey;
@@ -253,28 +253,7 @@
/** Whether the requirement of a headset to hear passwords if accessibility is enabled is announced. */
private boolean mHeadsetRequiredToHearPasswordsAnnounced;
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SHOW_PREVIEW:
- showKey(msg.arg1);
- break;
- case MSG_REMOVE_PREVIEW:
- mPreviewText.setVisibility(INVISIBLE);
- break;
- case MSG_REPEAT:
- if (repeatKey()) {
- Message repeat = Message.obtain(this, MSG_REPEAT);
- sendMessageDelayed(repeat, REPEAT_INTERVAL);
- }
- break;
- case MSG_LONGPRESS:
- openPopupIfRequired((MotionEvent) msg.obj);
- break;
- }
- }
- };
+ Handler mHandler;
public KeyboardView(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.keyboardViewStyle);
@@ -298,7 +277,7 @@
int keyTextSize = 0;
int n = a.getIndexCount();
-
+
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
@@ -338,7 +317,7 @@
break;
}
}
-
+
a = mContext.obtainStyledAttributes(
com.android.internal.R.styleable.Theme);
mBackgroundDimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
@@ -352,16 +331,16 @@
} else {
mShowPreview = false;
}
-
+
mPreviewPopup.setTouchable(false);
-
+
mPopupKeyboard = new PopupWindow(context);
mPopupKeyboard.setBackgroundDrawable(null);
//mPopupKeyboard.setClippingEnabled(false);
-
+
mPopupParent = this;
//mPredicting = true;
-
+
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(keyTextSize);
@@ -380,64 +359,94 @@
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
resetMultiTap();
- initGestureDetector();
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ initGestureDetector();
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SHOW_PREVIEW:
+ showKey(msg.arg1);
+ break;
+ case MSG_REMOVE_PREVIEW:
+ mPreviewText.setVisibility(INVISIBLE);
+ break;
+ case MSG_REPEAT:
+ if (repeatKey()) {
+ Message repeat = Message.obtain(this, MSG_REPEAT);
+ sendMessageDelayed(repeat, REPEAT_INTERVAL);
+ }
+ break;
+ case MSG_LONGPRESS:
+ openPopupIfRequired((MotionEvent) msg.obj);
+ break;
+ }
+ }
+ };
+ }
+ }
private void initGestureDetector() {
- mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onFling(MotionEvent me1, MotionEvent me2,
- float velocityX, float velocityY) {
- if (mPossiblePoly) return false;
- final float absX = Math.abs(velocityX);
- final float absY = Math.abs(velocityY);
- float deltaX = me2.getX() - me1.getX();
- float deltaY = me2.getY() - me1.getY();
- int travelX = getWidth() / 2; // Half the keyboard width
- int travelY = getHeight() / 2; // Half the keyboard height
- mSwipeTracker.computeCurrentVelocity(1000);
- final float endingVelocityX = mSwipeTracker.getXVelocity();
- final float endingVelocityY = mSwipeTracker.getYVelocity();
- boolean sendDownKey = false;
- if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) {
- if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) {
- sendDownKey = true;
- } else {
- swipeRight();
- return true;
+ if (mGestureDetector == null) {
+ mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onFling(MotionEvent me1, MotionEvent me2,
+ float velocityX, float velocityY) {
+ if (mPossiblePoly) return false;
+ final float absX = Math.abs(velocityX);
+ final float absY = Math.abs(velocityY);
+ float deltaX = me2.getX() - me1.getX();
+ float deltaY = me2.getY() - me1.getY();
+ int travelX = getWidth() / 2; // Half the keyboard width
+ int travelY = getHeight() / 2; // Half the keyboard height
+ mSwipeTracker.computeCurrentVelocity(1000);
+ final float endingVelocityX = mSwipeTracker.getXVelocity();
+ final float endingVelocityY = mSwipeTracker.getYVelocity();
+ boolean sendDownKey = false;
+ if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) {
+ if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) {
+ sendDownKey = true;
+ } else {
+ swipeRight();
+ return true;
+ }
+ } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) {
+ if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) {
+ sendDownKey = true;
+ } else {
+ swipeLeft();
+ return true;
+ }
+ } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) {
+ if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) {
+ sendDownKey = true;
+ } else {
+ swipeUp();
+ return true;
+ }
+ } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) {
+ if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) {
+ sendDownKey = true;
+ } else {
+ swipeDown();
+ return true;
+ }
}
- } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) {
- if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) {
- sendDownKey = true;
- } else {
- swipeLeft();
- return true;
- }
- } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) {
- if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) {
- sendDownKey = true;
- } else {
- swipeUp();
- return true;
- }
- } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) {
- if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) {
- sendDownKey = true;
- } else {
- swipeDown();
- return true;
- }
- }
- if (sendDownKey) {
- detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime());
+ if (sendDownKey) {
+ detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime());
+ }
+ return false;
}
- return false;
- }
- });
+ });
- mGestureDetector.setIsLongpressEnabled(false);
+ mGestureDetector.setIsLongpressEnabled(false);
+ }
}
public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
@@ -487,7 +496,7 @@
public Keyboard getKeyboard() {
return mKeyboard;
}
-
+
/**
* Sets the state of the shift key of the keyboard, if any.
* @param shifted whether or not to enable the state of the shift key
@@ -520,7 +529,7 @@
/**
* Enables or disables the key feedback popup. This is a popup that shows a magnified
- * version of the depressed key. By default the preview is enabled.
+ * version of the depressed key. By default the preview is enabled.
* @param previewEnabled whether or not to enable the key feedback popup
* @see #isPreviewEnabled()
*/
@@ -536,14 +545,14 @@
public boolean isPreviewEnabled() {
return mShowPreview;
}
-
+
public void setVerticalCorrection(int verticalOffset) {
-
+
}
public void setPopupParent(View v) {
mPopupParent = v;
}
-
+
public void setPopupOffset(int x, int y) {
mMiniKeyboardOffsetX = x;
mMiniKeyboardOffsetY = y;
@@ -569,9 +578,9 @@
return mProximityCorrectOn;
}
- /**
+ /**
* Popup keyboard close button clicked.
- * @hide
+ * @hide
*/
public void onClick(View v) {
dismissPopupKeyboard();
@@ -654,9 +663,9 @@
}
final Canvas canvas = mCanvas;
canvas.clipRect(mDirtyRect, Op.REPLACE);
-
+
if (mKeyboard == null) return;
-
+
final Paint paint = mPaint;
final Drawable keyBackground = mKeyBackground;
final Rect clipRegion = mClipRegion;
@@ -689,15 +698,15 @@
// Switch the character to uppercase if shift is pressed
String label = key.label == null? null : adjustCase(key.label).toString();
-
+
final Rect bounds = keyBackground.getBounds();
- if (key.width != bounds.right ||
+ if (key.width != bounds.right ||
key.height != bounds.bottom) {
keyBackground.setBounds(0, 0, key.width, key.height);
}
canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop);
keyBackground.draw(canvas);
-
+
if (label != null) {
// For characters, use large font. For labels like "Done", use small font.
if (label.length() > 1 && key.codes.length < 2) {
@@ -719,12 +728,12 @@
// Turn off drop shadow
paint.setShadowLayer(0, 0, 0, 0);
} else if (key.icon != null) {
- final int drawableX = (key.width - padding.left - padding.right
+ final int drawableX = (key.width - padding.left - padding.right
- key.icon.getIntrinsicWidth()) / 2 + padding.left;
- final int drawableY = (key.height - padding.top - padding.bottom
+ final int drawableY = (key.height - padding.top - padding.bottom
- key.icon.getIntrinsicHeight()) / 2 + padding.top;
canvas.translate(drawableX, drawableY);
- key.icon.setBounds(0, 0,
+ key.icon.setBounds(0, 0,
key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight());
key.icon.draw(canvas);
canvas.translate(-drawableX, -drawableY);
@@ -748,7 +757,7 @@
paint.setColor(0xFF00FF00);
canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
}
-
+
mDrawPending = false;
mDirtyRect.setEmpty();
}
@@ -769,8 +778,8 @@
primaryIndex = nearestKeyIndices[i];
}
- if (((mProximityCorrectOn
- && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold)
+ if (((mProximityCorrectOn
+ && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold)
|| isInside)
&& key.codes[0] > 32) {
// Find insertion point
@@ -779,9 +788,9 @@
closestKeyDist = dist;
closestKey = nearestKeyIndices[i];
}
-
+
if (allKeys == null) continue;
-
+
for (int j = 0; j < mDistances.length; j++) {
if (mDistances[j] > dist) {
// Make space for nCodes codes
@@ -846,11 +855,11 @@
return adjustCase(key.label);
}
}
-
+
private void showPreview(int keyIndex) {
int oldKeyIndex = mCurrentKeyIndex;
final PopupWindow previewPopup = mPreviewPopup;
-
+
mCurrentKeyIndex = keyIndex;
// Release the old key and press the new key
final Key[] keys = mKeys;
@@ -884,7 +893,7 @@
if (previewPopup.isShowing()) {
if (keyIndex == NOT_A_KEY) {
mHandler.sendMessageDelayed(mHandler
- .obtainMessage(MSG_REMOVE_PREVIEW),
+ .obtainMessage(MSG_REMOVE_PREVIEW),
DELAY_AFTER_PREVIEW);
}
}
@@ -894,20 +903,20 @@
showKey(keyIndex);
} else {
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0),
+ mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0),
DELAY_BEFORE_PREVIEW);
}
}
}
}
-
+
private void showKey(final int keyIndex) {
final PopupWindow previewPopup = mPreviewPopup;
final Key[] keys = mKeys;
if (keyIndex < 0 || keyIndex >= mKeys.length) return;
Key key = keys[keyIndex];
if (key.icon != null) {
- mPreviewText.setCompoundDrawables(null, null, null,
+ mPreviewText.setCompoundDrawables(null, null, null,
key.iconPreview != null ? key.iconPreview : key.icon);
mPreviewText.setText(null);
} else {
@@ -921,9 +930,9 @@
mPreviewText.setTypeface(Typeface.DEFAULT);
}
}
- mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width
+ int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width
+ mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
final int popupHeight = mPreviewHeight;
LayoutParams lp = mPreviewText.getLayoutParams();
@@ -969,7 +978,7 @@
} else {
previewPopup.setWidth(popupWidth);
previewPopup.setHeight(popupHeight);
- previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,
+ previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,
mPopupPreviewX, mPopupPreviewY);
}
mPreviewText.setVisibility(VISIBLE);
@@ -1030,7 +1039,7 @@
/**
* Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient
- * because the keyboard renders the keys to an off-screen buffer and an invalidate() only
+ * because the keyboard renders the keys to an off-screen buffer and an invalidate() only
* draws the cached buffer.
* @see #invalidateKey(int)
*/
@@ -1054,10 +1063,10 @@
}
final Key key = mKeys[keyIndex];
mInvalidatedKey = key;
- mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop,
+ mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop,
key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
onBufferDraw();
- invalidate(key.x + mPaddingLeft, key.y + mPaddingTop,
+ invalidate(key.x + mPaddingLeft, key.y + mPaddingTop,
key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
}
@@ -1070,7 +1079,7 @@
return false;
}
- Key popupKey = mKeys[mCurrentKey];
+ Key popupKey = mKeys[mCurrentKey];
boolean result = onLongPress(popupKey);
if (result) {
mAbortKey = true;
@@ -1105,12 +1114,12 @@
mKeyboardActionListener.onKey(primaryCode, keyCodes);
dismissPopupKeyboard();
}
-
+
public void onText(CharSequence text) {
mKeyboardActionListener.onText(text);
dismissPopupKeyboard();
}
-
+
public void swipeLeft() { }
public void swipeRight() { }
public void swipeUp() { }
@@ -1125,7 +1134,7 @@
//mInputView.setSuggest(mSuggest);
Keyboard keyboard;
if (popupKey.popupCharacters != null) {
- keyboard = new Keyboard(getContext(), popupKeyboardId,
+ keyboard = new Keyboard(getContext(), popupKeyboardId,
popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight());
} else {
keyboard = new Keyboard(getContext(), popupKeyboardId);
@@ -1133,9 +1142,9 @@
mMiniKeyboard.setKeyboard(keyboard);
mMiniKeyboard.setPopupParent(this);
mMiniKeyboardContainer.measure(
- MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
-
+
mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer);
} else {
mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(
@@ -1184,7 +1193,7 @@
@Override
public boolean onTouchEvent(MotionEvent me) {
- // Convert multi-pointer up/down events to single up/down events to
+ // Convert multi-pointer up/down events to single up/down events to
// deal with the typical multi-pointer behavior of two-thumb typing
final int pointerCount = me.getPointerCount();
final int action = me.getAction();
@@ -1250,7 +1259,7 @@
mHandler.removeMessages(MSG_LONGPRESS);
return true;
}
-
+
// Needs to be called after the gesture detector gets a turn, as it may have
// displayed the mini keyboard
if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) {
@@ -1272,7 +1281,7 @@
mDownTime = me.getEventTime();
mLastMoveTime = mDownTime;
checkMultiTap(eventTime, keyIndex);
- mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ?
+ mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ?
mKeys[keyIndex].codes[0] : 0);
if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) {
mRepeatKeyIndex = mCurrentKey;
@@ -1371,11 +1380,11 @@
detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime);
return true;
}
-
+
protected void swipeRight() {
mKeyboardActionListener.swipeRight();
}
-
+
protected void swipeLeft() {
mKeyboardActionListener.swipeLeft();
}
@@ -1393,7 +1402,7 @@
mPreviewPopup.dismiss();
}
removeMessages();
-
+
dismissPopupKeyboard();
mBuffer = null;
mCanvas = null;
@@ -1434,7 +1443,7 @@
mLastTapTime = -1;
mInMultiTap = false;
}
-
+
private void checkMultiTap(long eventTime, int keyIndex) {
if (keyIndex == NOT_A_KEY) return;
Key key = mKeys[keyIndex];
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 444548f..ad9058f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -901,8 +901,12 @@
* Tells the underlying networking system that the caller wants to
* begin using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType specifies which network the request pertains to
* @param feature the name of the feature to be used
* @return an integer value representing the outcome of the request.
@@ -952,8 +956,12 @@
* Tells the underlying networking system that the caller is finished
* using the named feature. The interpretation of {@code feature}
* is completely up to each networking implementation.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType specifies which network the request pertains to
* @param feature the name of the feature that is no longer needed
* @return an integer value representing the outcome of the request.
@@ -1339,8 +1347,12 @@
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface. An attempt to add a route that
* already exists is ignored, but treated as successful.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType the type of the network over which traffic to the specified
* host is to be routed
* @param hostAddress the IP address of the host to which the route is desired
@@ -1360,8 +1372,12 @@
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface. An attempt to add a route that
* already exists is ignored, but treated as successful.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param networkType the type of the network over which traffic to the specified
* host is to be routed
* @param hostAddress the IP address of the host to which the route is desired
@@ -1561,6 +1577,13 @@
return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
+ /** {@hide} */
+ public static final void enforceChangePermission(Context context) {
+ int uid = Binder.getCallingUid();
+ Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
+ .getPackageNameForUid(context, uid), true /* throwException */);
+ }
+
/** {@hide */
public static final void enforceTetherChangePermission(Context context) {
if (context.getResources().getStringArray(
@@ -1571,8 +1594,8 @@
android.Manifest.permission.CONNECTIVITY_INTERNAL, "ConnectivityService");
} else {
int uid = Binder.getCallingUid();
- Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
- .getPackageNameForUid(context, uid), true);
+ Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings
+ .getPackageNameForUid(context, uid), true /* throwException */);
}
}
@@ -1677,8 +1700,11 @@
* allowed between the tethered devices and this device, though upstream net
* access will of course fail until an upstream network interface becomes
* active.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param iface the interface name to tether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
@@ -1695,8 +1721,11 @@
/**
* Stop tethering the named interface.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param iface the interface name to untether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
@@ -1796,8 +1825,11 @@
* attempt to switch to Rndis and subsequently tether the resulting
* interface on {@code true} or turn off tethering and switch off
* Rndis on {@code false}.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param enable a boolean - {@code true} to enable tethering
* @return error a {@code TETHER_ERROR} value indicating success or failure type
@@ -2467,8 +2499,11 @@
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
* know how to go about satisfing a request with these capabilities.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} to be utilized for this
@@ -2490,8 +2525,12 @@
* network is not found within the given time (in milliseconds) the
* {@link NetworkCallback#unavailable} callback is called. The request must
* still be released normally by calling {@link releaseNetworkRequest}.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The callbacks to be utilized for this request. Note
* the callbacks must not be shared - they uniquely specify
@@ -2564,8 +2603,12 @@
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
* know how to go about satisfing a request with these capabilities.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
* @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
* to the {@link NetworkCallback#onAvailable} call. Typically
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 57eef83..b7a411e 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -288,7 +288,8 @@
} else {
final boolean matchesType = (sForceAllNetworkTypes
|| contains(DATA_USAGE_NETWORK_TYPES, ident.mType));
- return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+ return matchesType && !ArrayUtils.isEmpty(mMatchSubscriberIds)
+ && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
}
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 1273772b..5852f5f 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.IntegerRes;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -42,6 +43,8 @@
import java.util.Map;
import java.util.Set;
+import dalvik.system.VMRuntime;
+
/**
* Container for a message (data and object references) that can
* be sent through an IBinder. A Parcel can contain both flattened data
@@ -193,6 +196,7 @@
* indicating that we're responsible for its lifecycle.
*/
private boolean mOwnsNativeParcelObject;
+ private long mNativeSize;
private RuntimeException mStack;
@@ -244,7 +248,7 @@
private static native int nativeDataAvail(long nativePtr);
private static native int nativeDataPosition(long nativePtr);
private static native int nativeDataCapacity(long nativePtr);
- private static native void nativeSetDataSize(long nativePtr, int size);
+ private static native long nativeSetDataSize(long nativePtr, int size);
private static native void nativeSetDataPosition(long nativePtr, int pos);
private static native void nativeSetDataCapacity(long nativePtr, int size);
@@ -259,7 +263,7 @@
private static native void nativeWriteDouble(long nativePtr, double val);
private static native void nativeWriteString(long nativePtr, String val);
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
- private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
+ private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(long nativePtr);
private static native byte[] nativeReadBlob(long nativePtr);
@@ -272,13 +276,13 @@
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
private static native long nativeCreate();
- private static native void nativeFreeBuffer(long nativePtr);
+ private static native long nativeFreeBuffer(long nativePtr);
private static native void nativeDestroy(long nativePtr);
private static native byte[] nativeMarshall(long nativePtr);
- private static native void nativeUnmarshall(
+ private static native long nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
- private static native void nativeAppendFrom(
+ private static native long nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
private static native boolean nativeHasFileDescriptors(long nativePtr);
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
@@ -390,7 +394,7 @@
* @param size The new number of bytes in the Parcel.
*/
public final void setDataSize(int size) {
- nativeSetDataSize(mNativePtr, size);
+ updateNativeSize(nativeSetDataSize(mNativePtr, size));
}
/**
@@ -442,11 +446,11 @@
* Set the bytes in data to be the raw bytes of this Parcel.
*/
public final void unmarshall(byte[] data, int offset, int length) {
- nativeUnmarshall(mNativePtr, data, offset, length);
+ updateNativeSize(nativeUnmarshall(mNativePtr, data, offset, length));
}
public final void appendFrom(Parcel parcel, int offset, int length) {
- nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
+ updateNativeSize(nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length));
}
/**
@@ -599,7 +603,24 @@
* if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
*/
public final void writeFileDescriptor(FileDescriptor val) {
- nativeWriteFileDescriptor(mNativePtr, val);
+ updateNativeSize(nativeWriteFileDescriptor(mNativePtr, val));
+ }
+
+ private void updateNativeSize(long newNativeSize) {
+ if (mOwnsNativeParcelObject) {
+ if (newNativeSize > Integer.MAX_VALUE) {
+ newNativeSize = Integer.MAX_VALUE;
+ }
+ if (newNativeSize != mNativeSize) {
+ int delta = (int) (newNativeSize - mNativeSize);
+ if (delta > 0) {
+ VMRuntime.getRuntime().registerNativeAllocation(delta);
+ } else {
+ VMRuntime.getRuntime().registerNativeFree(-delta);
+ }
+ mNativeSize = newNativeSize;
+ }
+ }
}
/**
@@ -2545,7 +2566,7 @@
private void freeBuffer() {
if (mOwnsNativeParcelObject) {
- nativeFreeBuffer(mNativePtr);
+ updateNativeSize(nativeFreeBuffer(mNativePtr));
}
}
@@ -2553,6 +2574,7 @@
if (mNativePtr != 0) {
if (mOwnsNativeParcelObject) {
nativeDestroy(mNativePtr);
+ updateNativeSize(0);
}
mNativePtr = 0;
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 41de579..4535572 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -341,6 +341,10 @@
} finally {
uncryptFile.close();
}
+ // UNCRYPT_FILE needs to be readable by system server on bootup.
+ if (!UNCRYPT_FILE.setReadable(true, false)) {
+ Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath());
+ }
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
// If the package is on the /data partition, write the block map file
@@ -501,6 +505,25 @@
Log.e(TAG, "Error reading recovery log", e);
}
+ if (UNCRYPT_FILE.exists()) {
+ String filename = null;
+ try {
+ filename = FileUtils.readTextFile(UNCRYPT_FILE, 0, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading uncrypt file", e);
+ }
+
+ // Remove the OTA package on /data that has been (possibly
+ // partially) processed. (Bug: 24973532)
+ if (filename != null && filename.startsWith("/data")) {
+ if (UNCRYPT_FILE.delete()) {
+ Log.i(TAG, "Deleted: " + filename);
+ } else {
+ Log.e(TAG, "Can't delete: " + filename);
+ }
+ }
+ }
+
// Delete everything in RECOVERY_DIR except those beginning
// with LAST_PREFIX
String[] names = RECOVERY_DIR.list();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d601831..11effd0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1434,25 +1434,6 @@
}
/**
- * An app can use this method to check if it is currently allowed to change the network
- * state. In order to be allowed to do so, an app must first declare either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} or
- * {@link android.Manifest.permission#WRITE_SETTINGS} permission in its manifest. If it
- * is currently disallowed, it can prompt the user to grant it this capability through a
- * management UI by sending an Intent with action
- * {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}.
- *
- * @param context A context
- * @return true if the calling app can change the state of network, false otherwise.
- * @hide
- */
- public static boolean canChangeNetworkState(Context context) {
- int uid = Binder.getCallingUid();
- return Settings.isCallingPackageAllowedToChangeNetworkState(context, uid, Settings
- .getPackageNameForUid(context, uid), false);
- }
-
- /**
* System settings, containing miscellaneous system preferences. This
* table holds simple name/value pairs. There are convenience
* functions for accessing individual settings entries.
@@ -8384,7 +8365,7 @@
* write/modify system settings, as the condition differs for pre-M, M+, and
* privileged/preinstalled apps. If the provided uid does not match the
* callingPackage, a negative result will be returned. The caller is expected to have
- * either WRITE_SETTINGS or CHANGE_NETWORK_STATE permission declared.
+ * the WRITE_SETTINGS permission declared.
*
* Note: if the check is successful, the operation of this app will be updated to the
* current time.
@@ -8400,31 +8381,22 @@
/**
* Performs a strict and comprehensive check of whether a calling package is allowed to
* change the state of network, as the condition differs for pre-M, M+, and
- * privileged/preinstalled apps. If the provided uid does not match the
- * callingPackage, a negative result will be returned. The caller is expected to have
- * either of CHANGE_NETWORK_STATE or WRITE_SETTINGS permission declared.
- * @hide
- */
- public static boolean isCallingPackageAllowedToChangeNetworkState(Context context, int uid,
- String callingPackage, boolean throwException) {
- return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
- callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS,
- PM_CHANGE_NETWORK_STATE, false);
- }
-
- /**
- * Performs a strict and comprehensive check of whether a calling package is allowed to
- * change the state of network, as the condition differs for pre-M, M+, and
- * privileged/preinstalled apps. If the provided uid does not match the
- * callingPackage, a negative result will be returned. The caller is expected to have
- * either CHANGE_NETWORK_STATE or WRITE_SETTINGS permission declared.
+ * privileged/preinstalled apps. The caller is expected to have either the
+ * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
+ * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
+ * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
+ * permission and cannot be revoked. See http://b/23597341
*
- * Note: if the check is successful, the operation of this app will be updated to the
- * current time.
+ * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
+ * of this app will be updated to the current time.
* @hide
*/
public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid,
String callingPackage, boolean throwException) {
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid,
callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS,
PM_CHANGE_NETWORK_STATE, true);
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 954dcfb..cebb8f0 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -660,7 +660,7 @@
// and http://www.spaceroots.org/documents/ellipse/node22.html
// Maximum of 45 degrees per cubic Bezier segment
- int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
+ int numSegments = (int) Math.ceil(Math.abs(sweep * 4 / Math.PI));
double eta1 = start;
double cosTheta = Math.cos(theta);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 1c20cab..55cf56f 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -790,8 +790,14 @@
public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275;
/** Key code constant: put device to sleep unless a wakelock is held. */
public static final int KEYCODE_SOFT_SLEEP = 276;
+ /** Key code constant: Cut key. */
+ public static final int KEYCODE_CUT = 277;
+ /** Key code constant: Copy key. */
+ public static final int KEYCODE_COPY = 278;
+ /** Key code constant: Paste key. */
+ public static final int KEYCODE_PASTE = 279;
- private static final int LAST_KEYCODE = KEYCODE_SOFT_SLEEP;
+ private static final int LAST_KEYCODE = KEYCODE_PASTE;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index a105b40..18d7470 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -21,7 +21,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
-import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
@@ -112,7 +111,7 @@
// home screen. Therefore, we register the receiver as the current
// user not the one the context is for.
getContext().registerReceiverAsUser(mReceiver, android.os.Process.myUserHandle(),
- filter, null, mHandler);
+ filter, null, getHandler());
if (mAutoStart) {
@@ -194,9 +193,8 @@
// if the flipper is currently flipping automatically, and showNext() is called
// we should we should make sure to reset the timer
if (mRunning) {
- mHandler.removeMessages(FLIP_MSG);
- Message msg = mHandler.obtainMessage(FLIP_MSG);
- mHandler.sendMessageDelayed(msg, mFlipInterval);
+ removeCallbacks(mFlipRunnable);
+ postDelayed(mFlipRunnable, mFlipInterval);
}
super.showNext();
}
@@ -210,9 +208,8 @@
// if the flipper is currently flipping automatically, and showPrevious() is called
// we should we should make sure to reset the timer
if (mRunning) {
- mHandler.removeMessages(FLIP_MSG);
- Message msg = mHandler.obtainMessage(FLIP_MSG);
- mHandler.sendMessageDelayed(msg, mFlipInterval);
+ removeCallbacks(mFlipRunnable);
+ postDelayed(mFlipRunnable, mFlipInterval);
}
super.showPrevious();
}
@@ -241,10 +238,9 @@
if (running != mRunning) {
if (running) {
showOnly(mWhichChild, flipNow);
- Message msg = mHandler.obtainMessage(FLIP_MSG);
- mHandler.sendMessageDelayed(msg, mFlipInterval);
+ postDelayed(mFlipRunnable, mFlipInterval);
} else {
- mHandler.removeMessages(FLIP_MSG);
+ removeCallbacks(mFlipRunnable);
}
mRunning = running;
}
@@ -277,15 +273,11 @@
return mAutoStart;
}
- private final int FLIP_MSG = 1;
-
- private final Handler mHandler = new Handler() {
+ private final Runnable mFlipRunnable = new Runnable() {
@Override
- public void handleMessage(Message msg) {
- if (msg.what == FLIP_MSG) {
- if (mRunning) {
- showNext();
- }
+ public void run() {
+ if (mRunning) {
+ showNext();
}
}
};
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 45eee34..7f5e2133 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -56,7 +56,6 @@
private boolean mAttached;
- private final Handler mHandler = new Handler();
private float mMinutes;
private float mHour;
private boolean mChanged;
@@ -121,7 +120,7 @@
// home screen. Therefore, we register the receiver as the current
// user not the one the context is for.
getContext().registerReceiverAsUser(mIntentReceiver,
- android.os.Process.myUserHandle(), filter, null, mHandler);
+ android.os.Process.myUserHandle(), filter, null, getHandler());
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index ebb54ff..4d707e3 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -73,8 +73,6 @@
private OnChronometerTickListener mOnChronometerTickListener;
private StringBuilder mRecycle = new StringBuilder(8);
- private static final int TICK_WHAT = 2;
-
/**
* Initialize this Chronometer object.
* Sets the base to the current time.
@@ -259,20 +257,21 @@
if (running) {
updateText(SystemClock.elapsedRealtime());
dispatchChronometerTick();
- mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000);
+ postDelayed(mTickRunnable, 1000);
} else {
- mHandler.removeMessages(TICK_WHAT);
+ removeCallbacks(mTickRunnable);
}
mRunning = running;
}
}
-
- private Handler mHandler = new Handler() {
- public void handleMessage(Message m) {
+
+ private final Runnable mTickRunnable = new Runnable() {
+ @Override
+ public void run() {
if (mRunning) {
updateText(SystemClock.elapsedRealtime());
dispatchChronometerTick();
- sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000);
+ postDelayed(mTickRunnable, 1000);
}
}
};
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index 9e442f9..1df1643 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -60,18 +60,18 @@
if (mCalendar == null) {
mCalendar = Calendar.getInstance();
}
-
- mFormatChangeObserver = new FormatChangeObserver();
- getContext().getContentResolver().registerContentObserver(
- Settings.System.CONTENT_URI, true, mFormatChangeObserver);
-
- setFormat();
}
@Override
protected void onAttachedToWindow() {
mTickerStopped = false;
super.onAttachedToWindow();
+
+ mFormatChangeObserver = new FormatChangeObserver();
+ getContext().getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ setFormat();
+
mHandler = new Handler();
/**
@@ -95,6 +95,8 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mTickerStopped = true;
+ getContext().getContentResolver().unregisterContentObserver(
+ mFormatChangeObserver);
}
private void setFormat() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 018cc02..2fabe33 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,12 +16,6 @@
package android.widget;
-import java.text.BreakIterator;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-
import android.R;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -45,7 +39,6 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.ParcelableParcel;
@@ -113,6 +106,12 @@
import com.android.internal.util.Preconditions;
import com.android.internal.widget.EditableInputConnection;
+import java.text.BreakIterator;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
/**
* Helper class used by TextView to handle editable text views.
@@ -1005,8 +1004,7 @@
}
if (!handled && mTextActionMode != null) {
- // TODO: Fix dragging in extracted mode.
- if (touchPositionIsInSelection() && !mTextView.isInExtractedMode()) {
+ if (touchPositionIsInSelection()) {
// Start a drag
final int start = mTextView.getSelectionStart();
final int end = mTextView.getSelectionEnd();
@@ -2072,14 +2070,14 @@
if (shouldBlink()) {
mShowCursor = SystemClock.uptimeMillis();
if (mBlink == null) mBlink = new Blink();
- mBlink.removeCallbacks(mBlink);
- mBlink.postAtTime(mBlink, mShowCursor + BLINK);
+ mTextView.removeCallbacks(mBlink);
+ mTextView.postDelayed(mBlink, BLINK);
} else {
- if (mBlink != null) mBlink.removeCallbacks(mBlink);
+ if (mBlink != null) mTextView.removeCallbacks(mBlink);
}
}
- private class Blink extends Handler implements Runnable {
+ private class Blink implements Runnable {
private boolean mCancelled;
public void run() {
@@ -2087,20 +2085,20 @@
return;
}
- removeCallbacks(Blink.this);
+ mTextView.removeCallbacks(this);
if (shouldBlink()) {
if (mTextView.getLayout() != null) {
mTextView.invalidateCursorPath();
}
- postAtTime(this, SystemClock.uptimeMillis() + BLINK);
+ mTextView.postDelayed(this, BLINK);
}
}
void cancel() {
if (!mCancelled) {
- removeCallbacks(Blink.this);
+ mTextView.removeCallbacks(this);
mCancelled = true;
}
}
@@ -4262,10 +4260,14 @@
positionAtCursorOffset(offset, false);
}
+ /**
+ * @param offset Cursor offset. Must be in [-1, length].
+ * @param parentScrolled If the parent has been scrolled or not.
+ */
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
- mInWord = !getWordIteratorWithText().isBoundary(offset);
+ mInWord = (offset != -1) && !getWordIteratorWithText().isBoundary(offset);
}
@Override
@@ -4498,10 +4500,14 @@
positionAtCursorOffset(offset, false);
}
+ /**
+ * @param offset Cursor offset. Must be in [-1, length].
+ * @param parentScrolled If the parent has been scrolled or not.
+ */
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
- mInWord = !getWordIteratorWithText().isBoundary(offset);
+ mInWord = (offset != -1) && !getWordIteratorWithText().isBoundary(offset);
}
@Override
@@ -4868,9 +4874,8 @@
mEndHandle.showAtLocation(endOffset);
// No longer the first dragging motion, reset.
- if (!(mTextView.isInExtractedMode())) {
- startSelectionActionMode();
- }
+ startSelectionActionMode();
+
mDragAcceleratorActive = false;
mStartOffset = -1;
mSwitchedLines = false;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index b187c1c..9ebbe36 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -201,9 +201,6 @@
public Gallery(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
-
- mGestureDetector = new GestureDetector(context, this);
- mGestureDetector.setIsLongpressEnabled(true);
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Gallery, defStyleAttr, defStyleRes);
@@ -236,6 +233,16 @@
mGroupFlags |= FLAG_SUPPORT_STATIC_TRANSFORMATIONS;
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mGestureDetector == null) {
+ mGestureDetector = new GestureDetector(getContext(), this);
+ mGestureDetector.setIsLongpressEnabled(true);
+ }
+ }
+
/**
* Whether or not to callback on any {@link #getOnItemSelectedListener()}
* while the items are being flinged. If false, only the final selected item
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 245c7332..6e90baf 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -232,6 +232,8 @@
if (w != mDrawableWidth || h != mDrawableHeight) {
mDrawableWidth = w;
mDrawableHeight = h;
+ // updates the matrix, which is dependent on the bounds
+ configureBounds();
}
}
/* we invalidate the whole view in this case because it's very
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index ff2f22b..8008637 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -20,8 +20,6 @@
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.media.AudioManager;
-import android.os.Handler;
-import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -83,8 +81,6 @@
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 3000;
- private static final int FADE_OUT = 1;
- private static final int SHOW_PROGRESS = 2;
private final boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet;
@@ -373,12 +369,11 @@
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
- mHandler.sendEmptyMessage(SHOW_PROGRESS);
+ post(mShowProgress);
if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
- mHandler.removeMessages(FADE_OUT);
- Message msg = mHandler.obtainMessage(FADE_OUT);
- mHandler.sendMessageDelayed(msg, timeout);
+ removeCallbacks(mFadeOut);
+ postDelayed(mFadeOut, timeout);
}
}
@@ -395,7 +390,7 @@
if (mShowing) {
try {
- mHandler.removeMessages(SHOW_PROGRESS);
+ removeCallbacks(mShowProgress);
mWindowManager.removeView(mDecor);
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
@@ -404,21 +399,19 @@
}
}
- private final Handler mHandler = new Handler() {
+ private final Runnable mFadeOut = new Runnable() {
@Override
- public void handleMessage(Message msg) {
- int pos;
- switch (msg.what) {
- case FADE_OUT:
- hide();
- break;
- case SHOW_PROGRESS:
- pos = setProgress();
- if (!mDragging && mShowing && mPlayer.isPlaying()) {
- msg = obtainMessage(SHOW_PROGRESS);
- sendMessageDelayed(msg, 1000 - (pos % 1000));
- }
- break;
+ public void run() {
+ hide();
+ }
+ };
+
+ private final Runnable mShowProgress = new Runnable() {
+ @Override
+ public void run() {
+ int pos = setProgress();
+ if (!mDragging && mShowing && mPlayer.isPlaying()) {
+ postDelayed(mShowProgress, 1000 - (pos % 1000));
}
}
};
@@ -587,7 +580,7 @@
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
- mHandler.removeMessages(SHOW_PROGRESS);
+ removeCallbacks(mShowProgress);
}
@Override
@@ -615,7 +608,7 @@
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
- mHandler.sendEmptyMessage(SHOW_PROGRESS);
+ post(mShowProgress);
}
};
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index e241d4c..8c15cde 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -96,10 +96,16 @@
com.android.internal.R.styleable.Theme_quickContactBadgeOverlay);
styledAttributes.recycle();
+ setOnClickListener(this);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
if (!isInEditMode()) {
mQueryHandler = new QueryHandler(mContext.getContentResolver());
}
- setOnClickListener(this);
}
@Override
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index 9c44236..a55e77d 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -93,7 +93,6 @@
private static final float MAXIMUM_MAJOR_VELOCITY = 200.0f;
private static final float MAXIMUM_ACCELERATION = 2000.0f;
private static final int VELOCITY_UNITS = 1000;
- private static final int MSG_ANIMATE = 1000;
private static final int ANIMATION_FRAME_DURATION = 1000 / 60;
private static final int EXPANDED_FULL_OPEN = -10001;
@@ -123,7 +122,6 @@
private OnDrawerCloseListener mOnDrawerCloseListener;
private OnDrawerScrollListener mOnDrawerScrollListener;
- private final Handler mHandler = new SlidingHandler();
private float mAnimatedAcceleration;
private float mAnimatedVelocity;
private float mAnimationPosition;
@@ -553,8 +551,8 @@
mAnimationLastTime = now;
mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
mAnimating = true;
- mHandler.removeMessages(MSG_ANIMATE);
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurrentAnimationTime);
+ removeCallbacks(mSlidingRunnable);
+ postDelayed(mSlidingRunnable, ANIMATION_FRAME_DURATION);
stopTracking();
}
@@ -569,7 +567,7 @@
(mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth);
moveHandle((int) mAnimationPosition);
mAnimating = true;
- mHandler.removeMessages(MSG_ANIMATE);
+ removeCallbacks(mSlidingRunnable);
long now = SystemClock.uptimeMillis();
mAnimationLastTime = now;
mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
@@ -577,7 +575,7 @@
} else {
if (mAnimating) {
mAnimating = false;
- mHandler.removeMessages(MSG_ANIMATE);
+ removeCallbacks(mSlidingRunnable);
}
moveHandle(position);
}
@@ -709,8 +707,7 @@
} else {
moveHandle((int) mAnimationPosition);
mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
- mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE),
- mCurrentAnimationTime);
+ postDelayed(mSlidingRunnable, ANIMATION_FRAME_DURATION);
}
}
}
@@ -974,13 +971,10 @@
}
}
- private class SlidingHandler extends Handler {
- public void handleMessage(Message m) {
- switch (m.what) {
- case MSG_ANIMATE:
- doAnimation();
- break;
- }
+ private final Runnable mSlidingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ doAnimation();
}
- }
+ };
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index bcde315..ff10287 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -137,7 +137,13 @@
private boolean mShowCurrentUserTime;
- private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
+ private ContentObserver mFormatChangeObserver;
+ private class FormatChangeObserver extends ContentObserver {
+
+ public FormatChangeObserver(Handler handler) {
+ super(handler);
+ }
+
@Override
public void onChange(boolean selfChange) {
chooseFormat();
@@ -553,13 +559,18 @@
}
private void registerObserver() {
- final ContentResolver resolver = getContext().getContentResolver();
- if (mShowCurrentUserTime) {
- resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
- mFormatChangeObserver, UserHandle.USER_ALL);
- } else {
- resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
- mFormatChangeObserver);
+ if (isAttachedToWindow()) {
+ if (mFormatChangeObserver == null) {
+ mFormatChangeObserver = new FormatChangeObserver(getHandler());
+ }
+ final ContentResolver resolver = getContext().getContentResolver();
+ if (mShowCurrentUserTime) {
+ resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
+ mFormatChangeObserver, UserHandle.USER_ALL);
+ } else {
+ resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
+ mFormatChangeObserver);
+ }
}
}
@@ -568,8 +579,10 @@
}
private void unregisterObserver() {
- final ContentResolver resolver = getContext().getContentResolver();
- resolver.unregisterContentObserver(mFormatChangeObserver);
+ if (mFormatChangeObserver != null) {
+ final ContentResolver resolver = getContext().getContentResolver();
+ resolver.unregisterContentObserver(mFormatChangeObserver);
+ }
}
private void onTimeChanged() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1aeb9c93..13b1c4b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,8 @@
package android.widget;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
import android.R;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
@@ -118,14 +120,14 @@
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View;
-import android.view.ViewParent;
-import android.view.ViewStructure;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup.LayoutParams;
-import android.view.ViewRootImpl;
-import android.view.ViewTreeObserver;
import android.view.ViewHierarchyEncoder;
+import android.view.ViewParent;
+import android.view.ViewRootImpl;
+import android.view.ViewStructure;
+import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -153,8 +155,6 @@
import java.util.ArrayList;
import java.util.Locale;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-
/**
* Displays text to the user and optionally allows them to edit it. A TextView
* is a complete text editor, however the basic class is configured to not
@@ -1478,7 +1478,12 @@
}
}
}
+ } else if (mText instanceof Spannable) {
+ // Reset the selection.
+ stopTextActionMode();
+ Selection.setSelection((Spannable) mText, getSelectionStart(), getSelectionEnd());
}
+
if (mEditor.hasSelectionController()) {
mEditor.startSelectionActionMode();
}
@@ -5282,14 +5287,6 @@
mEditor.mCreatedWithASelection = false;
}
- // Phone specific code (there is no ExtractEditText on tablets).
- // ExtractEditText does not call onFocus when it is displayed, and mHasSelectionOnFocus can
- // not be set. Do the test here instead.
- if (isInExtractedMode() && hasSelection() && mEditor != null
- && mEditor.mTextActionMode == null && isShown() && hasWindowFocus()) {
- mEditor.startSelectionActionMode();
- }
-
unregisterForPreDraw();
return true;
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index 94e7ba1..65af7aa 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -96,7 +96,7 @@
// home screen. Therefore, we register the receiver as the current
// user not the one the context is for.
getContext().registerReceiverAsUser(mReceiver, android.os.Process.myUserHandle(),
- filter, null, mHandler);
+ filter, null, getHandler());
if (mAutoStart) {
// Automatically start when requested
@@ -173,10 +173,9 @@
if (running != mRunning) {
if (running) {
showOnly(mWhichChild, flipNow);
- Message msg = mHandler.obtainMessage(FLIP_MSG);
- mHandler.sendMessageDelayed(msg, mFlipInterval);
+ postDelayed(mFlipRunnable, mFlipInterval);
} else {
- mHandler.removeMessages(FLIP_MSG);
+ removeCallbacks(mFlipRunnable);
}
mRunning = running;
}
@@ -209,17 +208,12 @@
return mAutoStart;
}
- private final int FLIP_MSG = 1;
-
- private final Handler mHandler = new Handler() {
+ private final Runnable mFlipRunnable = new Runnable() {
@Override
- public void handleMessage(Message msg) {
- if (msg.what == FLIP_MSG) {
- if (mRunning) {
- showNext();
- msg = obtainMessage(FLIP_MSG);
- sendMessageDelayed(msg, mFlipInterval);
- }
+ public void run() {
+ if (mRunning) {
+ showNext();
+ postDelayed(mFlipRunnable, mFlipInterval);
}
}
};
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index 0255bdb..7d4f8ed 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.os.Handler;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -26,12 +25,11 @@
public class ZoomButton extends ImageButton implements OnLongClickListener {
- private final Handler mHandler;
private final Runnable mRunnable = new Runnable() {
public void run() {
if (hasOnClickListeners() && mIsInLongpress && isEnabled()) {
callOnClick();
- mHandler.postDelayed(this, mZoomSpeed);
+ postDelayed(this, mZoomSpeed);
}
}
};
@@ -53,7 +51,6 @@
public ZoomButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mHandler = new Handler();
setOnLongClickListener(this);
}
@@ -72,7 +69,7 @@
public boolean onLongClick(View v) {
mIsInLongpress = true;
- mHandler.post(mRunnable);
+ post(mRunnable);
return true;
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 70d5f62..b7b7400 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -373,6 +373,11 @@
int targetsToQuery = 0;
for (int i = 0, N = adapter.getDisplayResolveInfoCount(); i < N; i++) {
final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
+ if (adapter.getScore(dri) == 0) {
+ // A score of 0 means the app hasn't been used in some time;
+ // don't query it as it's not likely to be relevant.
+ continue;
+ }
final ActivityInfo ai = dri.getResolveInfo().activityInfo;
final Bundle md = ai.metaData;
final String serviceName = md != null ? convertServiceName(ai.packageName,
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index a14afa0..41aa9ca 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -114,7 +114,7 @@
return parcel ? parcel->dataCapacity() : 0;
}
-static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
+static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -122,7 +122,9 @@
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
+ return parcel->getOpenAshmemSize();
}
+ return 0;
}
static void android_os_Parcel_setDataPosition(JNIEnv* env, jclass clazz, jlong nativePtr, jint pos)
@@ -304,7 +306,7 @@
}
}
-static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
+static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -313,7 +315,9 @@
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
+ return parcel->getOpenAshmemSize();
}
+ return 0;
}
static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -546,12 +550,14 @@
return reinterpret_cast<jlong>(parcel);
}
-static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
parcel->freeData();
+ return parcel->getOpenAshmemSize();
}
+ return 0;
}
static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -589,12 +595,12 @@
return ret;
}
-static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
- jbyteArray data, jint offset, jint length)
+static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
+ jbyteArray data, jint offset, jint length)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel == NULL || length < 0) {
- return;
+ return 0;
}
jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
@@ -608,24 +614,26 @@
env->ReleasePrimitiveArrayCritical(data, array, 0);
}
+ return parcel->getOpenAshmemSize();
}
-static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
- jlong otherNativePtr, jint offset, jint length)
+static jlong android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
+ jlong otherNativePtr, jint offset, jint length)
{
Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
if (thisParcel == NULL) {
- return;
+ return 0;
}
Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
if (otherParcel == NULL) {
- return;
+ return thisParcel->getOpenAshmemSize();
}
status_t err = thisParcel->appendFrom(otherParcel, offset, length);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
+ return thisParcel->getOpenAshmemSize();
}
static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -718,7 +726,7 @@
{"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail},
{"nativeDataPosition", "(J)I", (void*)android_os_Parcel_dataPosition},
{"nativeDataCapacity", "(J)I", (void*)android_os_Parcel_dataCapacity},
- {"nativeSetDataSize", "(JI)V", (void*)android_os_Parcel_setDataSize},
+ {"nativeSetDataSize", "(JI)J", (void*)android_os_Parcel_setDataSize},
{"nativeSetDataPosition", "(JI)V", (void*)android_os_Parcel_setDataPosition},
{"nativeSetDataCapacity", "(JI)V", (void*)android_os_Parcel_setDataCapacity},
@@ -733,7 +741,7 @@
{"nativeWriteDouble", "(JD)V", (void*)android_os_Parcel_writeDouble},
{"nativeWriteString", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
- {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
+ {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
{"nativeReadBlob", "(J)[B", (void*)android_os_Parcel_readBlob},
@@ -751,12 +759,12 @@
{"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
- {"nativeFreeBuffer", "(J)V", (void*)android_os_Parcel_freeBuffer},
+ {"nativeFreeBuffer", "(J)J", (void*)android_os_Parcel_freeBuffer},
{"nativeDestroy", "(J)V", (void*)android_os_Parcel_destroy},
{"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
- {"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall},
- {"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom},
+ {"nativeUnmarshall", "(J[BII)J", (void*)android_os_Parcel_unmarshall},
+ {"nativeAppendFrom", "(JJII)J", (void*)android_os_Parcel_appendFrom},
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
{"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 148e7c1..f300741 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1715,12 +1715,12 @@
android:protectionLevel="signature|privileged" />
<!-- Allows applications to change network connectivity state.
- <p>Protection level: signature
+ <p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:description="@string/permdesc_changeNetworkState"
android:label="@string/permlab_changeNetworkState"
- android:protectionLevel="signature|preinstalled|appop|pre23" />
+ android:protectionLevel="normal" />
<!-- Allows an application to clear the caches of all installed
applications on the device.
@@ -2075,10 +2075,11 @@
<permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
android:protectionLevel="signature" />
- <!-- Allows an application to monitor changes in tablet mode.
+ <!-- Allows an application to query tablet mode state and monitor changes
+ in it.
<p>Not for use by third-party applications.
@hide -->
- <permission android:name="android.permission.TABLET_MODE_LISTENER"
+ <permission android:name="android.permission.TABLET_MODE"
android:protectionLevel="signature" />
<!-- Allows an application to request installing packages. Apps
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a58ec89..e7acf7e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Verkeerde PIN-kode."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Om te ontsluit, druk Kieslys dan 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Noodnommer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Geen diens nie."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Geen diens nie"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skerm gesluit."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Druk kieslys om oop te sluit of maak noodoproep."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Druk kieslys om oop te maak."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 80665a27..5bd9ccf 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን ኮድ።"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"የአደጋ ጊዜቁጥር"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ከአገልግሎት መስጫ ክልል ውጪ"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"ምንም አገልግሎት የለም"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ማሳያ መቆለፊያ።"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ለመክፈት ምናሌ ተጫንወይም የአደጋ ጊዜ ጥሪ አድርግ።"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ለመክፈት ምናሌ ተጫን"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 22eaabe..4dd5144 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -654,7 +654,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"رمز PIN غير صحيح."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"لإلغاء التأمين، اضغط على \"القائمة\" ثم على 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"رقم الطوارئ"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"لا تتوفر خدمة"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"لا خدمة"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"الشاشة مؤمّنة."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"اضغط على \"القائمة\" لإلغاء التأمين أو إجراء اتصال بالطوارئ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"اضغط على \"القائمة\" لإلغاء التأمين."</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 401e5b8..c828fc4 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Yanlış PIN kodu."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmaq üçün Menyu, sonra 0 basın."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Təcili nömrə"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Xidmət yoxdur."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Xidmət yoxdur"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran kilidlənib."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Təcili zəng kilidini açmaq və ya yerləşdirmək üçün Menyu düyməsinə basın."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Kilidi açmaq üçün Menyu düyməsinə basın."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6c3fa54..e474e7e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неправилен ПИН код."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"За да отключите, натиснете „Меню“ и после 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Спешен номер"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Няма покритие."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Няма покритие"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Екранът е заключен."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Натиснете „Меню“, за да отключите или да извършите спешно обаждане."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Натиснете „Меню“, за да отключите."</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 3f986a0..1f365b9 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ভুল পিন কোড৷"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"আনলক করতে, মেনু টিপুন তারপর ০ টিপুন৷"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"জরুরী নম্বর"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"কোনো পরিষেবা নেই৷"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"কোনো পরিষেবা নেই"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"স্ক্রীণ লক করা আছে৷"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"আনলক করতে বা জরুরী কল করতে মেনু টিপুন৷"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"আনলক করতে মেনু টিপুন৷"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 8d004df..046ca14 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Codi PIN incorrecte."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Per desbloquejar-lo, premeu Menú i després 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número d\'emergència"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Sense servei."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sense servei"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloquejada."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Premeu Menú per desbloquejar-lo o per fer una trucada d\'emergència."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Premeu Menú per desbloquejar."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 6ead72f..8f3976d 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Nesprávný kód PIN."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Číslo tísňové linky"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Žádný signál"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Žádný signál"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Obrazovka uzamčena."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Telefon odemknete stisknutím tlačítka Menu."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 346cdb1..82b550b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -219,7 +219,7 @@
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er slået FRA"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Indstillinger"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Assistance"</string>
- <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Forkert pinkode."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Tryk på Menu og dernæst på 0 for at låse op."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nødnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ingen dækning."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ingen dækning"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skærmen er låst."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryk på Menu for at låse op."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4e8b455..9ae5473b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Falscher PIN-Code"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Kein Dienst"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Kein Dienst"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 3f5e1af..56deed13 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Λανθασμένος κωδικός PIN."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Για ξεκλείδωμα, πατήστε το πλήκτρο Menu και, στη συνέχεια, το πλήκτρο 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Αριθμός έκτακτης ανάγκης"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Καμία υπηρεσία."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Δίκτυο μη διαθέσιμο"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Η οθόνη κλειδώθηκε."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 22179ed..53adc2b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Emergency number"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"No service"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"No service"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Screen locked."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Press Menu to unlock."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 22179ed..53adc2b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Emergency number"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"No service"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"No service"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Screen locked."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Press Menu to unlock."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 22179ed..53adc2b 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Emergency number"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"No service"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"No service"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Screen locked."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Press Menu to unlock."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 08f513b..25ba6db8 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, presiona el menú y luego 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Sin servicio"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sin servicio"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Presionar Menú para desbloquear."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 4d1500d..e3a4b66 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Sin servicio"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sin servicio"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 09454d6..41474a4 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Hädaabinumber"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Teenus puudub."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Teenus puudub"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekraan lukus."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Vajutage avamiseks või hädaabikõne tegemiseks menüünuppu"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Vajutage avamiseks menüüklahvi."</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 0815aeb..3a23fba 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kode okerra."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Desblokeatzeko, sakatu Menua eta, ondoren, 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Larrialdietarako zenbakia"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ez dago zerbitzurik."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ez dago zerbitzurik"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantaila blokeatuta dago."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Desblokeatzeko edo larrialdi-deia egiteko, sakatu Menua."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Desblokeatzeko, sakatu Menua."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 683afb4..ae6598b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"پین کد اشتباه است."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"برای بازگشایی قفل، منو را فشار دهید و سپس 0 را فشار دهید."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"شماره اضطراری"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"سرویسی وجود ندارد."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"بدون سرویس"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"صفحه قفل شد."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"برای بازگشایی قفل یا انجام تماس اضطراری روی منو فشار دهید."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"برای بازگشایی قفل روی منو فشار دهید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f8fb76f7..d8778a8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN-koodi väärin."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Poista lukitus painamalla Valikko-painiketta ja 0-näppäintä."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Hätänumero"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ei yhteyttä."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ei yhteyttä"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Näyttö lukittu."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Poista lukitus tai soita hätäpuhelu painamalla Valikko-painiketta."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Poista lukitus painamalla Valikko-painiketta."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 286459a..6f59ee0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"NIP erroné."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le téléphone, appuyez sur \"Menu\", puis sur 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numéro d\'urgence"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Aucun service"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Aucun service"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Écran verrouillé"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e4daeb1..9f08389 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Le code PIN est erroné."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le clavier, appuyez sur \"Menu\" puis sur 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numéro d\'urgence"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Aucun service"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Aucun service"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Écran verrouillé"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 2abd2be..21e6ee7 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, preme Menú e, a continuación, 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emerxencia"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Non hai servizo."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sen servizo"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Preme Menú para desbloquear ou realizar unha chamada de emerxencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Preme Menú para desbloquear."</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 8f46194..6dc0371 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ખોટો PIN કોડ."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"અનલૉક કરવા માટે, મેનૂ દબાવો તે પછી 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ઇમરજન્સિ નંબર"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"કોઈ સેવા નથી."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"કોઈ સેવા નથી"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"સ્ક્રીન લૉક કરી."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"અનલૉક કરવા માટે અથવા કટોકટીનો કૉલ કરવા માટે મેનૂ દબાવો."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 61b21bd..6b1a91f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत पिन कोड."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करने के लिए, मेनू दबाएं और फिर 0 दबाएं."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"आपातकालीन नंबर"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"कोई सेवा नहीं."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"कोई सेवा नहीं"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"स्क्रीन लॉक की गई है."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"अनलॉक करने के लिए मेनू दबाएं या आपातलकालीन कॉल करें."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"अनलॉक करने के लिए मेनू दबाएं."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 680dabd..67d7110 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -651,7 +651,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Netočan PIN kôd."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Za otključavanje pritisnite Izbornik pa 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Broj hitne službe"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nema usluge."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nema usluge"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Zaslon zaključan."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pritisnite Izbornik za otključavanje ili pozivanje hitnih službi."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pritisnite Izbornik za otključavanje."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index faed9b9..7e1f55b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Helytelen PIN kód."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"A feloldáshoz nyomja meg a Menü, majd a 0 gombot."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Segélyhívó szám"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nincs szolgáltatás."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nincs szolgáltatás"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"A képernyő le van zárva."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"A feloldáshoz nyomja meg a Menü gombot."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 9a0e603..9259c06 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Սխալ PIN ծածկագիր:"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Ապակողպման համար սեղմեք Ցանկ, ապա 0:"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Արտակարգ իրավիճակների հեռախոսահամար"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ծառայություն չկա:"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ծառայություն չկա"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Էկրանը կողպված է:"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Սեղմեք Ցանկ` ապակողպելու համար, կամ կատարեք արտակարգ իրավիճակների զանգ:"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 1bbd020..0f6cd3e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kode PIN salah."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka, tekan Menu lalu 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nomor darurat"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Tidak ada layanan."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Tidak ada layanan"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Layar terkunci."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tekan Menu untuk membuka atau melakukan panggilan darurat."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tekan Menu untuk membuka."</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 2a97573..29f7408 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Rangt PIN-númer."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Til að taka úr lás ýtirðu á valmyndartakkann og síðan 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Neyðarnúmer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ekkert símasamband."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ekkert símasamband"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skjár læstur."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Ýttu á valmyndartakkann til að taka úr lás eða hringja neyðarsímtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Ýttu á valmyndartakkann til að taka úr lás."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c56b41b..ab541ea 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Codice PIN errato."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Per sbloccare, premi Menu, poi 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numero di emergenza"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nessun servizio."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nessun servizio"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Schermo bloccato."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Premi Menu per sbloccare."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 26fe698..de19821 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"קוד PIN שגוי"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"כדי לבטל את הנעילה, לחץ על \'תפריט\' ולאחר מכן על 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"מספר חירום"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"אין שירות"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"אין שירות"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"המסך נעול."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"לחץ על \'תפריט\' כדי לבטל את הנעילה או כדי לבצע שיחת חירום."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 6b1c833..45e82ac 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PINコードが正しくありません。"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"MENU、0キーでロック解除"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急通報番号"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"通信サービスはありません"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"通信サービスはありません"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"画面ロック中"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"MENUキーでロック解除(または緊急通報)"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"MENUキーでロック解除"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index e1221c4..7900f83 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"არასწორი PIN კოდი."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"განბლოკვისათვის დააჭირეთ მენიუს და შემდეგ 0-ს."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"გადაუდებელი დახმარების ნომრები"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"სერვისი არ არის."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"სერვისი არ არის"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ეკრანი დაბლოკილია."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"განბლოკვისთვის ან გადაუდებელი ზარისთვის დააჭირეთ მენიუს."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"განბლოკვისთვის დააჭირეთ მენიუს."</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index b3172ff..23ec612 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Қате PIN код"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Бекітпесін ашу үшін Мәзір, одан кейін 0 пернесін түртіңіз."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Төтенше жағдай нөмірі"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Қызмет көрсетілмейді."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Қызмет жоқ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран бекітілген."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Бекітпесін ашу үшін немесе төтенше қоңырауды табу үшін Мәзір тармағын басыңыз."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Ашу үшін Мәзір пернесін басыңыз."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 822a303..8ffa8b8 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"កូដ PIN មិនត្រឹមត្រូវ។"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ដើម្បីដោះសោ ចុចម៉ឺនុយ បន្ទាប់មក 0 ។"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"លេខពេលអាសន្ន"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"គ្មានសេវា"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"គ្មានសេវាទេ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ចាក់អេក្រង់។"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ចុចម៉ឺនុយ ដើម្បីដោះសោ ឬហៅពេលអាសន្ន។"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 73d7ffc..a840c7e 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ತಪ್ಪಾದ ಪಿನ್ ಕೋಡ್."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ಅನ್ಲಾಕ್ ಮಾಡಲು, ಮೆನು ನಂತರ 0 ಒತ್ತಿರಿ."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ತುರ್ತು ಸಂಖ್ಯೆ"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ಸೇವೆ ಇಲ್ಲ."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"ಯಾವುದೇ ಸೇವೆಯಿಲ್ಲ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ಪರದೆ ಲಾಕ್ ಆಗಿದೆ."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ ಇಲ್ಲವೇ ತುರ್ತು ಕರೆಯನ್ನು ಮಾಡಿ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0d76af2..59b0214 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 코드가 잘못되었습니다."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"잠금해제하려면 메뉴를 누른 다음 0을 누릅니다."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"비상 전화번호"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"서비스 불가"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"서비스 불가"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"화면 잠김"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"잠금해제하려면 메뉴를 누르세요."</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 22399b0..59c34dc 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN-код туура эмес."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Кулпусун ачуу үчүн, Менюна андан соң 0 баскычын басыңыз."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Шашылыш чалуу номери"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Байланыш жок."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Байланыш жок"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран кулпуланды."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Кулпусун ачып же Шашылыш чалуу аткаруу үчүн менюну басыңыз."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Бөгөттөн чыгаруу үчүн Менюну басыңыз."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 1d39230..f131914 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ເພື່ອປົດລັອກ, ໃຫ້ກົດເມນູ ແລ້ວກົດ 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ເບີໂທສຸກເສີນ"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ບໍ່ມີບໍລິການ."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"ບໍ່ມີບໍລິການ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ລັອກໜ້າຈໍແລ້ວ."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ກົດ ເມນູ ເພື່ອປົດລັອກ ຫຼື ໂທອອກຫາເບີສຸກເສີນ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index dbb8fbb..536a107 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Neteisingas PIN kodas."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Jei norite atrakinti, paspauskite „Meniu“ ir 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Pagalbos numeris"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nėra paslaugos."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nėra paslaugos"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekranas užrakintas."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Paspauskite „Meniu“, kad atrakintumėte ar skambintumėte pagalbos numeriu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Paspauskite „Meniu“, jei norite atrakinti."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index eaf7b46..288493a 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -651,7 +651,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kods nav pareizs."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Lai atbloķētu, nospiediet Izvēlne, pēc tam 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Ārkārtas numurs"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nav pakalpojuma."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nav pakalpojuma"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekrāns ir bloķēts."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Nospiediet Izvēlne, lai atbloķētu, vai veiciet ārkārtas zvanu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Lai atbloķētu, nospiediet vienumu Izvēlne."</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 17e0d49..eab72bf 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Погрешен ПИН код."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"За да го отклучите, притиснете „Мени“ и потоа „0“."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Број за итни случаи"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Нема услуга."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Нема услуга"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Екранот е заклучен."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Притисни „Мени“ да се отклучи или да направи итен повик."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Притиснете „Мени“ за да се отклучи."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 3df3c86..caaedda 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"പിൻ കോഡ് തെറ്റാണ്."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"അൺലോക്ക് ചെയ്യുന്നതിന് മെനു, 0 എന്നിവ അമർത്തുക."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"അടിയന്തര നമ്പർ"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"സേവനമില്ല"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"സേവനമില്ല"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"സ്ക്രീൻ ലോക്കുചെയ്തു."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"അൺലോക്ക് ചെയ്യുന്നതിനായി മെനു അമർത്തുക അല്ലെങ്കിൽ അടിയന്തര കോൾ വിളിക്കുക."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index ff8cc4d..c02760d 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Буруу PIN код."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Тайлах бол Цэсийг дараад 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Яаралтай дугаар"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Үйлчилгээ байхгүй."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Үйлчилгээ байхгүй"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Дэлгэц түгжигдсэн."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Яаралтай дуудлага хийх буюу эсвэл түгжээг тайлах бол цэсийг дарна уу."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Тайлах бол цэсийг дарна уу."</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 45bc3c5..d557661 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"अयोग्य पिन कोड."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करण्यासाठी, मेनू दाबा नंतर 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"आणीबाणीचा नंबर"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"सेवा नाही."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"सेवा नाही"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"स्क्रीन लॉक केली."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"अनलॉक करण्यासाठी मेनू दाबा किंवा आणीबाणीचा कॉल करा."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"अनलॉक करण्यासाठी मेनू दाबा."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1508d0e..8e5113b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kod PIN salah."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka kunci, tekan Menu, kemudian 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nombor kecemasan"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Tiada perkhidmatan."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Tiada perkhidmatan"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skrin dikunci."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tekan Menu untuk menyahsekat atau membuat panggilan kecemasan."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tekan Menu untuk membuka kunci."</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index a09093f..427e844 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ပင်နံပါတ်မှားနေပါသည်"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"သော့ဖွင့်ရန် Menu ထိုနောက်0ကိုနှိပ်ပါ"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"အရေးပေါ်နံပါတ်"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ဆားဗစ် မရှိပါ"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"ဝန်ဆောင်မှု မရှိပါ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"မျက်နှာပြင်အားသော့ချထားသည်"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ဖွင့်ရန်သို့မဟုတ်အရေးပေါ်ခေါ်ဆိုခြင်းပြုလုပ်ရန် မီနူးကိုနှိပ်ပါ"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"မီးနူးကို နှိပ်ခြင်းဖြင့် သော့ဖွင့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c2d2b80..e231e2a 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Feil personlig kode."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"For å låse opp, trykk på menyknappen og deretter 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nødnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ingen tjeneste."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ingen dekning"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skjermen er låst"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Trykk på menyknappen for å låse opp."</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index e4b6c22..8181f6c 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत PIN कोड।"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"अनलक गर्न मेनु थिच्नुहोस् र त्यसपछि ० थिच्नुहोस्।"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"आपतकालीन नम्बर"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"सेवा छैन।"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"कुनै सेवा छैन"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"स्क्रिन लक गरिएको।"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"अनलक वा आपतकालीन कल गर्न मेनु थिच्नुहोस्।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"अनलक गर्न मेनु थिच्नुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b208f48..361a816 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Onjuiste pincode."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Alarmnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Geen service"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Geen service"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Scherm vergrendeld."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Druk op \'Menu\' om te ontgrendelen."</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 8272d71..0b80c4a 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ਗ਼ਲਤ PIN ਕੋਡ।"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ਅਨਲੌਕ ਕਰਨ ਲਈ, ਪਹਿਲਾਂ ਮੀਨੂ ਫਿਰ 0 ਦਬਾਓ।"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ਐਮਰਜੈਂਸੀ ਨੰਬਰ"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ।"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ਸਕ੍ਰੀਨ ਲੌਕ ਕੀਤੀ।"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਐਮਰਜੈਂਸੀ ਕਾਲ ਕਰੋ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 34d26dc..d72281b 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Błędny kod PIN"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numer alarmowy"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Brak usługi"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Brak usługi"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran zablokowany."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Naciśnij Menu, aby odblokować."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bd1b2f0..daf17ef 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Sem serviço."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sem serviço"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Tela bloqueada."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pressione Menu para desbloquear."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 897dcd6..b98a1cd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, prima Menu e, em seguida, 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nenhum serviço"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sem rede móvel"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecrã bloqueado."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Prima Menu para desbloquear."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bd1b2f0..daf17ef 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Sem serviço."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Sem serviço"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Tela bloqueada."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pressione Menu para desbloquear."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 428e139..6c576ad 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -651,7 +651,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsaţi Meniu, apoi 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgență"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Fără serviciu."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Fără semnal"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecranul este blocat."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsaţi Meniu pentru deblocare."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 525e088..15cbe4a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неверный PIN-код."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Для разблокировки нажмите \"Меню\", а затем 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Экстренная служба"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Нет сигнала"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Нет сигнала"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран заблокирован."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Для разблокировки нажмите \"Меню\"."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 0135884..5e6cfcd 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"වැරදි PIN කේතයකි."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"අගුළු ඇරීමට, මෙනුව ඔබා පසුව 0 ද ඔබන්න."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"හදිසි ඇමතුම් අංකය"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"සේවාව නැත."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"සේවාව නැත"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"තිරය අගුළු දමා ඇත."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"අගුළු හැරීමට මෙනුව ඔබන්න හෝ හදිසි ඇමතුම ලබාගන්න."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"අගුළු හැරීමට මෙනු ඔබන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 5bd6867..dd3cbca 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Nesprávny kód PIN."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Ak chcete telefón odomknúť, stlačte Menu a následne 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Číslo tiesňového volania"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Žiadny signál"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Žiadny signál"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Obrazovka je uzamknutá."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Ak chcete odomknúť telefón alebo uskutočniť tiesňové volanie, stlačte Menu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Telefón odomknete stlačením tlačidla Menu."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 02a748b3..5c554ab 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Napačna koda PIN."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Če želite telefon odkleniti, pritisnite meni in nato 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Številka za klic v sili"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ni storitve."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ni signala"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Zaslon je zaklenjen."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Če želite odkleniti napravo ali opraviti klic v sili, pritisnite meni."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Če želite odkleniti, pritisnite meni."</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 128dc23..45a4c68 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kodi PIN është i pasaktë."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Për të shkyçur, shtyp \"Meny\" pastaj 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numri i urgjencës"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Nuk ka shërbim."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Nuk ka shërbim"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekrani është i kyçur."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Shtyp \"Meny\" për të shkyçur ose për të kryer telefonatë urgjence."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Shtyp \"Meny\" për të shkyçur."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index aec317e..71538de 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -651,7 +651,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN кôд је нетачан."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Да бисте откључали, притисните „Мени“, а затим 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Број за хитне случајеве"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Нема услуге."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Мобилна мрежа није доступна"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Екран је закључан."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Притисните „Мени“ да бисте откључали телефон или упутите хитан позив."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Притисните „Мени“ за откључавање."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1032768..49a3862 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Fel PIN-kod."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Tryck på Menu och sedan på 0 om du vill låsa upp."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nödsamtalsnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ingen tjänst."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ingen tjänst"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skärmen har låsts."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryck på Menu om du vill låsa upp eller ringa nödsamtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Menu om du vill låsa upp."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 6cc7b13..1d54bcf 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Msimbo wa PIN usio sahihi."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Ili kufungua, bofya Menyu kisha 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nambari ya dharura"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Hakuna huduma"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Hakuna huduma"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"skrini imefungwa."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Bonyeza Menyu ili kufungua au kupiga simu ya dharura."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Bonyeza Menyu ili kufungua."</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 1cdd590..e520908 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"தவறான பின் குறியீடு."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"தடைநீக்க, மெனுவை அழுத்தி பின்பு 0 ஐ அழுத்தவும்."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"அவசர எண்"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"சேவை இல்லை."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"சேவை இல்லை"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"திரை பூட்டப்பட்டுள்ளது."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"தடைநீக்க மெனுவை அழுத்தவும் அல்லது அவசர அழைப்பை மேற்கொள்ளவும்."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"திறக்க, மெனுவை அழுத்தவும்."</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 11c382e..fd3d5f2 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"చెల్లని పిన్ కోడ్."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"అన్లాక్ చేయడానికి, మెను ఆపై 0ని నొక్కండి."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"అత్యవసర నంబర్"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"సేవ లేదు."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"సేవ లేదు"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"స్క్రీన్ లాక్ చేయబడింది."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"అన్లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెను నొక్కండి."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"అన్లాక్ చేయడానికి మెను నొక్కండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d061873..4b4af30 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"รหัส PIN ไม่ถูกต้อง"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"หากต้องการปลดล็อก กด เมนู ตามด้วย 0"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"หมายเลขฉุกเฉิน"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ไม่มีบริการ"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"ไม่มีบริการ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"หน้าจอถูกล็อก"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"กด เมนู เพื่อปลดล็อกหรือโทรฉุกเฉิน"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"กด เมนู เพื่อปลดล็อก"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index d87d7a9..afc71b9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Maling PIN code."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Upang i-unlock, pindutin ang Menu pagkatapos ay 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Pang-emergency na numero"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Walang serbisyo."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Walang serbisyo"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Naka-lock ang screen."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pindutin ang Menu upang i-unlock o magsagawa ng pang-emergency na tawag."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pindutin ang Menu upang i-unlock."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a5917e5..7cbf3d2 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Yanlış PIN kodu."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Acil durum numarası"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Hizmet yok."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Hizmet yok"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran kilitli."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Kilidi açmak için Menü\'ye basın."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6f77952..9c4f867 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -652,7 +652,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неправильний PIN-код."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Щоб розбл., натисн. меню та 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Аварійний номер"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Зв’язку немає."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Немає зв’язку"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Екран заблоков."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Натис. меню, щоб розбл. чи зробити авар. виклик."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Натисн. меню, щоб розбл."</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 55e6efd..dd8aeca 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"غلط PIN کوڈ۔"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"غیر مقفل کرنے کیلئے، مینو پھر 0 دبائیں۔"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ہنگامی نمبر"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"کوئی سروس نہیں ہے۔"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"کوئی سروس نہیں ہے"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"اسکرین مقفل ہے۔"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"غیر مقفل کرنے کیلئے مینو دبائیں یا ہنگامی کال کریں۔"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"غیر مقفل کرنے کیلئے مینو دبائیں۔"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index c76df70..ee7da4e 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Noto‘g‘ri PIN-kod."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Qulfni ochish uchun avval \"Menu\"ni, so‘ngra 0 raqamini bosing."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Favqulodda raqam"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Aloqa yo‘q."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Xizmat mavjud emas"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran qulflangan."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Qulfdan chiqarish yoki favqulodda qo‘ng‘iroqni amalga oshirish uchun \"Menyu\"ni bosing."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Qulfni ochish uchun \"Menyu\"ga bosing."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a74e10e..5ae3e1e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Mã PIN không chính xác."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Để mở khóa, hãy nhấn vào Menu sau đó nhấn 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Số khẩn cấp"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Không có dịch vụ nào."</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Không có dịch vụ nào"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Màn hình đã khóa."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Nhấn vào Menu để mở khóa hoặc thực hiện cuộc gọi khẩn cấp."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Nhấn vào Menu để mở khóa."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 57c91a8..602f607 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -650,7 +650,8 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN码有误。"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"要解锁,请先按 MENU 再按 0。"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"急救或报警电话"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"无服务。"</string>
+ <!-- no translation found for lockscreen_carrier_default (6169005837238288522) -->
+ <skip />
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"屏幕已锁定。"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按 Menu 解锁或进行紧急呼救。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按 MENU 解锁。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 5b6b456..41952a7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按選單鍵,然後按 0。"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急電話號碼"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"沒有服務。"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"沒有服務"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"螢幕已鎖定。"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按選單鍵解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按選單鍵解鎖。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 387f8bb..48ea636 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按 Menu 鍵,然後按 0。"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急電話號碼"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"沒有服務。"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"沒有服務"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"螢幕已鎖定。"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按下 [Menu] 解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按下 Menu 鍵解鎖。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a9b6d14..f597e5d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -650,7 +650,7 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Ikhodi ye-PIN engalungile!"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Ukuvula, chofoza Menyu bese 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Inombolo ephuthumayo"</string>
- <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Ayikho isevisi"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Ayikho isevisi"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Isikrini sivaliwe."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Chofoza Menyu ukuvula noma ukwenza ikholi ephuthumayo."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Chofoza Menyu ukuvula."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 90306fd..8e36eb0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1832,6 +1832,9 @@
<enum name="KEYCODE_MEDIA_STEP_FORWARD" value="274" />
<enum name="KEYCODE_MEDIA_STEP_BACKWARD" value="275" />
<enum name="KEYCODE_SOFT_SLEEP" value="276" />
+ <enum name="KEYCODE_CUT" value="277" />
+ <enum name="KEYCODE_COPY" value="278" />
+ <enum name="KEYCODE_PASTE" value="279" />
</attr>
<!-- ***************************************************************** -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1c8062d..d20b09f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2359,4 +2359,8 @@
<!-- The fraction of display size (lower of height and width) that will be used to determine
the default minimal size for resizeable tasks. -->
<fraction name="config_displayFractionForDefaultMinimalSizeOfResizeableTask">25%</fraction>
+
+ <!-- The BT name of the keyboard packaged with the device. If this is defined, SystemUI will
+ automatically try to pair with it when the device exits tablet mode. -->
+ <string translatable="false" name="config_packagedKeyboardName"></string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3ce8ec5..6f239e6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2333,4 +2333,6 @@
<java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
<java-symbol type="integer" name="config_windowResizingBackgroundColorARGB" />
+
+ <java-symbol type="string" name="config_packagedKeyboardName" />
</resources>
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index f10ba96..2a10bdd 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -152,11 +152,11 @@
# key 130 "KEY_PROPS"
# key 131 "KEY_UNDO"
# key 132 "KEY_FRONT"
-# key 133 "KEY_COPY"
+key 133 COPY
# key 134 "KEY_OPEN"
-# key 135 "KEY_PASTE"
+key 135 PASTE
# key 136 "KEY_FIND"
-# key 137 "KEY_CUT"
+key 137 CUT
# key 138 "KEY_HELP"
key 139 MENU
key 140 CALCULATOR
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index e235a99..3ed6a78 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -379,6 +379,7 @@
r, theme, attrs, R.styleable.AnimatedStateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
updateStateFromTypedArray(a);
+ updateDensity(r);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 521c74b..6bf3afd 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -291,6 +291,7 @@
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimationDrawable_visible);
updateStateFromTypedArray(a);
+ updateDensity(r);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 1f7d996..ac72734 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -29,6 +29,7 @@
import android.graphics.Rect;
import android.graphics.PorterDuff.Mode;
import android.os.SystemClock;
+import android.util.DisplayMetrics;
import android.util.LayoutDirection;
import android.util.SparseArray;
import android.view.View;
@@ -581,6 +582,17 @@
return mCurrDrawable;
}
+ /**
+ * Updates the source density based on the resources used to inflate
+ * density-dependent values. Implementing classes should call this method
+ * during inflation.
+ *
+ * @param res the resources used to inflate density-dependent values
+ */
+ final void updateDensity(Resources res) {
+ mDrawableContainerState.updateDensity(res);
+ }
+
@Override
public void applyTheme(Theme theme) {
mDrawableContainerState.applyTheme(theme);
@@ -638,22 +650,22 @@
*/
public abstract static class DrawableContainerState extends ConstantState {
final DrawableContainer mOwner;
- final Resources mRes;
- SparseArray<ConstantStateFuture> mDrawableFutures;
-
+ Resources mSourceRes;
+ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
int mChangingConfigurations;
int mChildrenChangingConfigurations;
+ SparseArray<ConstantStateFuture> mDrawableFutures;
Drawable[] mDrawables;
int mNumChildren;
boolean mVariablePadding = false;
- boolean mPaddingChecked;
+ boolean mCheckedPadding;
Rect mConstantPadding;
boolean mConstantSize = false;
- boolean mComputedConstantSize;
+ boolean mCheckedConstantSize;
int mConstantWidth;
int mConstantHeight;
int mConstantMinimumWidth;
@@ -689,7 +701,13 @@
DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
Resources res) {
mOwner = owner;
- mRes = res != null ? res : orig != null ? orig.mRes : null;
+
+ final Resources sourceRes = res != null ? res : (orig != null ? orig.mSourceRes : null);
+ mSourceRes = sourceRes;
+
+ final int densityDpi = sourceRes == null ? 0 : sourceRes.getDisplayMetrics().densityDpi;
+ final int sourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ mDensity = sourceDensity;
if (orig != null) {
mChangingConfigurations = orig.mChangingConfigurations;
@@ -713,21 +731,30 @@
mHasTintList = orig.mHasTintList;
mHasTintMode = orig.mHasTintMode;
- // Cloning the following values may require creating futures.
- mConstantPadding = orig.getConstantPadding();
- mPaddingChecked = true;
+ if (orig.mDensity == sourceDensity) {
+ if (orig.mCheckedPadding) {
+ mConstantPadding = new Rect(orig.mConstantPadding);
+ mCheckedPadding = true;
+ }
- mConstantWidth = orig.getConstantWidth();
- mConstantHeight = orig.getConstantHeight();
- mConstantMinimumWidth = orig.getConstantMinimumWidth();
- mConstantMinimumHeight = orig.getConstantMinimumHeight();
- mComputedConstantSize = true;
+ if (orig.mCheckedConstantSize) {
+ mConstantWidth = orig.mConstantWidth;
+ mConstantHeight = orig.mConstantHeight;
+ mConstantMinimumWidth = orig.mConstantMinimumWidth;
+ mConstantMinimumHeight = orig.mConstantMinimumHeight;
+ mCheckedConstantSize = true;
+ }
+ }
- mOpacity = orig.getOpacity();
- mCheckedOpacity = true;
+ if (orig.mCheckedOpacity) {
+ mOpacity = orig.mOpacity;
+ mCheckedOpacity = true;
+ }
- mStateful = orig.isStateful();
- mCheckedStateful = true;
+ if (orig.mCheckedStateful) {
+ mStateful = orig.mStateful;
+ mCheckedStateful = true;
+ }
// Postpone cloning children and futures until we're absolutely
// sure that we're done computing values for the original state.
@@ -783,8 +810,8 @@
mCheckedOpacity = false;
mConstantPadding = null;
- mPaddingChecked = false;
- mComputedConstantSize = false;
+ mCheckedPadding = false;
+ mCheckedConstantSize = false;
return pos;
}
@@ -863,6 +890,31 @@
return changed;
}
+ /**
+ * Updates the source density based on the resources used to inflate
+ * density-dependent values.
+ *
+ * @param res the resources used to inflate density-dependent values
+ */
+ final void updateDensity(Resources res) {
+ if (mSourceRes != null) {
+ mSourceRes = res;
+ }
+
+ // The density may have changed since the last update (if any). Any
+ // dimension-type attributes will need their default values scaled.
+ final int densityDpi = res.getDisplayMetrics().densityDpi;
+ final int newSourceDensity = densityDpi == 0 ?
+ DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ final int oldSourceDensity = mDensity;
+ mDensity = newSourceDensity;
+
+ if (oldSourceDensity != newSourceDensity) {
+ mCheckedConstantSize = false;
+ mCheckedPadding = false;
+ }
+ }
+
final void applyTheme(Theme theme) {
if (theme != null) {
createAllFutures();
@@ -877,6 +929,8 @@
mChildrenChangingConfigurations |= drawables[i].getChangingConfigurations();
}
}
+
+ updateDensity(theme.getResources());
}
}
@@ -941,7 +995,7 @@
return null;
}
- if ((mConstantPadding != null) || mPaddingChecked) {
+ if ((mConstantPadding != null) || mCheckedPadding) {
return mConstantPadding;
}
@@ -961,7 +1015,7 @@
}
}
- mPaddingChecked = true;
+ mCheckedPadding = true;
return (mConstantPadding = r);
}
@@ -974,7 +1028,7 @@
}
public final int getConstantWidth() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -982,7 +1036,7 @@
}
public final int getConstantHeight() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -990,7 +1044,7 @@
}
public final int getConstantMinimumWidth() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -998,7 +1052,7 @@
}
public final int getConstantMinimumHeight() {
- if (!mComputedConstantSize) {
+ if (!mCheckedConstantSize) {
computeConstantSize();
}
@@ -1006,7 +1060,7 @@
}
protected void computeConstantSize() {
- mComputedConstantSize = true;
+ mCheckedConstantSize = true;
createAllFutures();
@@ -1146,10 +1200,10 @@
*/
public Drawable get(DrawableContainerState state) {
final Drawable result;
- if (state.mRes == null) {
+ if (state.mSourceRes == null) {
result = mConstantState.newDrawable();
} else {
- result = mConstantState.newDrawable(state.mRes);
+ result = mConstantState.newDrawable(state.mSourceRes);
}
result.setLayoutDirection(state.mLayoutDirection);
result.setCallback(state.mOwner);
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index b01c643..4ce52d1 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -88,7 +88,13 @@
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
+ updateDensity(r);
+ inflateChildElements(r, parser, attrs, theme);
+ }
+
+ private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+ Theme theme) throws XmlPullParserException, IOException {
int type;
int low = 0;
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 758410a..64a9eb5 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -110,6 +110,7 @@
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.StateListDrawable_visible);
updateStateFromTypedArray(a);
+ updateDensity(r);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 5988781..e161f3d 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -222,11 +222,14 @@
// caching the bitmap by default is allowed.
private boolean mAllowCaching = true;
+ /** The density of the display on which this drawable will be rendered. */
+ private int mTargetDensity;
+
// Given the virtual display setup, the dpi can be different than the inflation's dpi.
// Therefore, we need to scale the values we got from the getDimension*().
private int mDpiScaledWidth = 0;
private int mDpiScaledHeight = 0;
- private Insets mDpiScaleInsets = Insets.NONE;
+ private Insets mDpiScaledInsets = Insets.NONE;
// Temp variable, only for saving "new" operation at the draw() time.
private final float[] mTmpFloats = new float[9];
@@ -234,17 +237,37 @@
private final Rect mTmpBounds = new Rect();
public VectorDrawable() {
- this(null, null);
+ this(new VectorDrawableState(), null);
}
+ /**
+ * The one constructor to rule them all. This is called by all public
+ * constructors to set the state and initialize local properties.
+ */
private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
- if (state == null) {
- mVectorState = new VectorDrawableState();
+ mVectorState = state;
+
+ updateLocalState(res);
+ }
+
+ /**
+ * Initializes local dynamic properties from state. This should be called
+ * after significant state changes, e.g. from the One True Constructor and
+ * after inflating or applying a theme.
+ *
+ * @param res resources of the context in which the drawable will be
+ * displayed, or {@code null} to use the constant state defaults
+ */
+ private void updateLocalState(Resources res) {
+ if (res != null) {
+ final int densityDpi = res.getDisplayMetrics().densityDpi;
+ mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
} else {
- mVectorState = state;
- mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ mTargetDensity = mVectorState.mVPathRenderer.mSourceDensity;
}
- updateDimensionInfo(res, false);
+
+ mTintFilter = updateTintFilter(mTintFilter, mVectorState.mTint, mVectorState.mTintMode);
+ computeVectorSize();
}
@Override
@@ -416,55 +439,38 @@
/** @hide */
@Override
public Insets getOpticalInsets() {
- return mDpiScaleInsets;
+ return mDpiScaledInsets;
}
/*
- * Update the VectorDrawable dimension since the res can be in different Dpi now.
- * Basically, when a new instance is created or getDimension() is called, we should update
- * the current VectorDrawable's dimension information.
- * Only after updateStateFromTypedArray() is called, we should called this and update the
- * constant state's dpi info, i.e. updateConstantStateDensity == true.
+ * Update local dimensions to adjust for a target density that may differ
+ * from the source density against which the constant state was loaded.
*/
- void updateDimensionInfo(@Nullable Resources res, boolean updateConstantStateDensity) {
- if (res != null) {
- final int densityDpi = res.getDisplayMetrics().densityDpi;
- final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ void computeVectorSize() {
+ final VPathRenderer pathRenderer = mVectorState.mVPathRenderer;
+ final Insets opticalInsets = pathRenderer.mOpticalInsets;
- if (updateConstantStateDensity) {
- mVectorState.mVPathRenderer.mTargetDensity = targetDensity;
- } else {
- final int constantStateDensity = mVectorState.mVPathRenderer.mTargetDensity;
- if (targetDensity != constantStateDensity && constantStateDensity != 0) {
- mDpiScaledWidth = Bitmap.scaleFromDensity(
- (int) mVectorState.mVPathRenderer.mBaseWidth, constantStateDensity,
- targetDensity);
- mDpiScaledHeight = Bitmap.scaleFromDensity(
- (int) mVectorState.mVPathRenderer.mBaseHeight,constantStateDensity,
- targetDensity);
- final int left = Bitmap.scaleFromDensity(
- mVectorState.mVPathRenderer.mOpticalInsets.left, constantStateDensity,
- targetDensity);
- final int right = Bitmap.scaleFromDensity(
- mVectorState.mVPathRenderer.mOpticalInsets.right, constantStateDensity,
- targetDensity);
- final int top = Bitmap.scaleFromDensity(
- mVectorState.mVPathRenderer.mOpticalInsets.top, constantStateDensity,
- targetDensity);
- final int bottom = Bitmap.scaleFromDensity(
- mVectorState.mVPathRenderer.mOpticalInsets.bottom, constantStateDensity,
- targetDensity);
- mDpiScaleInsets = Insets.of(left, top, right, bottom);
- return;
- }
- }
+ final int sourceDensity = pathRenderer.mSourceDensity;
+ final int targetDensity = mTargetDensity;
+ if (targetDensity != sourceDensity) {
+ mDpiScaledWidth = Bitmap.scaleFromDensity(
+ (int) pathRenderer.mBaseWidth, sourceDensity, targetDensity);
+ mDpiScaledHeight = Bitmap.scaleFromDensity(
+ (int) pathRenderer.mBaseHeight,sourceDensity, targetDensity);
+ final int left = Bitmap.scaleFromDensity(
+ opticalInsets.left, sourceDensity, targetDensity);
+ final int right = Bitmap.scaleFromDensity(
+ opticalInsets.right, sourceDensity, targetDensity);
+ final int top = Bitmap.scaleFromDensity(
+ opticalInsets.top, sourceDensity, targetDensity);
+ final int bottom = Bitmap.scaleFromDensity(
+ opticalInsets.bottom, sourceDensity, targetDensity);
+ mDpiScaledInsets = Insets.of(left, top, right, bottom);
+ } else {
+ mDpiScaledWidth = (int) pathRenderer.mBaseWidth;
+ mDpiScaledHeight = (int) pathRenderer.mBaseHeight;
+ mDpiScaledInsets = opticalInsets;
}
- // For all the other cases, like either res is null, constant state is not initialized or
- // target density is the same as the constant state, we will just use the constant state
- // dimensions.
- mDpiScaledWidth = (int) mVectorState.mVPathRenderer.mBaseWidth;
- mDpiScaledHeight = (int) mVectorState.mVPathRenderer.mBaseHeight;
- mDpiScaleInsets = mVectorState.mVPathRenderer.mOpticalInsets;
}
@Override
@@ -487,7 +493,6 @@
try {
state.mCacheDirty = true;
updateStateFromTypedArray(a);
- updateDimensionInfo(t.getResources(), true /* update constant state */);
} catch (XmlPullParserException e) {
throw new RuntimeException(e);
} finally {
@@ -505,8 +510,8 @@
path.applyTheme(t);
}
- // Update local state.
- mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ // Update local properties.
+ updateLocalState(t.getResources());
}
/**
@@ -579,8 +584,8 @@
state.mCacheDirty = true;
inflateInternal(res, parser, attrs, theme);
- mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
- updateDimensionInfo(res, true /* update constant state */);
+ // Update local properties.
+ updateLocalState(res);
}
private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
@@ -593,6 +598,14 @@
// Extract the theme attributes, if any.
state.mThemeAttrs = a.extractThemeAttrs();
+ // The density may have changed since the last update (if any). Any
+ // dimension-type attributes will need their default values scaled.
+ final int densityDpi = a.getResources().getDisplayMetrics().densityDpi;
+ final int newSourceDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+ final int oldSourceDensity = pathRenderer.mSourceDensity;
+ final float densityScale = newSourceDensity / (float) oldSourceDensity;
+ pathRenderer.mSourceDensity = newSourceDensity;
+
final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
if (tintMode != -1) {
state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
@@ -620,9 +633,11 @@
}
pathRenderer.mBaseWidth = a.getDimension(
- R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
+ R.styleable.VectorDrawable_width,
+ pathRenderer.mBaseWidth * densityScale);
pathRenderer.mBaseHeight = a.getDimension(
- R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
+ R.styleable.VectorDrawable_height,
+ pathRenderer.mBaseHeight * densityScale);
if (pathRenderer.mBaseWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
@@ -633,13 +648,17 @@
}
final int insetLeft = a.getDimensionPixelSize(
- R.styleable.VectorDrawable_opticalInsetLeft, pathRenderer.mOpticalInsets.left);
+ R.styleable.VectorDrawable_opticalInsetLeft,
+ (int) (pathRenderer.mOpticalInsets.left * densityScale));
final int insetTop = a.getDimensionPixelSize(
- R.styleable.VectorDrawable_opticalInsetTop, pathRenderer.mOpticalInsets.top);
+ R.styleable.VectorDrawable_opticalInsetTop,
+ (int) (pathRenderer.mOpticalInsets.top * densityScale));
final int insetRight = a.getDimensionPixelSize(
- R.styleable.VectorDrawable_opticalInsetRight, pathRenderer.mOpticalInsets.right);
+ R.styleable.VectorDrawable_opticalInsetRight,
+ (int) (pathRenderer.mOpticalInsets.right * densityScale));
final int insetBottom = a.getDimensionPixelSize(
- R.styleable.VectorDrawable_opticalInsetBottom, pathRenderer.mOpticalInsets.bottom);
+ R.styleable.VectorDrawable_opticalInsetBottom,
+ (int) (pathRenderer.mOpticalInsets.bottom * densityScale));
pathRenderer.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
@@ -917,7 +936,7 @@
int mRootAlpha = 0xFF;
String mRootName = null;
- int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+ int mSourceDensity = DisplayMetrics.DENSITY_DEFAULT;
final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
@@ -954,7 +973,7 @@
mChangingConfigurations = copy.mChangingConfigurations;
mRootAlpha = copy.mRootAlpha;
mRootName = copy.mRootName;
- mTargetDensity = copy.mTargetDensity;
+ mSourceDensity = copy.mSourceDensity;
if (copy.mRootName != null) {
mVGTargetsMap.put(copy.mRootName, this);
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 1a43658..842f575 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -263,4 +263,9 @@
microbench/DisplayListCanvasBench.cpp \
microbench/LinearAllocatorBench.cpp
+ifeq (true, $(HWUI_NEW_OPS))
+ LOCAL_SRC_FILES += \
+ microbench/OpReordererBench.cpp
+endif
+
include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 4d9f9b4..94806ca 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -74,53 +74,64 @@
#endif
}
-void BakedOpRenderer::onRenderNodeOp(Info*, const RenderNodeOp&, const BakedOpState&) {
+void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) {
LOG_ALWAYS_FATAL("unsupported operation");
}
-void BakedOpRenderer::onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
- info->caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
- Texture* texture = info->getTexture(op.bitmap);
+void BakedOpRenderer::onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) {
+ info.caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
+ Texture* texture = info.getTexture(op.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
Glop glop;
- GlopBuilder(info->renderState, info->caches, &glop)
+ GlopBuilder(info.renderState, info.caches, &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedUnitQuad(texture->uvMapper)
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
.build();
- info->renderGlop(state, glop);
+ info.renderGlop(state, glop);
}
-void BakedOpRenderer::onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
+void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) {
Glop glop;
- GlopBuilder(info->renderState, info->caches, &glop)
+ GlopBuilder(info.renderState, info.caches, &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshUnitQuad()
.setFillPaint(*op.paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRect(op.unmappedBounds)
.build();
- info->renderGlop(state, glop);
+ info.renderGlop(state, glop);
}
-void BakedOpRenderer::onSimpleRectsOp(Info* info, const SimpleRectsOp& op, const BakedOpState& state) {
+void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) {
Glop glop;
- GlopBuilder(info->renderState, info->caches, &glop)
+ GlopBuilder(info.renderState, info.caches, &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
.setFillPaint(*op.paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewOffsetRect(0, 0, op.unmappedBounds)
.build();
- info->renderGlop(state, glop);
+ info.renderGlop(state, glop);
}
+void BakedOpRenderer::onBeginLayerOp(Info& info, const BeginLayerOp& op, const BakedOpState& state) {
+ LOG_ALWAYS_FATAL("unsupported operation");
+}
+
+void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const BakedOpState& state) {
+ LOG_ALWAYS_FATAL("unsupported operation");
+}
+
+void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) {
+ LOG_ALWAYS_FATAL("unsupported operation");
+}
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index b8b4426..f45dbe4 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -65,7 +65,7 @@
* These functions will perform the actual rendering of the individual operations in OpenGL,
* given the transform/clip and other state built into the BakedOpState object passed in.
*/
- #define BAKED_OP_RENDERER_METHOD(Type) static void on##Type(Info* info, const Type& op, const BakedOpState& state);
+ #define BAKED_OP_RENDERER_METHOD(Type) static void on##Type(Info& info, const Type& op, const BakedOpState& state);
MAP_OPS(BAKED_OP_RENDERER_METHOD);
};
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index e2201ca..ddb8c84 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -68,7 +68,7 @@
// resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
clipRect = recordedOp.localClipRect;
snapshot.transform->mapRect(clipRect);
- clipRect.doIntersect(snapshot.getClipRect());
+ clipRect.doIntersect(snapshot.getRenderTargetClip());
clipRect.snapToPixelBoundaries();
// resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index eca71c6..6a6cc42 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -259,7 +259,7 @@
currentTransform()->mapRect(r);
r.snapGeometryToPixelBoundaries(snapOut);
- Rect clipRect(currentClipRect());
+ Rect clipRect(currentRenderTargetClip());
clipRect.snapToPixelBoundaries();
if (!clipRect.intersects(r)) return true;
@@ -287,7 +287,7 @@
currentTransform()->mapRect(r);
r.roundOut(); // rounded out to be conservative
- Rect clipRect(currentClipRect());
+ Rect clipRect(currentRenderTargetClip());
clipRect.snapToPixelBoundaries();
if (!clipRect.intersects(r)) return true;
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index be57f44..4709ef4 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -147,7 +147,7 @@
void setInvisible(bool value) { mSnapshot->invisible = value; }
inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
- inline const Rect& currentClipRect() const { return currentSnapshot()->getClipRect(); }
+ inline const Rect& currentRenderTargetClip() const { return currentSnapshot()->getRenderTargetClip(); }
inline Region* currentRegion() const { return currentSnapshot()->region; }
inline int currentFlags() const { return currentSnapshot()->flags; }
const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 7c0e257..c1417c4 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -52,7 +52,8 @@
const std::vector<BakedOpState*>& getOps() const { return mOps; }
void dump() const {
- ALOGD(" Batch %p, merging %d, bounds " RECT_STRING, this, mMerging, RECT_ARGS(mBounds));
+ ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
+ this, mBatchId, mMerging, mOps.size(), RECT_ARGS(mBounds));
}
protected:
batchid_t mBatchId;
@@ -201,17 +202,106 @@
Rect mClipRect;
};
-class NullClient: public CanvasStateClient {
- void onViewportInitialized() override {}
- void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
- GLuint getTargetFbo() const override { return 0; }
-};
-static NullClient sNullClient;
+// iterate back toward target to see if anything drawn since should overlap the new op
+// if no target, merging ops still interate to find similar batch to insert after
+void OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
+ BatchBase** targetBatch, size_t* insertBatchIndex) const {
+ for (int i = mBatches.size() - 1; i >= 0; i--) {
+ BatchBase* overBatch = mBatches[i];
+
+ if (overBatch == *targetBatch) break;
+
+ // TODO: also consider shader shared between batch types
+ if (batchId == overBatch->getBatchId()) {
+ *insertBatchIndex = i + 1;
+ if (!*targetBatch) break; // found insert position, quit
+ }
+
+ if (overBatch->intersects(clippedBounds)) {
+ // NOTE: it may be possible to optimize for special cases where two operations
+ // of the same batch/paint could swap order, such as with a non-mergeable
+ // (clipped) and a mergeable text operation
+ *targetBatch = nullptr;
+ break;
+ }
+ }
+}
+
+void OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator,
+ BakedOpState* op, batchid_t batchId) {
+ OpBatch* targetBatch = mBatchLookup[batchId];
+
+ size_t insertBatchIndex = mBatches.size();
+ if (targetBatch) {
+ locateInsertIndex(batchId, op->computedState.clippedBounds,
+ (BatchBase**)(&targetBatch), &insertBatchIndex);
+ }
+
+ if (targetBatch) {
+ targetBatch->batchOp(op);
+ } else {
+ // new non-merging batch
+ targetBatch = new (allocator) OpBatch(batchId, op);
+ mBatchLookup[batchId] = targetBatch;
+ mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
+ }
+}
+
+// insertion point of a new batch, will hopefully be immediately after similar batch
+// (generally, should be similar shader)
+void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator,
+ BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
+ MergingOpBatch* targetBatch = nullptr;
+
+ // Try to merge with any existing batch with same mergeId
+ auto getResult = mMergingBatchLookup[batchId].find(mergeId);
+ if (getResult != mMergingBatchLookup[batchId].end()) {
+ targetBatch = getResult->second;
+ if (!targetBatch->canMergeWith(op)) {
+ targetBatch = nullptr;
+ }
+ }
+
+ size_t insertBatchIndex = mBatches.size();
+ locateInsertIndex(batchId, op->computedState.clippedBounds,
+ (BatchBase**)(&targetBatch), &insertBatchIndex);
+
+ if (targetBatch) {
+ targetBatch->mergeOp(op);
+ } else {
+ // new merging batch
+ targetBatch = new (allocator) MergingOpBatch(batchId, op);
+ mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
+
+ mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
+ }
+}
+
+void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const {
+ for (const BatchBase* batch : mBatches) {
+ // TODO: different behavior based on batch->isMerging()
+ for (const BakedOpState* op : batch->getOps()) {
+ receivers[op->op->opId](arg, *op->op, *op);
+ }
+ }
+}
+
+void OpReorderer::LayerReorderer::dump() const {
+ for (const BatchBase* batch : mBatches) {
+ batch->dump();
+ }
+}
OpReorderer::OpReorderer()
- : mCanvasState(sNullClient) {
+ : mCanvasState(*this) {
+ mLayerReorderers.emplace_back();
+ mLayerStack.push_back(0);
}
+void OpReorderer::onViewportInitialized() {}
+
+void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+
void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight,
const std::vector< sp<RenderNode> >& nodes) {
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
@@ -244,11 +334,11 @@
* This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. E.g. a
* BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&)
*/
-#define OP_RECIEVER(Type) \
+#define OP_RECEIVER(Type) \
[](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
void OpReorderer::deferImpl(const DisplayList& displayList) {
static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = {
- MAP_OPS(OP_RECIEVER)
+ MAP_OPS(OP_RECEIVER)
};
for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
@@ -260,23 +350,18 @@
void OpReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) {
ATRACE_NAME("flush drawing commands");
- for (const BatchBase* batch : mBatches) {
- // TODO: different behavior based on batch->isMerging()
- for (const BakedOpState* op : batch->getOps()) {
- receivers[op->op->opId](arg, *op->op, *op);
- }
+ // Relay through layers in reverse order, since layers
+ // later in the list will be drawn by earlier ones
+ for (int i = mLayerReorderers.size() - 1; i >= 0; i--) {
+ mLayerReorderers[i].replayBakedOpsImpl(arg, receivers);
}
}
-BakedOpState* OpReorderer::bakeOpState(const RecordedOp& recordedOp) {
- return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
-}
-
void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
if (op.renderNode->nothingToDraw()) {
return;
}
- mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+ int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
// apply state from RecordedOp
mCanvasState.concatMatrix(op.localMatrix);
@@ -285,10 +370,10 @@
// apply RenderProperties state
if (op.renderNode->applyViewProperties(mCanvasState)) {
- // not rejected do ops...
+ // if node not rejected based on properties, do ops...
deferImpl(op.renderNode->getDisplayList());
}
- mCanvasState.restore();
+ mCanvasState.restoreToCount(count);
}
static batchid_t tessellatedBatchId(const SkPaint& paint) {
@@ -298,104 +383,70 @@
}
void OpReorderer::onBitmapOp(const BitmapOp& op) {
- BakedOpState* bakedStateOp = bakeOpState(op);
+ BakedOpState* bakedStateOp = tryBakeOpState(op);
if (!bakedStateOp) return; // quick rejected
mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
// TODO: AssetAtlas
-
- deferMergeableOp(bakedStateOp, OpBatchType::Bitmap, mergeId);
+ currentLayer().deferMergeableOp(mAllocator, bakedStateOp, OpBatchType::Bitmap, mergeId);
}
void OpReorderer::onRectOp(const RectOp& op) {
- BakedOpState* bakedStateOp = bakeOpState(op);
+ BakedOpState* bakedStateOp = tryBakeOpState(op);
if (!bakedStateOp) return; // quick rejected
- deferUnmergeableOp(bakedStateOp, tessellatedBatchId(*op.paint));
+ currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, tessellatedBatchId(*op.paint));
}
void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) {
- BakedOpState* bakedStateOp = bakeOpState(op);
+ BakedOpState* bakedStateOp = tryBakeOpState(op);
if (!bakedStateOp) return; // quick rejected
- deferUnmergeableOp(bakedStateOp, OpBatchType::Vertices);
+ currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices);
}
-// iterate back toward target to see if anything drawn since should overlap the new op
-// if no target, merging ops still interate to find similar batch to insert after
-void OpReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
- BatchBase** targetBatch, size_t* insertBatchIndex) const {
- for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) {
- BatchBase* overBatch = mBatches[i];
+// TODO: test rejection at defer time, where the bounds become empty
+void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) {
+ mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+ mCanvasState.writableSnapshot()->transform->loadIdentity();
+ mCanvasState.writableSnapshot()->initializeViewport(
+ (int) op.unmappedBounds.getWidth(), (int) op.unmappedBounds.getHeight());
+ mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
- if (overBatch == *targetBatch) break;
+ // create a new layer, and push its index on the stack
+ mLayerStack.push_back(mLayerReorderers.size());
+ mLayerReorderers.emplace_back();
+ mLayerReorderers.back().beginLayerOp = &op;
+}
- // TODO: also consider shader shared between batch types
- if (batchId == overBatch->getBatchId()) {
- *insertBatchIndex = i + 1;
- if (!*targetBatch) break; // found insert position, quit
- }
+void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) {
+ mCanvasState.restore();
- if (overBatch->intersects(clippedBounds)) {
- // NOTE: it may be possible to optimize for special cases where two operations
- // of the same batch/paint could swap order, such as with a non-mergeable
- // (clipped) and a mergeable text operation
- *targetBatch = nullptr;
- break;
- }
+ const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp;
+
+ // pop finished layer off of the stack
+ int finishedLayerIndex = mLayerStack.back();
+ mLayerStack.pop_back();
+
+ // record the draw operation into the previous layer's list of draw commands
+ // uses state from the associated beginLayerOp, since it has all the state needed for drawing
+ LayerOp* drawLayerOp = new (mAllocator) LayerOp(
+ beginLayerOp.unmappedBounds,
+ beginLayerOp.localMatrix,
+ beginLayerOp.localClipRect,
+ beginLayerOp.paint);
+ BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
+
+ if (bakedOpState) {
+ // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack)
+ currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
+ } else {
+ // Layer won't be drawn - delete its drawing batches to prevent it from doing any work
+ mLayerReorderers[finishedLayerIndex].clear();
+ return;
}
}
-void OpReorderer::deferUnmergeableOp(BakedOpState* op, batchid_t batchId) {
- OpBatch* targetBatch = mBatchLookup[batchId];
-
- size_t insertBatchIndex = mBatches.size();
- if (targetBatch) {
- locateInsertIndex(batchId, op->computedState.clippedBounds,
- (BatchBase**)(&targetBatch), &insertBatchIndex);
- }
-
- if (targetBatch) {
- targetBatch->batchOp(op);
- } else {
- // new non-merging batch
- targetBatch = new (mAllocator) OpBatch(batchId, op);
- mBatchLookup[batchId] = targetBatch;
- mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
- }
-}
-
-// insertion point of a new batch, will hopefully be immediately after similar batch
-// (generally, should be similar shader)
-void OpReorderer::deferMergeableOp(BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
- MergingOpBatch* targetBatch = nullptr;
-
- // Try to merge with any existing batch with same mergeId
- auto getResult = mMergingBatches[batchId].find(mergeId);
- if (getResult != mMergingBatches[batchId].end()) {
- targetBatch = getResult->second;
- if (!targetBatch->canMergeWith(op)) {
- targetBatch = nullptr;
- }
- }
-
- size_t insertBatchIndex = mBatches.size();
- locateInsertIndex(batchId, op->computedState.clippedBounds,
- (BatchBase**)(&targetBatch), &insertBatchIndex);
-
- if (targetBatch) {
- targetBatch->mergeOp(op);
- } else {
- // new merging batch
- targetBatch = new (mAllocator) MergingOpBatch(batchId, op);
- mMergingBatches[batchId].insert(std::make_pair(mergeId, targetBatch));
-
- mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
- }
-}
-
-void OpReorderer::dump() {
- for (const BatchBase* batch : mBatches) {
- batch->dump();
- }
+void OpReorderer::onLayerOp(const LayerOp& op) {
+ LOG_ALWAYS_FATAL("unsupported");
}
} // namespace uirenderer
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index 6776a3c..73dc9af 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -54,19 +54,63 @@
};
}
-class OpReorderer {
+class OpReorderer : public CanvasStateClient {
+ typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver;
+
+ /**
+ * Stores the deferred render operations and state used to compute ordering
+ * for a single FBO/layer.
+ */
+ class LayerReorderer {
+ public:
+ // iterate back toward target to see if anything drawn since should overlap the new op
+ // if no target, merging ops still iterate to find similar batch to insert after
+ void locateInsertIndex(int batchId, const Rect& clippedBounds,
+ BatchBase** targetBatch, size_t* insertBatchIndex) const;
+
+ void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId);
+
+ // insertion point of a new batch, will hopefully be immediately after similar batch
+ // (generally, should be similar shader)
+ void deferMergeableOp(LinearAllocator& allocator,
+ BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
+
+ void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const;
+
+ void clear() {
+ mBatches.clear();
+ }
+
+ void dump() const;
+
+ const BeginLayerOp* beginLayerOp = nullptr;
+
+ private:
+ std::vector<BatchBase*> mBatches;
+
+ /**
+ * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
+ * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
+ * collide, which avoids the need to resolve mergeid collisions.
+ */
+ std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count];
+
+ // Maps batch ids to the most recent *non-merging* batch of that id
+ OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
+
+ };
public:
OpReorderer();
+ virtual ~OpReorderer() {}
// TODO: not final, just presented this way for simplicity. Layers too?
void defer(const SkRect& clip, int viewportWidth, int viewportHeight,
const std::vector< sp<RenderNode> >& nodes);
void defer(int viewportWidth, int viewportHeight, const DisplayList& displayList);
- typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver;
/**
- * replayBakedOps() is templated based on what class will recieve ops being replayed.
+ * replayBakedOps() is templated based on what class will receive ops being replayed.
*
* It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use
* state->op->opId to lookup a receiver that will be called when the op is replayed.
@@ -77,19 +121,37 @@
*/
#define BAKED_OP_RECEIVER(Type) \
[](void* internalArg, const RecordedOp& op, const BakedOpState& state) { \
- StaticReceiver::on##Type(static_cast<Arg*>(internalArg), static_cast<const Type&>(op), state); \
+ StaticReceiver::on##Type(*(static_cast<Arg*>(internalArg)), static_cast<const Type&>(op), state); \
},
template <typename StaticReceiver, typename Arg>
- void replayBakedOps(Arg* arg) {
+ void replayBakedOps(Arg& arg) {
static BakedOpReceiver receivers[] = {
MAP_OPS(BAKED_OP_RECEIVER)
};
- StaticReceiver::startFrame(*arg);
- replayBakedOpsImpl((void*)arg, receivers);
- StaticReceiver::endFrame(*arg);
+ StaticReceiver::startFrame(arg);
+ replayBakedOpsImpl((void*)&arg, receivers);
+ StaticReceiver::endFrame(arg);
}
+
+ void dump() const {
+ for (auto&& layer : mLayerReorderers) {
+ layer.dump();
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ /// CanvasStateClient interface
+ ///////////////////////////////////////////////////////////////////
+ virtual void onViewportInitialized() override;
+ virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
+ virtual GLuint getTargetFbo() const override { return 0; }
+
private:
- BakedOpState* bakeOpState(const RecordedOp& recordedOp);
+ LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; }
+
+ BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
+ return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
+ }
void deferImpl(const DisplayList& displayList);
@@ -105,36 +167,27 @@
void on##Type(const Type& op);
MAP_OPS(INTERNAL_OP_HANDLER)
- // iterate back toward target to see if anything drawn since should overlap the new op
- // if no target, merging ops still iterate to find similar batch to insert after
- void locateInsertIndex(int batchId, const Rect& clippedBounds,
- BatchBase** targetBatch, size_t* insertBatchIndex) const;
+ // List of every deferred layer's render state. Replayed in reverse order to render a frame.
+ std::vector<LayerReorderer> mLayerReorderers;
- void deferUnmergeableOp(BakedOpState* op, batchid_t batchId);
+ /*
+ * Stack of indices within mLayerReorderers representing currently active layers. If drawing
+ * layerA within a layerB, will contain, in order:
+ * - 0 (representing FBO 0, always present)
+ * - layerB's index
+ * - layerA's index
+ *
+ * Note that this doesn't vector doesn't always map onto all values of mLayerReorderers. When a
+ * layer is finished deferring, it will still be represented in mLayerReorderers, but it's index
+ * won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing
+ * ops added to it.
+ */
+ std::vector<size_t> mLayerStack;
- // insertion point of a new batch, will hopefully be immediately after similar batch
- // (generally, should be similar shader)
- void deferMergeableOp(BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
-
- void dump();
-
- std::vector<BatchBase*> mBatches;
-
- /**
- * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
- * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
- * collide, which avoids the need to resolve mergeid collisions.
- */
- std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatches[OpBatchType::Count];
-
- // Maps batch ids to the most recent *non-merging* batch of that id
- OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
CanvasState mCanvasState;
// contains ResolvedOps and Batches
LinearAllocator mAllocator;
-
- int mEarliestBatchIndex = 0;
};
}; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cd03ac4..d4f65b6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -223,7 +223,7 @@
void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
if (mState.currentlyIgnored()) return;
- Rect clip(mState.currentClipRect());
+ Rect clip(mState.currentRenderTargetClip());
clip.snapToPixelBoundaries();
// Since we don't know what the functor will draw, let's dirty
@@ -488,7 +488,7 @@
currentTransform()->mapRect(bounds);
// Layers only make sense if they are in the framebuffer's bounds
- bounds.doIntersect(mState.currentClipRect());
+ bounds.doIntersect(mState.currentRenderTargetClip());
if (!bounds.isEmpty()) {
// We cannot work with sub-pixels in this case
bounds.snapToPixelBoundaries();
@@ -1036,7 +1036,7 @@
}
void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
- bounds.doIntersect(mState.currentClipRect());
+ bounds.doIntersect(mState.currentRenderTargetClip());
if (!bounds.isEmpty()) {
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
@@ -1084,7 +1084,7 @@
.setMeshIndexedQuads(&mesh[0], quadCount)
.setFillClear()
.setTransform(*currentSnapshot(), transformFlags)
- .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
+ .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getRenderTargetClip()))
.build();
renderGlop(glop, GlopRenderType::LayerClear);
@@ -1099,7 +1099,7 @@
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
- const Rect& currentClip = mState.currentClipRect();
+ const Rect& currentClip = mState.currentRenderTargetClip();
const mat4* currentMatrix = currentTransform();
if (stateDeferFlags & kStateDeferFlag_Draw) {
@@ -1187,7 +1187,7 @@
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setScissorFromClip() {
- Rect clip(mState.currentClipRect());
+ Rect clip(mState.currentRenderTargetClip());
clip.snapToPixelBoundaries();
if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
@@ -1430,7 +1430,7 @@
return;
}
- DeferredDisplayList deferredList(mState.currentClipRect());
+ DeferredDisplayList deferredList(mState.currentRenderTargetClip());
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
renderNode->defer(deferStruct, 0);
@@ -1765,7 +1765,7 @@
// No need to check against the clip, we fill the clip region
if (mState.currentlyIgnored()) return;
- Rect clip(mState.currentClipRect());
+ Rect clip(mState.currentRenderTargetClip());
clip.snapToPixelBoundaries();
SkPaint paint;
@@ -2030,7 +2030,7 @@
}
fontRenderer.setTextureFiltering(linearFilter);
- const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
+ const Rect& clip(pureTranslate ? writableSnapshot()->getRenderTargetClip() : writableSnapshot()->getLocalClip());
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
@@ -2191,7 +2191,7 @@
fontRenderer.setTextureFiltering(linearFilter);
// TODO: Implement better clipping for scaled/rotated text
- const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
+ const Rect* clip = !pureTranslate ? nullptr : &mState.currentRenderTargetClip();
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
bool status;
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 36a8dac..c0c61db 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -29,7 +29,6 @@
bool Properties::debugOverdraw = false;
bool Properties::showDirtyRegions = false;
bool Properties::skipEmptyFrames = true;
-bool Properties::swapBuffersWithDamage = true;
bool Properties::useBufferAge = true;
bool Properties::enablePartialUpdates = true;
@@ -117,7 +116,6 @@
}
skipEmptyFrames = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE, true);
- swapBuffersWithDamage = property_get_bool(PROPERTY_SWAP_WITH_DAMAGE, true);
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 3512c36..74cd74b 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -142,13 +142,6 @@
#define PROPERTY_SKIP_EMPTY_DAMAGE "debug.hwui.skip_empty_damage"
/**
- * Setting this property will enable or disable usage of EGL_KHR_swap_buffers_with_damage
- * See: https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt
- * Default is "true"
- */
-#define PROPERTY_SWAP_WITH_DAMAGE "debug.hwui.swap_with_damage"
-
-/**
* Controls whether or not HWUI will use the EGL_EXT_buffer_age extension
* to do partial invalidates. Setting this to "false" will fall back to
* using BUFFER_PRESERVED instead
@@ -271,8 +264,6 @@
static bool showDirtyRegions;
// TODO: Remove after stabilization period
static bool skipEmptyFrames;
- // TODO: Remove after stabilization period
- static bool swapBuffersWithDamage;
static bool useBufferAge;
static bool enablePartialUpdates;
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index a69f030..dd01637 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -41,7 +41,10 @@
OP_FN(BitmapOp) \
OP_FN(RectOp) \
OP_FN(RenderNodeOp) \
- OP_FN(SimpleRectsOp)
+ OP_FN(SimpleRectsOp) \
+ OP_FN(BeginLayerOp) \
+ OP_FN(EndLayerOp) \
+ OP_FN(LayerOp)
// Generate OpId enum
#define IDENTITY_FN(Type) Type,
@@ -112,6 +115,31 @@
const size_t vertexCount;
};
+/**
+ * Stateful operation! denotes the creation of an off-screen layer,
+ * and that commands following will render into it.
+ */
+struct BeginLayerOp : RecordedOp {
+ BeginLayerOp(BASE_PARAMS)
+ : SUPER(BeginLayerOp) {}
+};
+
+/**
+ * Stateful operation! Denotes end of off-screen layer, and that
+ * commands since last BeginLayerOp should be drawn into parent FBO.
+ *
+ * State in this op is empty, it just serves to signal that a layer has been finished.
+ */
+struct EndLayerOp : RecordedOp {
+ EndLayerOp()
+ : RecordedOp(RecordedOpId::EndLayerOp, Rect(0, 0), Matrix4::identity(), Rect(0, 0), nullptr) {}
+};
+
+struct LayerOp : RecordedOp {
+ LayerOp(BASE_PARAMS)
+ : SUPER(LayerOp) {}
+};
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3b413aa..1f113bc 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -73,6 +73,20 @@
}
// ----------------------------------------------------------------------------
+// CanvasStateClient implementation
+// ----------------------------------------------------------------------------
+
+void RecordingCanvas::onViewportInitialized() {
+
+}
+
+void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
+ if (removed.flags & Snapshot::kFlagIsFboLayer) {
+ addOp(new (alloc()) EndLayerOp());
+ }
+}
+
+// ----------------------------------------------------------------------------
// android/graphics/Canvas state operations
// ----------------------------------------------------------------------------
// Save (layer)
@@ -97,8 +111,66 @@
int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
SkCanvas::SaveFlags flags) {
- LOG_ALWAYS_FATAL("TODO");
- return 0;
+ if (!(flags & SkCanvas::kClipToLayer_SaveFlag)) {
+ LOG_ALWAYS_FATAL("unclipped layers not supported");
+ }
+ // force matrix/clip isolation for layer
+ flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
+
+
+ const Snapshot& previous = *mState.currentSnapshot();
+
+ // initialize the snapshot as though it almost represents an FBO layer so deferred draw
+ // operations will be able to store and restore the current clip and transform info, and
+ // quick rejection will be correct (for display lists)
+
+ const Rect untransformedBounds(left, top, right, bottom);
+
+ // determine clipped bounds relative to previous viewport.
+ Rect visibleBounds = untransformedBounds;
+ previous.transform->mapRect(visibleBounds);
+
+
+ visibleBounds.doIntersect(previous.getRenderTargetClip());
+ visibleBounds.snapToPixelBoundaries();
+
+ Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
+ visibleBounds.doIntersect(previousViewport);
+
+ // Map visible bounds back to layer space, and intersect with parameter bounds
+ Rect layerBounds = visibleBounds;
+ Matrix4 inverse;
+ inverse.loadInverse(*previous.transform);
+ inverse.mapRect(layerBounds);
+ layerBounds.doIntersect(untransformedBounds);
+
+ int saveValue = mState.save((int) flags);
+ Snapshot& snapshot = *mState.writableSnapshot();
+
+ // layerBounds is now original bounds, but with clipped to clip
+ // and viewport to ensure it's minimal size.
+ if (layerBounds.isEmpty() || untransformedBounds.isEmpty()) {
+ // Don't bother recording layer, since it's been rejected
+ snapshot.resetClip(0, 0, 0, 0);
+ return saveValue;
+ }
+
+ snapshot.flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
+ snapshot.initializeViewport(untransformedBounds.getWidth(), untransformedBounds.getHeight());
+ snapshot.resetTransform(-untransformedBounds.left, -untransformedBounds.top, 0.0f);
+
+ Rect clip = layerBounds;
+ clip.translate(-untransformedBounds.left, -untransformedBounds.top);
+ snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
+ snapshot.roundRectClipState = nullptr;
+
+ addOp(new (alloc()) BeginLayerOp(
+ Rect(left, top, right, bottom),
+ *previous.transform, // transform to *draw* with
+ previous.getRenderTargetClip(), // clip to *draw* with
+ refPaint(paint)));
+
+ return saveValue;
}
// Matrix
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 2179e4c..9c32b1a 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -52,8 +52,8 @@
// ----------------------------------------------------------------------------
// CanvasStateClient interface
// ----------------------------------------------------------------------------
- virtual void onViewportInitialized() override {}
- virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override {}
+ virtual void onViewportInitialized() override;
+ virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
virtual GLuint getTargetFbo() const override { return -1; }
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 894a2bd..351fbaa 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -929,7 +929,7 @@
const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
- // If the projection reciever has an outline, we mask projected content to it
+ // If the projection receiver has an outline, we mask projected content to it
// (which we know, apriori, are all tessellated paths)
renderer.setProjectionPathMask(alloc, projectionReceiverOutline);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index f824cc0..abef806 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -203,8 +203,8 @@
return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject);
}
- bool setProjectionReceiver(bool shouldRecieve) {
- return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve);
+ bool setProjectionReceiver(bool shouldReceive) {
+ return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldReceive);
}
bool isProjectionReceiver() const {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index aeeda96..4789b33 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -158,13 +158,12 @@
/**
* Returns the current clip in render target coordinates.
*/
- const Rect& getRenderTargetClip() { return mClipArea->getClipRect(); }
+ const Rect& getRenderTargetClip() const { return mClipArea->getClipRect(); }
/*
* Accessor functions so that the clip area can stay private
*/
bool clipIsEmpty() const { return mClipArea->isEmpty(); }
- const Rect& getClipRect() const { return mClipArea->getClipRect(); }
const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
bool clipIsSimple() const { return mClipArea->isSimple(); }
const ClipArea& getClipArea() const { return *mClipArea; }
diff --git a/libs/hwui/microbench/OpReordererBench.cpp b/libs/hwui/microbench/OpReordererBench.cpp
new file mode 100644
index 0000000..cf96d44
--- /dev/null
+++ b/libs/hwui/microbench/OpReordererBench.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <benchmark/Benchmark.h>
+
+#include "BakedOpState.h"
+#include "BakedOpRenderer.h"
+#include "OpReorderer.h"
+#include "RecordedOp.h"
+#include "RecordingCanvas.h"
+#include "unit_tests/TestUtils.h"
+#include "microbench/MicroBench.h"
+
+#include <vector>
+
+using namespace android;
+using namespace android::uirenderer;
+
+auto sReorderingDisplayList = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
+ SkPaint paint;
+
+ // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+ // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+ canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ for (int i = 0; i < 30; i++) {
+ canvas.translate(0, 10);
+ canvas.drawRect(0, 0, 10, 10, paint);
+ canvas.drawBitmap(bitmap, 5, 0, nullptr);
+ }
+ canvas.restore();
+});
+
+BENCHMARK_NO_ARG(BM_OpReorderer_defer);
+void BM_OpReorderer_defer::Run(int iters) {
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; i++) {
+ OpReorderer reorderer;
+ reorderer.defer(200, 200, *sReorderingDisplayList);
+ MicroBench::DoNotOptimize(&reorderer);
+ }
+ StopBenchmarkTiming();
+}
+
+BENCHMARK_NO_ARG(BM_OpReorderer_deferAndRender);
+void BM_OpReorderer_deferAndRender::Run(int iters) {
+ TestUtils::runOnRenderThread([this, iters](RenderState& renderState, Caches& caches) {
+ StartBenchmarkTiming();
+ for (int i = 0; i < iters; i++) {
+ OpReorderer reorderer;
+ reorderer.defer(200, 200, *sReorderingDisplayList);
+ MicroBench::DoNotOptimize(&reorderer);
+
+ BakedOpRenderer::Info info(caches, renderState, 200, 200, true);
+ reorderer.replayBakedOps<BakedOpRenderer>(info);
+ }
+ StopBenchmarkTiming();
+ });
+}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 238cf06..f571426 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -323,7 +323,7 @@
BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(),
frame.width(), frame.height(), mOpaque);
// TODO: profiler().draw(mCanvas);
- reorderer.replayBakedOps<BakedOpRenderer>(&info);
+ reorderer.replayBakedOps<BakedOpRenderer>(info);
bool drew = info.didDraw;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index c9b9637..b353ae6 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -137,6 +137,8 @@
StringCollection extensions(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age");
EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
+ LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
+ "Missing required extension EGL_KHR_swap_buffers_with_damage");
}
bool EglManager::hasEglContext() {
@@ -322,18 +324,10 @@
}
#endif
-#ifdef EGL_KHR_swap_buffers_with_damage
- if (CC_LIKELY(Properties::swapBuffersWithDamage)) {
- EGLint rects[4];
- frame.map(screenDirty, rects);
- eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects,
- screenDirty.isEmpty() ? 0 : 1);
- } else {
- eglSwapBuffers(mEglDisplay, frame.mSurface);
- }
-#else
- eglSwapBuffers(mEglDisplay, frame.mSurface);
-#endif
+ EGLint rects[4];
+ frame.map(screenDirty, rects);
+ eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects,
+ screenDirty.isEmpty() ? 0 : 1);
EGLint err = eglGetError();
if (CC_LIKELY(err == EGL_SUCCESS)) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 26aae90..15ccd6a 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -574,12 +574,7 @@
RenderThread& thread = RenderThread::getInstance();
void* retval;
task->setReturnPtr(&retval);
- Mutex mutex;
- Condition condition;
- SignalingRenderTask syncTask(task, &mutex, &condition);
- AutoMutex _lock(mutex);
- thread.queue(&syncTask);
- condition.wait(mutex);
+ thread.queueAndWait(task);
return retval;
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 64075f1..8fcd109 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -312,6 +312,16 @@
}
}
+void RenderThread::queueAndWait(RenderTask* task) {
+ Mutex mutex;
+ Condition condition;
+ SignalingRenderTask syncTask(task, &mutex, &condition);
+
+ AutoMutex _lock(mutex);
+ queue(&syncTask);
+ condition.wait(mutex);
+}
+
void RenderThread::queueAtFront(RenderTask* task) {
AutoMutex _lock(mLock);
mQueue.queueAtFront(task);
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 8096099..f3444a8 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -39,6 +39,7 @@
namespace uirenderer {
class RenderState;
+class TestUtils;
namespace renderthread {
@@ -76,6 +77,7 @@
// RenderThread takes complete ownership of tasks that are queued
// and will delete them after they are run
ANDROID_API void queue(RenderTask* task);
+ ANDROID_API void queueAndWait(RenderTask* task);
ANDROID_API void queueAtFront(RenderTask* task);
void queueAt(RenderTask* task, nsecs_t runAtNs);
void remove(RenderTask* task);
@@ -101,6 +103,7 @@
friend class Singleton<RenderThread>;
friend class DispatchFrameCallbacks;
friend class RenderProxy;
+ friend class android::uirenderer::TestUtils;
RenderThread();
virtual ~RenderThread();
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index e1249fb..d02f89d 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -27,26 +27,69 @@
namespace android {
namespace uirenderer {
-#define UNSUPPORTED_OP(Info, Type) \
- static void on##Type(Info*, const Type&, const BakedOpState&) { FAIL(); }
+/**
+ * Class that redirects static operation dispatch to virtual methods on a Client class.
+ *
+ * The client is recreated for every op (so data cannot be persisted between operations), but the
+ * virtual dispatch allows for default behaviors to be specified without enumerating each operation
+ * for every test.
+ *
+ * onXXXOp methods fail by default - tests should override ops they expect
+ * startFrame/endFrame do nothing by default - tests should override to intercept
+ */
+template<class CustomClient, class Arg>
+class TestReceiver {
+public:
+#define CLIENT_METHOD(Type) \
+ virtual void on##Type(Arg&, const Type&, const BakedOpState&) { FAIL(); }
+ class Client {
+ public:
+ virtual ~Client() {};
+ MAP_OPS(CLIENT_METHOD)
+
+ virtual void startFrame(Arg& info) {}
+ virtual void endFrame(Arg& info) {}
+ };
+
+#define DISPATCHER_METHOD(Type) \
+ static void on##Type(Arg& arg, const Type& op, const BakedOpState& state) { \
+ CustomClient client; client.on##Type(arg, op, state); \
+ }
+ MAP_OPS(DISPATCHER_METHOD)
+
+ static void startFrame(Arg& info) {
+ CustomClient client;
+ client.startFrame(info);
+ }
+
+ static void endFrame(Arg& info) {
+ CustomClient client;
+ client.endFrame(info);
+ }
+};
class Info {
public:
int index = 0;
};
-class SimpleReceiver {
+// Receiver class which will fail if it receives any ops
+class FailReceiver : public TestReceiver<FailReceiver, Info>::Client {};
+
+class SimpleReceiver : public TestReceiver<SimpleReceiver, Info>::Client {
public:
- static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
- EXPECT_EQ(1, info->index++);
+ void startFrame(Info& info) override {
+ EXPECT_EQ(0, info.index++);
}
- static void onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
- EXPECT_EQ(0, info->index++);
+ void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, info.index++);
}
- UNSUPPORTED_OP(Info, RenderNodeOp)
- UNSUPPORTED_OP(Info, SimpleRectsOp)
- static void startFrame(Info& info) {}
- static void endFrame(Info& info) {}
+ void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(2, info.index++);
+ }
+ void endFrame(Info& info) override {
+ EXPECT_EQ(3, info.index++);
+ }
};
TEST(OpReorderer, simple) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
@@ -54,28 +97,39 @@
canvas.drawRect(0, 0, 100, 200, SkPaint());
canvas.drawBitmap(bitmap, 10, 10, nullptr);
});
-
OpReorderer reorderer;
reorderer.defer(200, 200, *dl);
Info info;
- reorderer.replayBakedOps<SimpleReceiver>(&info);
+ reorderer.replayBakedOps<TestReceiver<SimpleReceiver, Info>>(info);
+ EXPECT_EQ(4, info.index); // 2 ops + start + end
+}
+
+
+TEST(OpReorderer, simpleRejection) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ canvas.restore();
+ });
+ OpReorderer reorderer;
+ reorderer.defer(200, 200, *dl);
+
+ Info info;
+ reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info);
}
static int SIMPLE_BATCHING_LOOPS = 5;
-class SimpleBatchingReceiver {
+class SimpleBatchingReceiver : public TestReceiver<SimpleBatchingReceiver, Info>::Client {
public:
- static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
- EXPECT_TRUE(info->index++ >= SIMPLE_BATCHING_LOOPS);
+ void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
+ EXPECT_TRUE(info.index++ >= SIMPLE_BATCHING_LOOPS);
}
- static void onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
- EXPECT_TRUE(info->index++ < SIMPLE_BATCHING_LOOPS);
+ void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
+ EXPECT_TRUE(info.index++ < SIMPLE_BATCHING_LOOPS);
}
- UNSUPPORTED_OP(Info, RenderNodeOp)
- UNSUPPORTED_OP(Info, SimpleRectsOp)
- static void startFrame(Info& info) {}
- static void endFrame(Info& info) {}
};
TEST(OpReorderer, simpleBatching) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
@@ -96,15 +150,14 @@
reorderer.defer(200, 200, *dl);
Info info;
- reorderer.replayBakedOps<SimpleBatchingReceiver>(&info);
+ reorderer.replayBakedOps<TestReceiver<SimpleBatchingReceiver, Info>>(info);
EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, info.index); // 2 x loops ops, because no merging (TODO: force no merging)
}
-class RenderNodeReceiver {
+class RenderNodeReceiver : public TestReceiver<RenderNodeReceiver, Info>::Client {
public:
- UNSUPPORTED_OP(Info, BitmapOp)
- static void onRectOp(Info* info, const RectOp& op, const BakedOpState& state) {
- switch(info->index++) {
+ void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
+ switch(info.index++) {
case 0:
EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
@@ -117,10 +170,6 @@
FAIL();
}
}
- UNSUPPORTED_OP(Info, RenderNodeOp)
- UNSUPPORTED_OP(Info, SimpleRectsOp)
- static void startFrame(Info& info) {}
- static void endFrame(Info& info) {}
};
TEST(OpReorderer, renderNode) {
sp<RenderNode> child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110, [](RecordingCanvas& canvas) {
@@ -151,22 +200,17 @@
reorderer.defer(SkRect::MakeWH(200, 200), 200, 200, nodes);
Info info;
- reorderer.replayBakedOps<RenderNodeReceiver>(&info);
+ reorderer.replayBakedOps<TestReceiver<RenderNodeReceiver, Info>>(info);
}
-class ClippedReceiver {
+class ClippedReceiver : public TestReceiver<ClippedReceiver, Info>::Client {
public:
- static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) {
- EXPECT_EQ(0, info->index++);
+ void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, info.index++);
EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
- UNSUPPORTED_OP(Info, RectOp)
- UNSUPPORTED_OP(Info, RenderNodeOp)
- UNSUPPORTED_OP(Info, SimpleRectsOp)
- static void startFrame(Info& info) {}
- static void endFrame(Info& info) {}
};
TEST(OpReorderer, clipped) {
sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RecordingCanvas& canvas) {
@@ -182,8 +226,106 @@
200, 200, nodes);
Info info;
- reorderer.replayBakedOps<ClippedReceiver>(&info);
+ reorderer.replayBakedOps<TestReceiver<ClippedReceiver, Info>>(info);
}
+
+class SaveLayerSimpleReceiver : public TestReceiver<SaveLayerSimpleReceiver, Info>::Client {
+public:
+ void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, info.index++);
+ EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
+ EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
+
+ Matrix4 expectedTransform;
+ expectedTransform.loadTranslate(-10, -10, 0);
+ EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
+ }
+ void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, info.index++);
+ EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
+ EXPECT_TRUE(state.computedState.transform.isIdentity());
+ }
+};
+TEST(OpReorderer, saveLayerSimple) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, SkCanvas::kClipToLayer_SaveFlag);
+ canvas.drawRect(10, 10, 190, 190, SkPaint());
+ canvas.restore();
+ });
+
+ OpReorderer reorderer;
+ reorderer.defer(200, 200, *dl);
+
+ Info info;
+ reorderer.replayBakedOps<TestReceiver<SaveLayerSimpleReceiver, Info>>(info);
+ EXPECT_EQ(2, info.index);
}
+
+
+// saveLayer1 {rect1, saveLayer2 { rect2 } } will play back as rect2, rect1, layerOp2, layerOp1
+class SaveLayerNestedReceiver : public TestReceiver<SaveLayerNestedReceiver, Info>::Client {
+public:
+ void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
+ const int index = info.index++;
+ if (index == 0) {
+ EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
+ } else if (index == 1) {
+ EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
+ } else { FAIL(); }
+ }
+ void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override {
+ const int index = info.index++;
+ if (index == 2) {
+ EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
+ } else if (index == 3) {
+ EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
+ } else { FAIL(); }
+ }
+};
+TEST(OpReorderer, saveLayerNested) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(800, 800, [](RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(0, 0, 800, 800, 128, SkCanvas::kClipToLayer_SaveFlag);
+ {
+ canvas.drawRect(0, 0, 800, 800, SkPaint());
+ canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
+ {
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ }
+ canvas.restore();
+ }
+ canvas.restore();
+ });
+
+ OpReorderer reorderer;
+ reorderer.defer(800, 800, *dl);
+
+ Info info;
+ reorderer.replayBakedOps<TestReceiver<SaveLayerNestedReceiver, Info>>(info);
+ EXPECT_EQ(4, info.index);
}
+
+TEST(OpReorderer, saveLayerContentRejection) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
+ canvas.saveLayerAlpha(200, 200, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
+
+ // draw within save layer may still be recorded, but shouldn't be drawn
+ canvas.drawRect(200, 200, 400, 400, SkPaint());
+
+ canvas.restore();
+ canvas.restore();
+ });
+ OpReorderer reorderer;
+ reorderer.defer(200, 200, *dl);
+ Info info;
+
+ // should see no ops, even within the layer, since the layer should be rejected
+ reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info);
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/unit_tests/RecordingCanvasTests.cpp b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
index ce25fc6..c023123 100644
--- a/libs/hwui/unit_tests/RecordingCanvasTests.cpp
+++ b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
@@ -24,11 +24,11 @@
namespace uirenderer {
static void playbackOps(const DisplayList& displayList,
- std::function<void(const RecordedOp&)> opReciever) {
+ std::function<void(const RecordedOp&)> opReceiver) {
for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
RecordedOp* op = displayList.getOps()[opIndex];
- opReciever(*op);
+ opReceiver(*op);
}
}
}
@@ -109,5 +109,123 @@
ASSERT_EQ(2, count); // two draws observed
}
+TEST(RecordingCanvas, saveLayerSimple) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10, 20, 190, 180, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ canvas.drawRect(10, 20, 190, 180, SkPaint());
+ canvas.restore();
+ });
+ int count = 0;
+ playbackOps(*dl, [&count](const RecordedOp& op) {
+ Matrix4 expectedMatrix;
+ switch(count++) {
+ case 0:
+ EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
+ // TODO: add asserts
+ break;
+ case 1:
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(Rect(0, 0, 180, 160), op.localClipRect);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ expectedMatrix.loadTranslate(-10, -20, 0);
+ EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+ break;
+ case 2:
+ EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
+ // TODO: add asserts
+ break;
+ default:
+ FAIL();
+ }
+ });
+ EXPECT_EQ(3, count);
}
+
+TEST(RecordingCanvas, saveLayerViewportCrop) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ // shouldn't matter, since saveLayer will clip to its bounds
+ canvas.clipRect(-1000, -1000, 1000, 1000, SkRegion::kReplace_Op);
+
+ canvas.saveLayerAlpha(100, 100, 300, 300, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ canvas.restore();
+ });
+ int count = 0;
+ playbackOps(*dl, [&count](const RecordedOp& op) {
+ if (count++ == 1) {
+ Matrix4 expectedMatrix;
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+
+ // recorded clip rect should be intersection of
+ // viewport and saveLayer bounds, in layer space
+ EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect);
+ EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
+ expectedMatrix.loadTranslate(-100, -100, 0);
+ EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+ }
+ });
+ EXPECT_EQ(3, count);
}
+
+TEST(RecordingCanvas, saveLayerRotateUnclipped) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ canvas.translate(100, 100);
+ canvas.rotate(45);
+ canvas.translate(-50, -50);
+
+ canvas.saveLayerAlpha(0, 0, 100, 100, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.restore();
+
+ canvas.restore();
+ });
+ int count = 0;
+ playbackOps(*dl, [&count](const RecordedOp& op) {
+ if (count++ == 1) {
+ Matrix4 expectedMatrix;
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+
+ // recorded rect doesn't see rotate, since recorded relative to saveLayer bounds
+ EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect);
+ EXPECT_EQ(Rect(0, 0, 100, 100), op.unmappedBounds);
+ expectedMatrix.loadIdentity();
+ EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+ }
+ });
+ EXPECT_EQ(3, count);
+}
+
+TEST(RecordingCanvas, saveLayerRotateClipped) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ canvas.translate(100, 100);
+ canvas.rotate(45);
+ canvas.translate(-200, -200);
+
+ // area of saveLayer will be clipped to parent viewport, so we ask for 400x400...
+ canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ canvas.restore();
+
+ canvas.restore();
+ });
+ int count = 0;
+ playbackOps(*dl, [&count](const RecordedOp& op) {
+ if (count++ == 1) {
+ Matrix4 expectedMatrix;
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+
+ // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
+ // the parent 200x200 viewport, but prior to rotation
+ EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), op.localClipRect);
+ EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
+ expectedMatrix.loadIdentity();
+ EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+ }
+ });
+ EXPECT_EQ(3, count);
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
index bb58928..99ecc9b 100644
--- a/libs/hwui/unit_tests/TestUtils.h
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -17,8 +17,11 @@
#define TEST_UTILS_H
#include <Matrix.h>
-#include <Snapshot.h>
+#include <Rect.h>
#include <RenderNode.h>
+#include <renderstate/RenderState.h>
+#include <renderthread/RenderThread.h>
+#include <Snapshot.h>
#include <memory>
@@ -28,6 +31,12 @@
#define EXPECT_MATRIX_APPROX_EQ(a, b) \
EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
+#define EXPECT_RECT_APPROX_EQ(a, b) \
+ EXPECT_TRUE(MathUtils::areEqual(a.left, b.left) \
+ && MathUtils::areEqual(a.top, b.top) \
+ && MathUtils::areEqual(a.right, b.right) \
+ && MathUtils::areEqual(a.bottom, b.bottom));
+
class TestUtils {
public:
static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
@@ -48,7 +57,9 @@
static SkBitmap createSkBitmap(int width, int height) {
SkBitmap bitmap;
- bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
+ SkImageInfo info = SkImageInfo::MakeUnknown(width, height);
+ bitmap.setInfo(info);
+ bitmap.allocPixels(info);
return bitmap;
}
@@ -78,6 +89,32 @@
node->syncProperties();
node->syncDisplayList();
}
+
+ typedef std::function<void(RenderState& state, Caches& caches)> RtCallback;
+
+ class TestTask : public renderthread::RenderTask {
+ public:
+ TestTask(RtCallback rtCallback)
+ : rtCallback(rtCallback) {}
+ virtual ~TestTask() {}
+ virtual void run() override {
+ // RenderState only valid once RenderThread is running, so queried here
+ RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
+
+ renderState.onGLContextCreated();
+ rtCallback(renderState, Caches::getInstance());
+ renderState.onGLContextDestroyed();
+ };
+ RtCallback rtCallback;
+ };
+
+ /**
+ * NOTE: requires surfaceflinger to run, otherwise this method will wait indefinitely.
+ */
+ static void runOnRenderThread(RtCallback rtCallback) {
+ TestTask task(rtCallback);
+ renderthread::RenderThread::getInstance().queueAndWait(&task);
+ }
}; // class TestUtils
} /* namespace uirenderer */
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 0f86bc6..4a1d7e7 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -78,7 +78,7 @@
mLocked.pointerAlpha = 0.0f; // pointer is initially faded
mLocked.pointerSprite = mSpriteController->createSprite();
mLocked.pointerIconChanged = false;
- mLocked.requestedPointerShape = 0;
+ mLocked.requestedPointerShape = mPolicy->getDefaultPointerIconId();
mLocked.buttonState = 0;
@@ -512,7 +512,7 @@
if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
if (mLocked.presentation == PRESENTATION_POINTER) {
- if (mLocked.requestedPointerShape == 0) {
+ if (mLocked.requestedPointerShape == mPolicy->getDefaultPointerIconId()) {
mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
} else {
std::map<int, SpriteIcon>::const_iterator iter =
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 308ff12..24a1681 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -58,7 +58,8 @@
public:
virtual void loadPointerResources(PointerResources* outResources) = 0;
- virtual void loadAdditionalMouseResources(std::map<int, SpriteIcon>* outResources) = 0;
+ virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources) = 0;
+ virtual int32_t getDefaultPointerIconId() = 0;
};
diff --git a/packages/DocumentsUI/res/color/item_doc_list_background_activated.xml b/packages/DocumentsUI/res/color/item_doc_list_background_activated.xml
index 90e2b7e..7d7a110 100644
--- a/packages/DocumentsUI/res/color/item_doc_list_background_activated.xml
+++ b/packages/DocumentsUI/res/color/item_doc_list_background_activated.xml
@@ -16,10 +16,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:state_focused="true"
- android:color="@color/platform_blue_a200"
- android:alpha="0.1" />
- <item
android:state_activated="true"
android:color="?android:attr/colorAccent"
android:alpha="0.1" />
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
index d124320..231e110 100644
--- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -14,10 +14,16 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.ListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/item_doc_list_background">
+ android:background="@drawable/item_doc_list_background"
+ android:orientation="horizontal">
+
+ <View
+ android:id="@+id/focus_indicator"
+ android:layout_width="4dp"
+ android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
@@ -121,4 +127,4 @@
</LinearLayout>
-</FrameLayout>
+</com.android.documentsui.ListItem>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index c576669..085df35 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -14,10 +14,16 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.DocListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/item_doc_list_background">
+ android:background="@drawable/item_doc_list_background"
+ android:orientation="horizontal">
+
+ <View
+ android:id="@+id/focus_indicator"
+ android:layout_width="4dp"
+ android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
@@ -131,4 +137,4 @@
</LinearLayout>
-</FrameLayout>
+</com.android.documentsui.DocListItem>
diff --git a/packages/DocumentsUI/res/values-af/config.xml b/packages/DocumentsUI/res/values-af/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-af/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-am/config.xml b/packages/DocumentsUI/res/values-am/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-am/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ar/config.xml b/packages/DocumentsUI/res/values-ar/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ar/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/config.xml b/packages/DocumentsUI/res/values-az-rAZ/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-az-rAZ/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-bg/config.xml b/packages/DocumentsUI/res/values-bg/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-bg/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/config.xml b/packages/DocumentsUI/res/values-bn-rBD/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-bn-rBD/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ca/config.xml b/packages/DocumentsUI/res/values-ca/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ca/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-cs/config.xml b/packages/DocumentsUI/res/values-cs/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-cs/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-da/config.xml b/packages/DocumentsUI/res/values-da/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-da/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-de/config.xml b/packages/DocumentsUI/res/values-de/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-de/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-el/config.xml b/packages/DocumentsUI/res/values-el/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-el/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/config.xml b/packages/DocumentsUI/res/values-en-rAU/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-en-rAU/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/config.xml b/packages/DocumentsUI/res/values-en-rGB/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-en-rGB/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/config.xml b/packages/DocumentsUI/res/values-en-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-en-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/config.xml b/packages/DocumentsUI/res/values-es-rUS/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-es-rUS/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-es/config.xml b/packages/DocumentsUI/res/values-es/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-es/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/config.xml b/packages/DocumentsUI/res/values-et-rEE/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-et-rEE/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/config.xml b/packages/DocumentsUI/res/values-eu-rES/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-eu-rES/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-fa/config.xml b/packages/DocumentsUI/res/values-fa/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-fa/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-fi/config.xml b/packages/DocumentsUI/res/values-fi/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-fi/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/config.xml b/packages/DocumentsUI/res/values-fr-rCA/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-fr-rCA/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-fr/config.xml b/packages/DocumentsUI/res/values-fr/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-fr/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/config.xml b/packages/DocumentsUI/res/values-gl-rES/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-gl-rES/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/config.xml b/packages/DocumentsUI/res/values-gu-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-gu-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-hi/config.xml b/packages/DocumentsUI/res/values-hi/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-hi/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-hr/config.xml b/packages/DocumentsUI/res/values-hr/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-hr/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-hu/config.xml b/packages/DocumentsUI/res/values-hu/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-hu/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/config.xml b/packages/DocumentsUI/res/values-hy-rAM/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-hy-rAM/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-in/config.xml b/packages/DocumentsUI/res/values-in/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-in/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/config.xml b/packages/DocumentsUI/res/values-is-rIS/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-is-rIS/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-it/config.xml b/packages/DocumentsUI/res/values-it/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-it/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-iw/config.xml b/packages/DocumentsUI/res/values-iw/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-iw/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ja/config.xml b/packages/DocumentsUI/res/values-ja/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ja/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/config.xml b/packages/DocumentsUI/res/values-ka-rGE/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ka-rGE/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/config.xml b/packages/DocumentsUI/res/values-kk-rKZ/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-kk-rKZ/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/config.xml b/packages/DocumentsUI/res/values-km-rKH/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-km-rKH/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/config.xml b/packages/DocumentsUI/res/values-kn-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-kn-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ko/config.xml b/packages/DocumentsUI/res/values-ko/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ko/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/config.xml b/packages/DocumentsUI/res/values-ky-rKG/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ky-rKG/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/config.xml b/packages/DocumentsUI/res/values-lo-rLA/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-lo-rLA/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-lt/config.xml b/packages/DocumentsUI/res/values-lt/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-lt/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-lv/config.xml b/packages/DocumentsUI/res/values-lv/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-lv/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/config.xml b/packages/DocumentsUI/res/values-mk-rMK/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-mk-rMK/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/config.xml b/packages/DocumentsUI/res/values-ml-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ml-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/config.xml b/packages/DocumentsUI/res/values-mn-rMN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-mn-rMN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/config.xml b/packages/DocumentsUI/res/values-mr-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-mr-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/config.xml b/packages/DocumentsUI/res/values-ms-rMY/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ms-rMY/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/config.xml b/packages/DocumentsUI/res/values-my-rMM/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-my-rMM/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-nb/config.xml b/packages/DocumentsUI/res/values-nb/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-nb/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/config.xml b/packages/DocumentsUI/res/values-ne-rNP/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ne-rNP/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-nl/config.xml b/packages/DocumentsUI/res/values-nl/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-nl/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/config.xml b/packages/DocumentsUI/res/values-pa-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-pa-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-pl/config.xml b/packages/DocumentsUI/res/values-pl/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-pl/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/config.xml b/packages/DocumentsUI/res/values-pt-rBR/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-pt-rBR/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/config.xml b/packages/DocumentsUI/res/values-pt-rPT/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-pt-rPT/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-pt/config.xml b/packages/DocumentsUI/res/values-pt/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-pt/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ro/config.xml b/packages/DocumentsUI/res/values-ro/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ro/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ru/config.xml b/packages/DocumentsUI/res/values-ru/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ru/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/config.xml b/packages/DocumentsUI/res/values-si-rLK/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-si-rLK/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sk/config.xml b/packages/DocumentsUI/res/values-sk/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sk/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sl/config.xml b/packages/DocumentsUI/res/values-sl/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sl/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/config.xml b/packages/DocumentsUI/res/values-sq-rAL/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sq-rAL/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sr/config.xml b/packages/DocumentsUI/res/values-sr/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sr/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sv/config.xml b/packages/DocumentsUI/res/values-sv/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sv/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw/config.xml b/packages/DocumentsUI/res/values-sw/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/config.xml b/packages/DocumentsUI/res/values-ta-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ta-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/config.xml b/packages/DocumentsUI/res/values-te-rIN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-te-rIN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-th/config.xml b/packages/DocumentsUI/res/values-th/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-th/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-tl/config.xml b/packages/DocumentsUI/res/values-tl/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-tl/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-tr/config.xml b/packages/DocumentsUI/res/values-tr/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-tr/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-uk/config.xml b/packages/DocumentsUI/res/values-uk/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-uk/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/config.xml b/packages/DocumentsUI/res/values-ur-rPK/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-ur-rPK/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/config.xml b/packages/DocumentsUI/res/values-uz-rUZ/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-uz-rUZ/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-vi/config.xml b/packages/DocumentsUI/res/values-vi/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-vi/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/config.xml b/packages/DocumentsUI/res/values-zh-rCN/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-zh-rCN/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/config.xml b/packages/DocumentsUI/res/values-zh-rHK/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-zh-rHK/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/config.xml b/packages/DocumentsUI/res/values-zh-rTW/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-zh-rTW/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-zu/config.xml b/packages/DocumentsUI/res/values-zu/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-zu/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
+</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 7662689..45a8907 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -68,6 +68,7 @@
import android.support.v7.widget.RecyclerView.OnItemTouchListener;
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.support.v7.widget.SimpleItemAnimator;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Formatter;
@@ -79,12 +80,12 @@
import android.view.ActionMode;
import android.view.DragEvent;
import android.view.GestureDetector;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
@@ -97,10 +98,12 @@
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
+import com.android.internal.annotations.GuardedBy;
import com.google.common.collect.Lists;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -134,6 +137,7 @@
private Model mModel;
private MultiSelectManager mSelectionManager;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
+ private ItemClickListener mItemClickListener = new ItemClickListener();
private View mEmptyView;
private RecyclerView mRecView;
@@ -238,7 +242,7 @@
// TODO: Rather than update columns on layout changes, push this
// code (or something like it) into GridLayoutManager.
mRecView.addOnLayoutChangeListener(
- new OnLayoutChangeListener() {
+ new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(
@@ -251,6 +255,9 @@
}
});
+ // TODO: Restore transition animations. See b/24802917.
+ ((SimpleItemAnimator) mRecView.getItemAnimator()).setSupportsChangeAnimations(false);
+
// TODO: Add a divider between views (which might use RecyclerView.ItemDecoration).
if (DEBUG_ENABLE_DND) {
setupDragAndDropOnDirectoryView(mRecView);
@@ -450,7 +457,10 @@
}
private boolean onSingleTapUp(MotionEvent e) {
- if (Events.isTouchEvent(e) && mSelectionManager.getSelection().isEmpty()) {
+ // Only respond to touch events. Single-click mouse events are selection events and are
+ // handled by the selection manager. Tap events that occur while the selection manager is
+ // active are also selection events.
+ if (Events.isTouchEvent(e) && !mSelectionManager.hasSelection()) {
int position = getEventAdapterPosition(e);
if (position != RecyclerView.NO_POSITION) {
return handleViewItem(position);
@@ -825,7 +835,7 @@
Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
.setAction(
R.string.undo,
- new android.view.View.OnClickListener() {
+ new View.OnClickListener() {
@Override
public void onClick(View view) {}
})
@@ -889,10 +899,16 @@
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
- private static final class DocumentHolder extends RecyclerView.ViewHolder {
+ private static final class DocumentHolder
+ extends RecyclerView.ViewHolder
+ implements View.OnKeyListener
+ {
// each data item is just a string in this case
public View view;
public String docId; // The stable document id.
+ private ClickListener mClickListener;
+ private View.OnKeyListener mKeyListener;
+
public DocumentHolder(View view) {
super(view);
this.view = view;
@@ -900,6 +916,38 @@
// So we set it here. Note that touch mode focus is a separate issue - see
// View.setFocusableInTouchMode and View.isInTouchMode for more info.
this.view.setFocusable(true);
+ this.view.setOnKeyListener(this);
+ }
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // Intercept enter key-up events, and treat them as clicks. Forward other events.
+ if (event.getAction() == KeyEvent.ACTION_UP &&
+ keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (mClickListener != null) {
+ mClickListener.onClick(this);
+ }
+ return true;
+ } else if (mKeyListener != null) {
+ return mKeyListener.onKey(v, keyCode, event);
+ }
+ return false;
+ }
+
+ public void addClickListener(ClickListener listener) {
+ // Just handle one for now; switch to a list if necessary.
+ checkState(mClickListener == null);
+ mClickListener = listener;
+ }
+
+ public void addOnKeyListener(View.OnKeyListener listener) {
+ // Just handle one for now; switch to a list if necessary.
+ checkState(mKeyListener == null);
+ mKeyListener = listener;
+ }
+
+ interface ClickListener {
+ public void onClick(DocumentHolder doc);
}
}
@@ -952,10 +1000,11 @@
default:
throw new IllegalStateException("Unsupported layout mode.");
}
- // Key event bubbling doesn't work properly, so instead of setting one key listener on
- // the RecyclerView, we have to set it on each Item. See b/24865023.
- item.setOnKeyListener(mSelectionManager);
- return new DocumentHolder(item);
+
+ DocumentHolder holder = new DocumentHolder(item);
+ holder.addClickListener(mItemClickListener);
+ holder.addOnKeyListener(mSelectionManager);
+ return holder;
}
@Override
@@ -1696,6 +1745,9 @@
private Context mContext;
private int mCursorCount;
private boolean mIsLoading;
+ @GuardedBy("mPendingDelete")
+ private Boolean mPendingDelete = false;
+ @GuardedBy("mPendingDelete")
private SparseBooleanArray mMarkedForDeletion = new SparseBooleanArray();
private UpdateListener mUpdateListener;
@Nullable private Cursor mCursor;
@@ -1740,35 +1792,39 @@
}
int getItemCount() {
- return mCursorCount - mMarkedForDeletion.size();
+ synchronized(mPendingDelete) {
+ return mCursorCount - mMarkedForDeletion.size();
+ }
}
Cursor getItem(int position) {
- // Items marked for deletion are masked out of the UI. To do this, for every marked
- // item whose position is less than the requested item position, advance the requested
- // position by 1.
- final int originalPos = position;
- final int size = mMarkedForDeletion.size();
- for (int i = 0; i < size; ++i) {
- // It'd be more concise, but less efficient, to iterate over positions while calling
- // mMarkedForDeletion.get. Instead, iterate over deleted entries.
- if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
- ++position;
+ synchronized(mPendingDelete) {
+ // Items marked for deletion are masked out of the UI. To do this, for every marked
+ // item whose position is less than the requested item position, advance the requested
+ // position by 1.
+ final int originalPos = position;
+ final int size = mMarkedForDeletion.size();
+ for (int i = 0; i < size; ++i) {
+ // It'd be more concise, but less efficient, to iterate over positions while calling
+ // mMarkedForDeletion.get. Instead, iterate over deleted entries.
+ if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
+ ++position;
+ }
}
- }
- if (DEBUG && position != originalPos) {
- Log.d(TAG, "Item position adjusted for deletion. Original: " + originalPos
- + " Adjusted: " + position);
- }
+ if (DEBUG && position != originalPos) {
+ Log.d(TAG, "Item position adjusted for deletion. Original: " + originalPos
+ + " Adjusted: " + position);
+ }
- if (position >= mCursorCount) {
- throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
- mCursorCount + " items");
- }
+ if (position >= mCursorCount) {
+ throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
+ mCursorCount + " items");
+ }
- mCursor.moveToPosition(position);
- return mCursor;
+ mCursor.moveToPosition(position);
+ return mCursor;
+ }
}
private boolean isEmpty() {
@@ -1801,17 +1857,19 @@
}
List<DocumentInfo> getDocumentsMarkedForDeletion() {
- final int size = mMarkedForDeletion.size();
- List<DocumentInfo> docs = new ArrayList<>(size);
+ synchronized (mPendingDelete) {
+ final int size = mMarkedForDeletion.size();
+ List<DocumentInfo> docs = new ArrayList<>(size);
- for (int i = 0; i < size; ++i) {
- final int position = mMarkedForDeletion.keyAt(i);
- checkState(position < mCursorCount);
- mCursor.moveToPosition(position);
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
- docs.add(doc);
+ for (int i = 0; i < size; ++i) {
+ final int position = mMarkedForDeletion.keyAt(i);
+ checkState(position < mCursorCount);
+ mCursor.moveToPosition(position);
+ final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
+ docs.add(doc);
+ }
+ return docs;
}
- return docs;
}
/**
@@ -1822,17 +1880,23 @@
* @param selected A selection representing the files to delete.
*/
void markForDeletion(Selection selected) {
- // Only one deletion operation at a time.
- checkState(mMarkedForDeletion.size() == 0);
- // There should never be more to delete than what exists.
- checkState(mCursorCount >= selected.size());
+ synchronized (mPendingDelete) {
+ mPendingDelete = true;
+ // Only one deletion operation at a time.
+ checkState(mMarkedForDeletion.size() == 0);
+ // There should never be more to delete than what exists.
+ checkState(mCursorCount >= selected.size());
- final int size = selected.size();
- for (int i = 0; i < size; ++i) {
- int position = selected.get(i);
- if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion");
- mMarkedForDeletion.append(position, true);
- mViewAdapter.notifyItemRemoved(position);
+ int[] positions = selected.getAll();
+ Arrays.sort(positions);
+
+ // Walk backwards through the set, since we're removing positions.
+ // Otherwise, positions would change after the first modification.
+ for (int p = positions.length - 1; p >= 0; p--) {
+ mMarkedForDeletion.append(positions[p], true);
+ mViewAdapter.notifyItemRemoved(positions[p]);
+ if (DEBUG) Log.d(TAG, "Scheduled " + positions[p] + " for delete.");
+ }
}
}
@@ -1841,17 +1905,24 @@
* unmarked, and restored in the UI. See {@link #markForDeletion(Selection)}.
*/
void undoDeletion() {
- // Iterate over deleted items, temporarily marking them false in the deletion list, and
- // re-adding them to the UI.
- final int size = mMarkedForDeletion.size();
- for (int i = 0; i < size; ++i) {
- final int position = mMarkedForDeletion.keyAt(i);
- mMarkedForDeletion.put(position, false);
- mViewAdapter.notifyItemInserted(position);
+ synchronized (mPendingDelete) {
+ // Iterate over deleted items, temporarily marking them false in the deletion list, and
+ // re-adding them to the UI.
+ final int size = mMarkedForDeletion.size();
+ for (int i = 0; i < size; ++i) {
+ final int position = mMarkedForDeletion.keyAt(i);
+ mMarkedForDeletion.put(position, false);
+ mViewAdapter.notifyItemInserted(position);
+ }
+ resetDeleteData();
}
+ }
- // Then, clear the deletion list.
- mMarkedForDeletion.clear();
+ private void resetDeleteData() {
+ synchronized (mPendingDelete) {
+ mPendingDelete = false;
+ mMarkedForDeletion.clear();
+ }
}
/**
@@ -1862,9 +1933,16 @@
* snackbars) for errors, info, etc.
*/
void finalizeDeletion(DeletionListener listener) {
- final ContentResolver resolver = mContext.getContentResolver();
- DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
- task.execute();
+ synchronized (mPendingDelete) {
+ if (mPendingDelete) {
+ // Necessary to avoid b/25072545. Even when that's resolved, this
+ // is a nice safe thing to day.
+ mPendingDelete = false;
+ final ContentResolver resolver = mContext.getContentResolver();
+ DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
+ task.execute();
+ }
+ }
}
/**
@@ -1921,7 +1999,7 @@
} else {
if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
}
- mMarkedForDeletion.clear();
+ resetDeleteData();
mListener.onCompletion();
}
@@ -1957,6 +2035,18 @@
}
}
+ private class ItemClickListener implements DocumentHolder.ClickListener {
+ @Override
+ public void onClick(DocumentHolder doc) {
+ final int position = doc.getAdapterPosition();
+ if (mSelectionManager.hasSelection()) {
+ mSelectionManager.toggleSelection(position);
+ } else {
+ handleViewItem(position);
+ }
+ }
+ }
+
private class ModelUpdateListener extends Model.UpdateListener {
@Override
public void onModelUpdate(Model model) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ListItem.java b/packages/DocumentsUI/src/com/android/documentsui/ListItem.java
new file mode 100644
index 0000000..5c40f1b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/ListItem.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Layout for a single item in List mode. This class overrides the default focus listener in order
+ * to light up a focus indicator when it is focused.
+ */
+public class ListItem extends LinearLayout
+{
+ public ListItem(Context context) {
+ super(context);
+ }
+
+ public ListItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+ View indicator = findViewById(R.id.focus_indicator);
+ if (gainFocus) {
+ TypedValue color = new TypedValue();
+ getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, color, true);
+ indicator.setBackgroundColor(color.data);
+ } else {
+ indicator.setBackgroundColor(android.R.color.transparent);
+ }
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 87c037d..ef53d53 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -183,6 +183,10 @@
mCallbacks.add(callback);
}
+ public boolean hasSelection() {
+ return !mSelection.isEmpty();
+ }
+
/**
* Returns a Selection object that provides a live view
* on the current selection.
@@ -217,7 +221,7 @@
*/
@VisibleForTesting
public boolean setItemSelected(int position, boolean selected) {
- if (mSingleSelect && !mSelection.isEmpty()) {
+ if (mSingleSelect && hasSelection()) {
clearSelectionQuietly();
}
return setItemsSelected(position, 1, selected);
@@ -263,7 +267,7 @@
private void clearSelectionQuietly() {
mRanger = null;
- if (mSelection.isEmpty()) {
+ if (!hasSelection()) {
return;
}
if (mIntermediateSelection == null) {
@@ -292,7 +296,7 @@
@VisibleForTesting
boolean onSingleTapUp(InputEvent input) {
if (DEBUG) Log.d(TAG, "Processing tap event.");
- if (mSelection.isEmpty()) {
+ if (!hasSelection()) {
// if this is a mouse click on an item, start selection mode.
// TODO: && input.isPrimaryButtonPressed(), but it is returning false.
if (input.isOverItem() && input.isMouseEvent()) {
@@ -335,7 +339,7 @@
*
* @param position
*/
- private void toggleSelection(int position) {
+ void toggleSelection(int position) {
// Position may be special "no position" during certain
// transitional phases. If so, skip handling of the event.
if (position == RecyclerView.NO_POSITION) {
@@ -351,7 +355,7 @@
if (!canSelect) {
return;
}
- if (mSingleSelect && !mSelection.isEmpty()) {
+ if (mSingleSelect && hasSelection()) {
clearSelectionQuietly();
}
@@ -398,7 +402,7 @@
if (selected) {
boolean canSelect = notifyBeforeItemStateChange(i, true);
if (canSelect) {
- if (mSingleSelect && !mSelection.isEmpty()) {
+ if (mSingleSelect && hasSelection()) {
clearSelectionQuietly();
}
selectAndNotify(i);
@@ -597,6 +601,14 @@
mTotalSelection = new SparseBooleanArray();
}
+ @VisibleForTesting
+ public Selection(int... positions) {
+ this();
+ for (int i = 0; i < positions.length; i++) {
+ add(positions[i]);
+ }
+ }
+
/**
* @param position
* @return true if the position is currently selected.
@@ -620,6 +632,18 @@
}
/**
+ * Returns an unordered array of selected positions.
+ */
+ public int[] getAll() {
+ final int size = size();
+ int[] positions = new int[size];
+ for (int i = 0; i < size; i++) {
+ positions[i] = get(i);
+ }
+ return positions;
+ }
+
+ /**
* @return size of the selection.
*/
public int size() {
@@ -1959,7 +1983,11 @@
}
if (searchDir != -1) {
View targetView = view.focusSearch(searchDir);
- target = mEnvironment.getAdapterPositionForChildView(targetView);
+ // TargetView can be null, for example, if the user pressed <down> at the bottom of
+ // the list.
+ if (targetView != null) {
+ target = mEnvironment.getAdapterPositionForChildView(targetView);
+ }
}
}
@@ -1972,18 +2000,13 @@
mEnvironment.focusItem(target);
if (event.isShiftPressed()) {
- if (mSelection.isEmpty()) {
+ if (!hasSelection()) {
// If there is no selection, start a selection when the user presses shift-arrow.
toggleSelection(mEnvironment.getAdapterPositionForChildView(view));
- } else {
- // Deal with b/24802917 (selected items can't be focused) by adjusting the
- // selection sorted the focused item isn't in the selection.
- target -= Integer.signum(target - mRanger.mBegin);
- mRanger.snapSelection(target);
}
- } else if (!event.isShiftPressed() && !mSelection.isEmpty()) {
- // If there is a selection, clear it if the user presses arrow with no shift.
- clearSelection();
+
+ mRanger.snapSelection(target);
+ notifySelectionChanged();
}
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index c2b64fb..4bd6ae6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -36,7 +36,7 @@
import android.util.Log;
import com.android.documentsui.model.RootInfo;
-
+import com.android.internal.annotations.GuardedBy;
import com.google.common.util.concurrent.AbstractFuture;
import libcore.io.IoUtils;
@@ -79,6 +79,7 @@
private final RootsCache mRoots;
private final State mState;
+ @GuardedBy("mTasks")
private final HashMap<RootInfo, RecentTask> mTasks = new HashMap<>();
private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
@@ -165,6 +166,12 @@
@Override
public DirectoryResult loadInBackground() {
+ synchronized (mTasks) {
+ return loadInBackgroundLocked();
+ }
+ }
+
+ private DirectoryResult loadInBackgroundLocked() {
if (mFirstPassLatch == null) {
// First time through we kick off all the recent tasks, and wait
// around to see if everyone finishes quickly.
@@ -302,8 +309,10 @@
// Ensure the loader is stopped
onStopLoading();
- for (RecentTask task : mTasks.values()) {
- IoUtils.closeQuietly(task);
+ synchronized (mTasks) {
+ for (RecentTask task : mTasks.values()) {
+ IoUtils.closeQuietly(task);
+ }
}
IoUtils.closeQuietly(mResult);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
index ace9e27..36d880a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
@@ -32,10 +32,6 @@
import com.android.documentsui.model.DocumentInfo;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-
public class DirectoryFragmentModelTest extends AndroidTestCase {
@@ -117,15 +113,6 @@
assertEquals("0", docs.get(0).documentId);
assertEquals("1", docs.get(1).documentId);
assertEquals("4", docs.get(2).documentId);
-
- TestDeletionListener testListener = new TestDeletionListener();
- model.finalizeDeletion(testListener);
- testListener.waitForDone();
-
- docs = getDocumentInfo(0, 1, 2);
- assertEquals("0", docs.get(0).documentId);
- assertEquals("1", docs.get(1).documentId);
- assertEquals("2", docs.get(2).documentId);
}
// Tests that Model.getItem returns the right items after a deletion is undone.
@@ -149,20 +136,12 @@
};
}
- private void delete(int... items) {
- Selection sel = new Selection();
- for (int item: items) {
- sel.add(item);
- }
- model.markForDeletion(sel);
+ private void delete(int... positions) {
+ model.markForDeletion(new Selection(positions));
}
- private List<DocumentInfo> getDocumentInfo(int... items) {
- Selection sel = new Selection();
- for (int item: items) {
- sel.add(item);
- }
- return model.getDocuments(sel);
+ private List<DocumentInfo> getDocumentInfo(int... positions) {
+ return model.getDocuments(new Selection(positions));
}
private static class DummyListener extends Model.UpdateListener {
@@ -177,20 +156,4 @@
return null;
}
}
-
- private static class TestDeletionListener extends Model.DeletionListener {
- final CountDownLatch mSignal = new CountDownLatch(1);
-
- @Override
- public void onCompletion() {
- mSignal.countDown();
- }
-
- public void waitForDone() {
- try {
- boolean timeout = mSignal.await(10, TimeUnit.SECONDS);
- assertTrue("Timed out waiting for deletion completion", timeout);
- } catch (InterruptedException e) {}
- }
- }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
index cc510a9..9e874bd 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -18,6 +18,7 @@
import android.content.res.Resources;
import android.database.MatrixCursor;
+import android.media.MediaFile;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
import android.provider.DocumentsContract;
@@ -70,30 +71,18 @@
}
static String formatTypeToMimeType(int format) {
- // TODO: Add complete list of mime types.
- switch (format) {
- case MtpConstants.FORMAT_ASSOCIATION:
- return DocumentsContract.Document.MIME_TYPE_DIR;
- case MtpConstants.FORMAT_MP3:
- return "audio/mp3";
- case MtpConstants.FORMAT_EXIF_JPEG:
- return "image/jpeg";
- default:
- return "application/octet-stream";
+ if (format == MtpConstants.FORMAT_ASSOCIATION) {
+ return DocumentsContract.Document.MIME_TYPE_DIR;
+ } else {
+ return MediaFile.getMimeTypeForFormatCode(format);
}
}
- static int mimeTypeToFormatType(String mimeType) {
- // TODO: Add complete list of mime types.
- switch (mimeType.toLowerCase()) {
- case Document.MIME_TYPE_DIR:
- return MtpConstants.FORMAT_ASSOCIATION;
- case "audio/mp3":
- return MtpConstants.FORMAT_MP3;
- case "image/jpeg":
- return MtpConstants.FORMAT_EXIF_JPEG;
- default:
- return MtpConstants.FORMAT_UNDEFINED;
+ static int mimeTypeToFormatType(String fileName, String mimeType) {
+ if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ return MtpConstants.FORMAT_ASSOCIATION;
+ } else {
+ return MediaFile.getFormatCode(fileName, mimeType);
}
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 9d5850b..7883e61 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -242,7 +242,7 @@
new MtpObjectInfo.Builder()
.setStorageId(parentId.mStorageId)
.setParent(parentId.mObjectHandle)
- .setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
+ .setFormat(CursorHelper.mimeTypeToFormatType(displayName, mimeType))
.setName(displayName)
.build(), pipe[1]);
final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index 0380e21..f935f31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -19,6 +19,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.BluetoothLeScanner;
import android.content.Context;
import android.os.ParcelUuid;
import android.util.Log;
@@ -106,6 +107,10 @@
return mAdapter.getScanMode();
}
+ public BluetoothLeScanner getBluetoothLeScanner() {
+ return mAdapter.getBluetoothLeScanner();
+ }
+
public int getState() {
return mAdapter.getState();
}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 314b3c4..0cc2a67 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -3,7 +3,7 @@
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) \
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) $(call all-Iaidl-files-under, src) \
src/com/android/systemui/EventLogTags.logtags
LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8fc7ad0..5d622a0 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -127,6 +127,9 @@
<!-- Assist -->
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
+ <!-- Listen for keyboard attachment / detachment -->
+ <uses-permission android:name="android.permission.TABLET_MODE" />
+
<!-- Self permission for internal broadcasts. -->
<permission android:name="com.android.systemui.permission.SELF"
android:protectionLevel="signature" />
@@ -196,6 +199,11 @@
android:value="com.android.settings.category.system" />
</activity>
+ <!-- Service used by secondary users to register themselves with the system user. -->
+ <service android:name=".recents.RecentsSystemUserService"
+ android:exported="false"
+ android:permission="com.android.systemui.permission.SELF" />
+
<!-- Alternate Recents -->
<activity android:name=".recents.RecentsActivity"
android:label="@string/accessibility_desc_recent_apps"
@@ -212,17 +220,6 @@
</intent-filter>
</activity>
- <receiver android:name=".recents.RecentsUserEventProxyReceiver"
- android:exported="false">
- <intent-filter>
- <action android:name="com.android.systemui.recents.action.SHOW_RECENTS_FOR_USER" />
- <action android:name="com.android.systemui.recents.action.HIDE_RECENTS_FOR_USER" />
- <action android:name="com.android.systemui.recents.action.TOGGLE_RECENTS_FOR_USER" />
- <action android:name="com.android.systemui.recents.action.PRELOAD_RECENTS_FOR_USER" />
- <action android:name="com.android.systemui.recents.action.CONFIG_CHANGED_FOR_USER" />
- </intent-filter>
- </receiver>
-
<!-- Callback for dismissing screenshot notification after a share target is picked -->
<receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
android:process=":screenshot"
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 59fed5b..f430fa5 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -19,14 +19,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:paddingBottom="@dimen/navigation_bar_size"
android:background="@drawable/qs_customizer_background"
android:gravity="center_horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?android:attr/colorPrimary">
+ android:background="@drawable/notification_header_bg">
<LinearLayout
android:id="@+id/drag_buttons"
@@ -72,8 +71,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:navigationContentDescription="@*android:string/action_bar_up_description"
- style="?android:attr/toolbarStyle"
- android:background="?android:attr/colorPrimary" />
+ android:background="@drawable/notification_header_bg"
+ style="?android:attr/toolbarStyle" />
</FrameLayout>
<com.android.systemui.tuner.AutoScrollView
@@ -105,4 +104,10 @@
android:elevation="@dimen/fab_elevation"
android:background="@drawable/fab_background" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/navigation_bar_size"
+ android:layout_gravity="bottom"
+ android:background="#ff000000" />
+
</com.android.systemui.qs.customize.QSCustomizer>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 0b8da83..6187070 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-** Copyright 2015, The Android Open Source Project
+** Copyright 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.
@@ -32,55 +32,21 @@
android:focusable="true"
>
+ <com.android.systemui.qs.QuickQSPanel
+ android:id="@+id/quick_qs_panel"
+ android:background="#0000"
+ android:layout_width="142dp"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true" />
+
<LinearLayout
android:id="@+id/expanded_group"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:paddingEnd="12dp"
- android:orientation="horizontal">
-
- <com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:drawablePadding="6dp"
- android:drawableStart="@drawable/ic_access_alarms_small"
- android:textColor="#64ffffff"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:paddingEnd="6dp"
- android:paddingStart="6dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:background="?android:attr/selectableItemBackground"
- android:visibility="gone"
- />
-
- <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:layout_below="@id/clock"
- systemui:datePattern="EEE"
- android:gravity="center_vertical"
- android:textSize="20sp"
- android:paddingTop="16dp"
- android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin" />
-
- <include layout="@layout/split_clock_view"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="16dp"
- android:layout_marginTop="16dp"
- android:id="@+id/clock"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" />
-
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="horizontal"
+ android:layout_alignParentEnd="true">
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/settings_button_container"
android:layout_width="48dp"
@@ -105,8 +71,57 @@
android:src="@drawable/tuner" />
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_expand_less"
+ android:tint="@android:color/white" />
</LinearLayout>
+ <FrameLayout
+ android:id="@+id/date_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
+ android:layout_alignParentBottom="true">
+ <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
+ android:layout_below="@id/clock"
+ systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm"
+ />
+ </FrameLayout>
+
+ <include layout="@layout/split_clock_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_above="@id/date_group"
+ android:id="@+id/clock"
+ />
+
+ <com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_toEndOf="@id/date_group"
+ android:layout_marginBottom="4dp"
+ android:drawablePadding="6dp"
+ android:drawableStart="@drawable/ic_access_alarms_small"
+ android:textColor="#64ffffff"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
+ android:paddingEnd="6dp"
+ android:paddingStart="6dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
+
<include
android:id="@+id/qs_detail_header"
layout="@layout/qs_detail_header"
@@ -115,12 +130,6 @@
android:layout_alignParentBottom="true"
/>
- <com.android.systemui.qs.QuickQSPanel
- android:id="@+id/quick_qs_panel"
- android:background="#0000"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/qs_detail_header_progress"
android:src="@drawable/indeterminate_anim"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 4d07cdb..f50abf7 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c1180b6..e507e64 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
<string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
<string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index fc2941f..1098af1 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -444,4 +444,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
<string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
<string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 04d680b..4b5309c 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
<string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ca45d24..70cf7f8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
<string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 7df68ac..fd61c8b 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
<string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
<string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index c85fac6..8eac5d9 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Torna a ordenar la Configuració ràpida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a la Configuració ràpida"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index d58b11b..e1b0256 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -444,4 +444,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
<string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index f300b3e..745bf5a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -85,13 +85,13 @@
<string name="accessibility_search_light" msgid="1103867596330271848">"Søg"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
<string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
- <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Voice Assist"</string>
+ <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Taleassistent"</string>
<string name="accessibility_unlock_button" msgid="128158454631118828">"Lås op"</string>
<string name="accessibility_unlock_button_fingerprint" msgid="8214125623493923751">"Knap til oplåsning. Venter på fingeraftryk"</string>
<string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Lås op uden at bruge dit fingeraftryk"</string>
<string name="unlock_label" msgid="8779712358041029439">"lås op"</string>
<string name="phone_label" msgid="2320074140205331708">"åbn telefon"</string>
- <string name="voice_assist_label" msgid="3956854378310019854">"åbn voice assist"</string>
+ <string name="voice_assist_label" msgid="3956854378310019854">"åbn taleassistent"</string>
<string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>
<string name="recents_caption_resize" msgid="3517056471774958200">"Vælg nyt opgavelayout"</string>
<string name="cancel" msgid="6442560571259935130">"Annuller"</string>
@@ -315,7 +315,7 @@
<string name="notification_tap_again" msgid="8524949573675922138">"Tryk igen for at åbne"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Stryg opad for at låse op"</string>
<string name="phone_hint" msgid="4872890986869209950">"Stryg fra telefonikonet"</string>
- <string name="voice_hint" msgid="8939888732119726665">"Stryg fra ikonet for voice assist"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"Stryg fra mikrofonikonet"</string>
<string name="camera_hint" msgid="7939688436797157483">"Stryg fra kameraikonet"</string>
<string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Helt lydløs. Denne handling slukker også skærmlæsere."</string>
<string name="interruption_level_none" msgid="6000083681244492992">"Total stilhed"</string>
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
<string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index ac513e40..796cce2 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
<string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c8ff7c6..1dcfb7b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
<string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
<string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 6e66842..d991f16 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 6e66842..d991f16 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 6e66842..d991f16 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
<string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 72258fa..4eef099 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 298a0c6..5dfb878 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 26b3081..d3d51209 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
<string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 83aac20..d48373c 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
<string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
<string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 3efd33d..f9e2b22 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
<string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
<string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 3154d5c..7816337 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
<string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
<string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 669ca9b..66c435c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
<string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
<string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d42190f..5b39201 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
<string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
<string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 3c53983..e5329ed 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 0887e75..38594be 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
<string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
<string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 11a0d3a..2abf37b 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
<string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
<string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index eec3a6f..30f22b7 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -441,4 +441,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
<string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 2dc9ba0..e1a57f9 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
<string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
<string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index a7fdb43..6124ef2 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
<string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index a6a68d4..2ce7a5b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
<string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 83468e5..cb95cde 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
<string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
<string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 4449a0a..1e0cec7 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
<string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 31c5126..88c6fbd 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
<string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
<string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d1603ff..6006f64 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
<string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
<string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index e5e9003..f74a434 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
<string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
<string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 946d86b..4483303 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
<string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
<string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 264438b..9b17ffc 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
<string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
<string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 1696076..7401340 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
<string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
<string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d053b53..1f7fec7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
<string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
<string name="experimental" msgid="6198182315536726162">"베타"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index ec4bec7..00ce218 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
<string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index e5d784f..92dbb4d 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ຈັດວາງການຕັ້ງຄ່າດ່ວນຄືນໃໝ່"</string>
<string name="show_brightness" msgid="6613930842805942519">"ສະແດງຄວາມແຈ້ງຢູ່ໃນການຕັ້ງຄ່າດ່ວນ"</string>
<string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ca50956..304afe4 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
<string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a87d918..a1a437d 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -441,4 +441,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
<string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 1015018..808943b 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
<string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 45ec29a..7724f34 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
<string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
<string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 1051e49..cecf5af 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -438,4 +438,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
<string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
<string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 66843fc..b253849 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
<string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्ये चमक दर्शवा"</string>
<string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index c50e214..5a94581 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
<string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
<string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index f4fd3d1..855df4d 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
<string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
<string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cae404d..d662464 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
<string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
<string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 563bc87..8333fb0 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
<string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
<string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index bf9f0f2..3bca7c4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
<string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
<string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 45d56cc..d431999 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
<string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
<string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2807c5a..e1a57be 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
<string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index c8400c9..e94318b 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
<string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 43088fe9..a41ee93 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c8400c9..e94318b 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
<string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
<string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d64ca7c..64560b9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -441,4 +441,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
<string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 480de30..7487393 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -444,4 +444,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
<string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
<string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index e784601..c54f0ff 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
<string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
<string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 15612ee..adde8be 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -444,4 +444,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
<string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 23e4233..2542807 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
<string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
<string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 771ad53..a710477 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
<string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
<string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f3abc81..c171a60 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -441,4 +441,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
<string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 6427644..fae5ab9 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
<string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
<string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index de39e9b..5b46a7e 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
<string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
<string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index a895df7..477b715 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
<string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
<string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c34a33d..f718669a 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్ల ఏర్పాటు క్రమం మార్చు"</string>
<string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్ల్లో ప్రకాశం చూపు"</string>
<string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d777a0a..ca4000a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
<string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
<string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 292d3a2..5e8bb7a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
<string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
<string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9c42e93..dbca4c7 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
<string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
<string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9638e80..8f8793c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
<string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
<string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 8c2fb64..086f9e2 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
<string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
<string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 0ad5a69..b1a556a 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
<string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
<string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index c1aeeb4..e22909c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
<string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
<string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index fe1c311..9d32567 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速设置"</string>
<string name="show_brightness" msgid="6613930842805942519">"在快速设置中显示亮度栏"</string>
<string name="experimental" msgid="6198182315536726162">"实验性"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index d39adc0..d80eb72 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
<string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
<string name="experimental" msgid="6198182315536726162">"實驗版"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 6606167..e7a4450 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -442,4 +442,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
<string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
<string name="experimental" msgid="6198182315536726162">"實驗性"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 229c16b..06dc0c9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -440,4 +440,10 @@
<string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
<string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
<string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
+ <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
+ <skip />
+ <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5661657..cbc92f2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -125,6 +125,7 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_tile_height">88dp</dimen>
+ <dimen name="qs_new_tile_height">100dp</dimen>
<dimen name="qs_quick_actions_height">88dp</dimen>
<dimen name="qs_quick_actions_padding">25dp</dimen>
<dimen name="qs_page_indicator_size">12dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a525fbb..6fe7e6a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1167,4 +1167,14 @@
<string name="qs_customize_info" translatable="false">Info</string>
<string name="qs_customize_remove" translatable="false">Remove</string>
+ <!-- Dialog title asking if Bluetooth should be enabled [CHAR LIMIT=NONE] -->
+ <string name="enable_bluetooth_title">Turn on Bluetooth?</string>
+
+ <!-- Dialog message explaining why Bluetooth should be enabled when a packaged keyboard is
+ conncted to the device [CHAR LIMIT=NONE] -->
+ <string name="enable_bluetooth_message">To connect your keyboard with your tablet, you first have to turn on Bluetooth.</string>
+
+ <!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
+ <string name="enable_bluetooth_confirmation_ok">Turn on</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 5bf251b..9551fb7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -50,6 +50,7 @@
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class,
+ com.android.systemui.keyboard.KeyboardUI.class,
};
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
new file mode 100644
index 0000000..64f3e13f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+public class BluetoothDialog extends SystemUIDialog {
+
+ public BluetoothDialog(Context context) {
+ super(context);
+
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ setShowForAllUsers(true);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
new file mode 100644
index 0000000..96ee397
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard;
+
+import android.app.AlertDialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanRecord;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.view.WindowManager;
+
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeChangedListener {
+ private static final String TAG = "KeyboardUI";
+ private static final boolean DEBUG = false;
+
+ // Give BT some time to start after SyUI comes up. This avoids flashing a dialog in the user's
+ // face because BT starts a little bit later in the boot process than SysUI and it takes some
+ // time for us to receive the signal that it's starting.
+ private static final long BLUETOOTH_START_DELAY_MILLIS = 10 * 1000;
+
+ private static final int STATE_NOT_ENABLED = -1;
+ private static final int STATE_UNKNOWN = 0;
+ private static final int STATE_WAITING_FOR_BOOT_COMPLETED = 1;
+ private static final int STATE_WAITING_FOR_TABLET_MODE_EXIT = 2;
+ private static final int STATE_WAITING_FOR_DEVICE_DISCOVERY = 3;
+ private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
+ private static final int STATE_WAITING_FOR_STATE_PAIRED = 5;
+ private static final int STATE_PAIRING = 6;
+ private static final int STATE_PAIRED = 7;
+ private static final int STATE_USER_CANCELLED = 8;
+ private static final int STATE_DEVICE_NOT_FOUND = 9;
+
+ private static final int MSG_INIT = 0;
+ private static final int MSG_ON_BOOT_COMPLETED = 1;
+ private static final int MSG_PROCESS_KEYBOARD_STATE = 2;
+ private static final int MSG_ENABLE_BLUETOOTH = 3;
+ private static final int MSG_ON_BLUETOOTH_STATE_CHANGED = 4;
+ private static final int MSG_ON_DEVICE_BOND_STATE_CHANGED = 5;
+ private static final int MSG_ON_BLUETOOTH_DEVICE_ADDED = 6;
+ private static final int MSG_ON_BLE_SCAN_FAILED = 7;
+ private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
+ private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
+
+ private volatile KeyboardHandler mHandler;
+ private volatile KeyboardUIHandler mUIHandler;
+
+ protected volatile Context mContext;
+
+ private boolean mEnabled;
+ private String mKeyboardName;
+ private CachedBluetoothDeviceManager mCachedDeviceManager;
+ private LocalBluetoothAdapter mLocalBluetoothAdapter;
+ private LocalBluetoothProfileManager mProfileManager;
+ private boolean mBootCompleted;
+ private long mBootCompletedTime;
+
+ private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
+ private ScanCallback mScanCallback;
+ private BluetoothDialog mDialog;
+
+ private int mState;
+
+ @Override
+ public void start() {
+ mContext = super.mContext;
+ HandlerThread thread = new HandlerThread("Keyboard", Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ mHandler = new KeyboardHandler(thread.getLooper());
+ mHandler.sendEmptyMessage(MSG_INIT);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("KeyboardUI:");
+ pw.println(" mEnabled=" + mEnabled);
+ pw.println(" mBootCompleted=" + mEnabled);
+ pw.println(" mBootCompletedTime=" + mBootCompletedTime);
+ pw.println(" mKeyboardName=" + mKeyboardName);
+ pw.println(" mInTabletMode=" + mInTabletMode);
+ pw.println(" mState=" + stateToString(mState));
+ }
+
+ @Override
+ protected void onBootCompleted() {
+ mHandler.sendEmptyMessage(MSG_ON_BOOT_COMPLETED);
+ }
+
+ @Override
+ public void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTabletModeChanged(" + whenNanos + ", " + inTabletMode + ")");
+ }
+
+ if (inTabletMode && mInTabletMode != InputManager.SWITCH_STATE_ON
+ || !inTabletMode && mInTabletMode != InputManager.SWITCH_STATE_OFF) {
+ mInTabletMode = inTabletMode ?
+ InputManager.SWITCH_STATE_ON : InputManager.SWITCH_STATE_OFF;
+ processKeyboardState();
+ }
+ }
+
+ // Shoud only be called on the handler thread
+ private void init() {
+ Context context = mContext;
+ mKeyboardName =
+ context.getString(com.android.internal.R.string.config_packagedKeyboardName);
+ if (TextUtils.isEmpty(mKeyboardName)) {
+ if (DEBUG) {
+ Slog.d(TAG, "No packaged keyboard name given.");
+ }
+ return;
+ }
+
+ LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(context, null);
+ if (bluetoothManager == null) {
+ if (DEBUG) {
+ Slog.e(TAG, "Failed to retrieve LocalBluetoothManager instance");
+ }
+ return;
+ }
+ mEnabled = true;
+ mCachedDeviceManager = bluetoothManager.getCachedDeviceManager();
+ mLocalBluetoothAdapter = bluetoothManager.getBluetoothAdapter();
+ mProfileManager = bluetoothManager.getProfileManager();
+ bluetoothManager.getEventManager().registerCallback(new BluetoothCallbackHandler());
+
+ InputManager im = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
+ im.registerOnTabletModeChangedListener(this, mHandler);
+ mInTabletMode = im.isInTabletMode();
+
+ processKeyboardState();
+ mUIHandler = new KeyboardUIHandler();
+ }
+
+ // Should only be called on the handler thread
+ private void processKeyboardState() {
+ mHandler.removeMessages(MSG_PROCESS_KEYBOARD_STATE);
+
+ if (!mEnabled) {
+ mState = STATE_NOT_ENABLED;
+ return;
+ }
+
+ if (!mBootCompleted) {
+ mState = STATE_WAITING_FOR_BOOT_COMPLETED;
+ return;
+ }
+
+ if (mInTabletMode != InputManager.SWITCH_STATE_OFF) {
+ if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
+ stopScanning();
+ }
+ mState = STATE_WAITING_FOR_TABLET_MODE_EXIT;
+ return;
+ }
+
+ final int btState = mLocalBluetoothAdapter.getState();
+ if (btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON
+ && mState == STATE_WAITING_FOR_BLUETOOTH) {
+ // If we're waiting for bluetooth but it has come on in the meantime, or is coming
+ // on, just dismiss the dialog. This frequently happens during device startup.
+ mUIHandler.sendEmptyMessage(MSG_DISMISS_BLUETOOTH_DIALOG);
+ }
+
+ if (btState == BluetoothAdapter.STATE_TURNING_ON) {
+ mState = STATE_WAITING_FOR_BLUETOOTH;
+ // Wait for bluetooth to fully come on.
+ return;
+ }
+
+ if (btState != BluetoothAdapter.STATE_ON) {
+ mState = STATE_WAITING_FOR_BLUETOOTH;
+ showBluetoothDialog();
+ return;
+ }
+
+ CachedBluetoothDevice device = getPairedKeyboard();
+ if (mState == STATE_WAITING_FOR_TABLET_MODE_EXIT || mState == STATE_WAITING_FOR_BLUETOOTH) {
+ if (device != null) {
+ // If we're just coming out of tablet mode or BT just turned on,
+ // then we want to go ahead and automatically connect to the
+ // keyboard. We want to avoid this in other cases because we might
+ // be spuriously called after the user has manually disconnected
+ // the keyboard, meaning we shouldn't try to automtically connect
+ // it again.
+ mState = STATE_PAIRED;
+ device.connect(false);
+ return;
+ }
+ mCachedDeviceManager.clearNonBondedDevices();
+ }
+
+ device = getDiscoveredKeyboard();
+ if (device != null) {
+ mState = STATE_PAIRING;
+ device.startPairing();
+ } else {
+ mState = STATE_WAITING_FOR_DEVICE_DISCOVERY;
+ startScanning();
+ }
+ }
+
+ // Should only be called on the handler thread
+ public void onBootCompletedInternal() {
+ mBootCompleted = true;
+ mBootCompletedTime = SystemClock.uptimeMillis();
+ if (mState == STATE_WAITING_FOR_BOOT_COMPLETED) {
+ processKeyboardState();
+ }
+ }
+
+ // Should only be called on the handler thread
+ private void showBluetoothDialog() {
+ if (isUserSetupComplete()) {
+ long now = SystemClock.uptimeMillis();
+ long earliestDialogTime = mBootCompletedTime + BLUETOOTH_START_DELAY_MILLIS;
+ if (earliestDialogTime < now) {
+ mUIHandler.sendEmptyMessage(MSG_SHOW_BLUETOOTH_DIALOG);
+ } else {
+ mHandler.sendEmptyMessageAtTime(MSG_PROCESS_KEYBOARD_STATE, earliestDialogTime);
+ }
+ } else {
+ // If we're in setup wizard and the keyboard is docked, just automatically enable BT.
+ mLocalBluetoothAdapter.enable();
+ }
+ }
+
+ private boolean isUserSetupComplete() {
+ ContentResolver resolver = mContext.getContentResolver();
+ return Secure.getIntForUser(
+ resolver, Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ }
+
+ private CachedBluetoothDevice getPairedKeyboard() {
+ Set<BluetoothDevice> devices = mLocalBluetoothAdapter.getBondedDevices();
+ for (BluetoothDevice d : devices) {
+ if (mKeyboardName.equals(d.getName())) {
+ return getCachedBluetoothDevice(d);
+ }
+ }
+ return null;
+ }
+
+ private CachedBluetoothDevice getDiscoveredKeyboard() {
+ Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
+ for (CachedBluetoothDevice d : devices) {
+ if (d.getName().equals(mKeyboardName)) {
+ return d;
+ }
+ }
+ return null;
+ }
+
+
+ private CachedBluetoothDevice getCachedBluetoothDevice(BluetoothDevice d) {
+ CachedBluetoothDevice cachedDevice = mCachedDeviceManager.findDevice(d);
+ if (cachedDevice == null) {
+ cachedDevice = mCachedDeviceManager.addDevice(
+ mLocalBluetoothAdapter, mProfileManager, d);
+ }
+ return cachedDevice;
+ }
+
+ private void startScanning() {
+ BluetoothLeScanner scanner = mLocalBluetoothAdapter.getBluetoothLeScanner();
+ ScanFilter filter = (new ScanFilter.Builder()).setDeviceName(mKeyboardName).build();
+ ScanSettings settings = (new ScanSettings.Builder())
+ .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
+ .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .setReportDelay(0)
+ .build();
+ mScanCallback = new KeyboardScanCallback();
+ scanner.startScan(Arrays.asList(filter), settings, mScanCallback);
+ }
+
+ private void stopScanning() {
+ if (mScanCallback != null) {
+ mLocalBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
+ mScanCallback = null;
+ }
+ }
+
+ // Should only be called on the handler thread
+ private void onDeviceAddedInternal(CachedBluetoothDevice d) {
+ if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && d.getName().equals(mKeyboardName)) {
+ stopScanning();
+ d.startPairing();
+ mState = STATE_PAIRING;
+ }
+ }
+
+ // Should only be called on the handler thread
+ private void onBluetoothStateChangedInternal(int bluetoothState) {
+ if (bluetoothState == BluetoothAdapter.STATE_ON && mState == STATE_WAITING_FOR_BLUETOOTH) {
+ processKeyboardState();
+ }
+ }
+
+ // Should only be called on the handler thread
+ private void onDeviceBondStateChangedInternal(CachedBluetoothDevice d, int bondState) {
+ if (d.getName().equals(mKeyboardName) && bondState == BluetoothDevice.BOND_BONDED) {
+ // We don't need to manually connect to the device here because it will automatically
+ // try to connect after it has been paired.
+ mState = STATE_PAIRED;
+ }
+ }
+
+ // Should only be called on the handler thread
+ private void onBleScanFailedInternal() {
+ mScanCallback = null;
+ if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
+ mState = STATE_DEVICE_NOT_FOUND;
+ }
+ }
+
+ private final class KeyboardUIHandler extends Handler {
+ public KeyboardUIHandler() {
+ super(Looper.getMainLooper(), null, true /*async*/);
+ }
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_SHOW_BLUETOOTH_DIALOG: {
+ DialogInterface.OnClickListener listener = new BluetoothDialogClickListener();
+ mDialog = new BluetoothDialog(mContext);
+ mDialog.setTitle(R.string.enable_bluetooth_title);
+ mDialog.setMessage(R.string.enable_bluetooth_message);
+ mDialog.setPositiveButton(R.string.enable_bluetooth_confirmation_ok, listener);
+ mDialog.setNegativeButton(android.R.string.cancel, listener);
+ mDialog.show();
+ break;
+ }
+ case MSG_DISMISS_BLUETOOTH_DIALOG: {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private final class KeyboardHandler extends Handler {
+ public KeyboardHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_INIT: {
+ init();
+ break;
+ }
+ case MSG_ON_BOOT_COMPLETED: {
+ onBootCompletedInternal();
+ break;
+ }
+ case MSG_PROCESS_KEYBOARD_STATE: {
+ processKeyboardState();
+ break;
+ }
+ case MSG_ENABLE_BLUETOOTH: {
+ boolean enable = msg.arg1 == 1;
+ if (enable) {
+ mLocalBluetoothAdapter.enable();
+ } else {
+ mState = STATE_USER_CANCELLED;
+ }
+ }
+ case MSG_ON_BLUETOOTH_STATE_CHANGED: {
+ int bluetoothState = msg.arg1;
+ onBluetoothStateChangedInternal(bluetoothState);
+ break;
+ }
+ case MSG_ON_DEVICE_BOND_STATE_CHANGED: {
+ CachedBluetoothDevice d = (CachedBluetoothDevice)msg.obj;
+ int bondState = msg.arg1;
+ onDeviceBondStateChangedInternal(d, bondState);
+ break;
+ }
+ case MSG_ON_BLUETOOTH_DEVICE_ADDED: {
+ BluetoothDevice d = (BluetoothDevice)msg.obj;
+ CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(d);
+ onDeviceAddedInternal(cachedDevice);
+ break;
+
+ }
+ case MSG_ON_BLE_SCAN_FAILED: {
+ onBleScanFailedInternal();
+ break;
+ }
+ }
+ }
+ }
+
+ private final class BluetoothDialogClickListener implements DialogInterface.OnClickListener {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int enable = DialogInterface.BUTTON_POSITIVE == which ? 1 : 0;
+ mHandler.obtainMessage(MSG_ENABLE_BLUETOOTH, enable, 0).sendToTarget();
+ mDialog = null;
+ }
+ }
+
+ private final class KeyboardScanCallback extends ScanCallback {
+
+ private boolean isDeviceDiscoverable(ScanResult result) {
+ final ScanRecord scanRecord = result.getScanRecord();
+ final int flags = scanRecord.getAdvertiseFlags();
+ final int BT_DISCOVERABLE_MASK = 0x03;
+
+ return (flags & BT_DISCOVERABLE_MASK) != 0;
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ if (DEBUG) {
+ Slog.d(TAG, "onBatchScanResults(" + results.size() + ")");
+ }
+
+ BluetoothDevice bestDevice = null;
+ int bestRssi = Integer.MIN_VALUE;
+
+ for (ScanResult result : results) {
+ if (DEBUG) {
+ Slog.d(TAG, "onBatchScanResults: considering " + result);
+ }
+
+ if (isDeviceDiscoverable(result) && result.getRssi() > bestRssi) {
+ bestDevice = result.getDevice();
+ bestRssi = result.getRssi();
+ }
+ }
+
+ if (bestDevice != null) {
+ mHandler.obtainMessage(MSG_ON_BLUETOOTH_DEVICE_ADDED, bestDevice).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ if (DEBUG) {
+ Slog.d(TAG, "onScanFailed(" + errorCode + ")");
+ }
+ mHandler.obtainMessage(MSG_ON_BLE_SCAN_FAILED).sendToTarget();
+ }
+
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ if (DEBUG) {
+ Slog.d(TAG, "onScanResult(" + callbackType + ", " + result + ")");
+ }
+
+ if (isDeviceDiscoverable(result)) {
+ mHandler.obtainMessage(MSG_ON_BLUETOOTH_DEVICE_ADDED,
+ result.getDevice()).sendToTarget();
+ } else if (DEBUG) {
+ Slog.d(TAG, "onScanResult: device " + result.getDevice() +
+ " is not discoverable, ignoring");
+ }
+ }
+ }
+
+ private final class BluetoothCallbackHandler implements BluetoothCallback {
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
+ mHandler.obtainMessage(MSG_ON_BLUETOOTH_STATE_CHANGED,
+ bluetoothState, 0).sendToTarget();
+ }
+
+ @Override
+ public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ mHandler.obtainMessage(MSG_ON_DEVICE_BOND_STATE_CHANGED,
+ bondState, 0, cachedDevice).sendToTarget();
+ }
+
+ @Override
+ public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { }
+ @Override
+ public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { }
+ @Override
+ public void onScanningStateChanged(boolean started) { }
+ @Override
+ public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
+ }
+
+ private static String stateToString(int state) {
+ switch (state) {
+ case STATE_NOT_ENABLED:
+ return "STATE_NOT_ENABLED";
+ case STATE_WAITING_FOR_BOOT_COMPLETED:
+ return "STATE_WAITING_FOR_BOOT_COMPLETED";
+ case STATE_WAITING_FOR_TABLET_MODE_EXIT:
+ return "STATE_WAITING_FOR_TABLET_MODE_EXIT";
+ case STATE_WAITING_FOR_DEVICE_DISCOVERY:
+ return "STATE_WAITING_FOR_DEVICE_DISCOVERY";
+ case STATE_WAITING_FOR_BLUETOOTH:
+ return "STATE_WAITING_FOR_BLUETOOTH";
+ case STATE_WAITING_FOR_STATE_PAIRED:
+ return "STATE_WAITING_FOR_STATE_PAIRED";
+ case STATE_PAIRING:
+ return "STATE_PAIRING";
+ case STATE_PAIRED:
+ return "STATE_PAIRED";
+ case STATE_USER_CANCELLED:
+ return "STATE_USER_CANCELLED";
+ case STATE_DEVICE_NOT_FOUND:
+ return "STATE_DEVICE_NOT_FOUND";
+ case STATE_UNKNOWN:
+ default:
+ return "STATE_UNKNOWN";
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 32c906e..0e4a4e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -75,8 +75,6 @@
@Override
public void setTileVisibility(TileRecord tile, int visibility) {
tile.tileView.setVisibility(visibility);
-// // TODO: Do something smarter here.
-// distributeTiles();
}
@Override
@@ -104,8 +102,7 @@
for (int i = 0; i < NT; i++) {
TileRecord tile = mTiles.get(i);
if (tile.tile.getTileType() == QSTileView.QS_TYPE_QUICK) {
- tile.tileView.setType(QSTileView.QS_TYPE_QUICK);
- mFirstPage.mQuickQuickTiles.addView(tile.tileView);
+ // Don't show any quick tiles for now.
continue;
}
if (mPages.get(index).isFull()) {
@@ -161,6 +158,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mQuickQuickTiles = (LinearLayout) findViewById(R.id.quick_tile_layout);
+ mQuickQuickTiles.setVisibility(View.GONE);
mTilePage = (TilePage) findViewById(R.id.tile_page);
// Less rows on first page, because it needs room for the quick tiles.
mTilePage.mMaxRows = 3;
@@ -176,7 +174,7 @@
}
public static class TilePage extends TileLayout {
- private int mMaxRows = 4;
+ private int mMaxRows = 3;
public TilePage(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -188,6 +186,11 @@
mMaxRows = maxRows;
}
+ @Override
+ protected int getCellHeight() {
+ return mContext.getResources().getDimensionPixelSize(R.dimen.qs_new_tile_height);
+ }
+
private void clear() {
if (DEBUG) Log.d(TAG, "Clearing page");
removeAllViews();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 53d0402..a2d9ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -60,7 +60,7 @@
if (tile.getTileType() == QSTileView.QS_TYPE_QUICK) {
quickTiles.add(tile);
}
- if (quickTiles.size() == 4) {
+ if (quickTiles.size() == 2) {
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index b8342e2..12a099d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -67,7 +67,7 @@
public void updateResources() {
final Resources res = mContext.getResources();
final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
- mCellHeight = res.getDimensionPixelSize(R.dimen.qs_tile_height);
+ mCellHeight = getCellHeight();
mCellWidth = (int) (mCellHeight * TILE_ASPECT);
mLargeCellHeight = mAllowDual ? res.getDimensionPixelSize(R.dimen.qs_dual_tile_height)
: mCellHeight;
@@ -79,6 +79,10 @@
}
}
+ protected int getCellHeight() {
+ return mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
index 012633c..1669278 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
@@ -61,6 +61,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mQuickTiles = (QuickTileLayout) findViewById(R.id.quick_tile_layout);
+ mQuickTiles.setVisibility(View.GONE);
TilePage page = (PagedTileLayout.TilePage) findViewById(R.id.tile_page);
page.setMaxRows(3 /* First page only gets 3 */);
mPages.add(page);
@@ -107,12 +108,12 @@
for (int i = 0; i < NT; i++) {
TileRecord tile = mTiles.get(i);
if (tile.tile.getTileType() == QSTileView.QS_TYPE_QUICK) {
- tile.tileView.setType(QSTileView.QS_TYPE_QUICK);
- mQuickTiles.addView(tile.tileView);
+ // Ignore quick tiles for now.
continue;
}
mPages.get(index).addTile(tile);
- if (mPages.get(index).isFull()) {
+ // Keep everything in one layout for now.
+ if (false && mPages.get(index).isFull()) {
if (++index == mPages.size()) {
LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.horizontal_divider, this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 601961b..fe8d78b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -84,7 +84,7 @@
TypedValue value = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
mToolbar.setNavigationIcon(
- getResources().getDrawable(value.resourceId, mContext.getTheme()));
+ getResources().getDrawable(R.drawable.ic_close_white, mContext.getTheme()));
mToolbar.setNavigationOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -193,7 +193,8 @@
@Override
public void onClick(View v) {
if (mFab == v) {
- // TODO: Show list of tiles.
+ SystemUIDialog dialog = new SystemUIDialog(mContext);
+ dialog.show();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
new file mode 100644
index 0000000..79eca30d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+/**
+ * Due to the fact that RecentsActivity is per-user, we need to establish an
+ * interface (this) for the system user to callback to the secondary users in
+ * response to UI events coming in from the system user's SystemUI.
+ */
+oneway interface IRecentsNonSystemUserCallbacks {
+ void preloadRecents();
+ void cancelPreloadingRecents();
+ void showRecents(boolean triggeredFromAltTab);
+ void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+ void toggleRecents();
+ void onConfigurationChanged();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
new file mode 100644
index 0000000..6b49195
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+/**
+ * Due to the fact that RecentsActivity is per-user, we need to establish an
+ * interface (this) for the non-system user to register itself for callbacks and to
+ * callback to the system user to update internal state.
+ */
+oneway interface IRecentsSystemUserCallbacks {
+ void registerNonSystemUserCallbacks(IBinder nonSystemUserCallbacks, int userId);
+
+ void updateRecentsVisibility(boolean visible);
+ void startScreenPinning();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index aee3623..ae79fe2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,908 +16,385 @@
package com.android.systemui.recents;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.ITaskStackListener;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.os.AsyncTask;
import android.os.Handler;
-import android.os.SystemClock;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.MutableBoolean;
+import android.util.Log;
import android.view.Display;
-import android.view.LayoutInflater;
import android.view.View;
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.recents.misc.Console;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskGrouping;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.TaskStackView;
-import com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
-import com.android.systemui.recents.views.TaskViewHeader;
-import com.android.systemui.recents.views.TaskViewTransform;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
-/**
- * Annotation for a method that is only called from the system user's SystemUI process and will be
- * proxied to the current user.
- */
-@interface ProxyFromSystemToCurrentUser {}
-/**
- * Annotation for a method that may be called from any user's SystemUI process and will be proxied
- * to the system user.
- */
-@interface ProxyFromAnyToSystemUser {}
-/** A proxy implementation for the recents component */
+/**
+ * An implementation of the SystemUI recents component, which supports both system and secondary
+ * users.
+ */
public class Recents extends SystemUI
- implements ActivityOptions.OnAnimationStartedListener, RecentsComponent {
+ implements RecentsComponent {
+
+ private final static String TAG = "Recents";
+ private final static boolean DEBUG = false;
public final static int EVENT_BUS_PRIORITY = 1;
+ public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
- final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
- final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
- final public static String EXTRA_RECENTS_VISIBILITY = "recentsVisibility";
+ private SystemServicesProxy mSystemServicesProxy;
+ private Handler mHandler;
+ private RecentsImpl mImpl;
- // Owner proxy events
- final public static String ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER =
- "action_notify_recents_visibility_change";
- final public static String ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER =
- "action_screen_pinning_request";
+ // Only For system user, this is the callbacks instance we return to each secondary user
+ private RecentsSystemUser mSystemUserCallbacks;
- final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
- final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
- final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
+ // Only for secondary users, this is the callbacks instance provided by the system user to make
+ // calls back
+ private IRecentsSystemUserCallbacks mCallbacksToSystemUser;
- final static int sMinToggleDelay = 350;
+ // The set of runnables to run after binding to the system user's service.
+ private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>();
- public final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS";
- public final static String sRecentsPackage = "com.android.systemui";
- public final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
-
- /**
- * An implementation of ITaskStackListener, that allows us to listen for changes to the system
- * task stacks and update recents accordingly.
- */
- class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
- Handler mHandler;
-
- public TaskStackListenerImpl(Handler handler) {
- mHandler = handler;
- }
-
+ // Only for secondary users, this is the death handler for the binder from the system user
+ private final IBinder.DeathRecipient mCallbacksToSystemUserDeathRcpt = new IBinder.DeathRecipient() {
@Override
- public void onTaskStackChanged() {
- // Debounce any task stack changes
- mHandler.removeCallbacks(this);
- mHandler.post(this);
- }
+ public void binderDied() {
+ mCallbacksToSystemUser = null;
- /** Preloads the next task */
- public void run() {
- // TODO: Temporarily skip this if multi stack is enabled
- /*
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
- RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- SystemServicesProxy ssp = loader.getSystemServicesProxy();
- ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
-
- // Load the next task only if we aren't svelte
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
- loader.preloadTasks(plan, true);
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- // This callback is made when a new activity is launched and the old one is paused
- // so ignore the current activity and try and preload the thumbnail for the
- // previous one.
- if (runningTaskInfo != null) {
- launchOpts.runningTaskId = runningTaskInfo.id;
+ // Retry after a fixed duration
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ registerWithSystemUser();
}
- launchOpts.numVisibleTasks = 2;
- launchOpts.numVisibleTaskThumbnails = 2;
- launchOpts.onlyLoadForCache = true;
- launchOpts.onlyLoadPausedActivities = true;
- loader.loadTasks(mContext, plan, launchOpts);
- }
- */
+ }, BIND_TO_SYSTEM_USER_RETRY_DELAY);
}
- }
+ };
- /**
- * A proxy for Recents events which happens strictly for the owner.
- */
- class RecentsOwnerEventProxyReceiver extends BroadcastReceiver {
+ // Only for secondary users, this is the service connection we use to connect to the system user
+ private final ServiceConnection mServiceConnectionToSystemUser = new ServiceConnection() {
@Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getAction()) {
- case ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER:
- visibilityChanged(context,
- intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false));
- break;
- case ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER:
- onStartScreenPinning(context);
- break;
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (service != null) {
+ mCallbacksToSystemUser = IRecentsSystemUserCallbacks.Stub.asInterface(
+ service);
+
+ // Listen for system user's death, so that we can reconnect later
+ try {
+ service.linkToDeath(mCallbacksToSystemUserDeathRcpt, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Lost connection to (System) SystemUI", e);
+ }
+
+ // Run each of the queued runnables
+ runAndFlushOnConnectRunnables();
}
+
+ // Unbind ourselves now that we've registered our callbacks. The
+ // binder to the system user are still valid at this point.
+ mContext.unbindService(this);
}
- }
- static RecentsTaskLoadPlan sInstanceLoadPlan;
- static Recents sInstance;
-
- SystemServicesProxy mSystemServicesProxy;
- Handler mHandler;
- TaskStackListenerImpl mTaskStackListener;
- RecentsOwnerEventProxyReceiver mProxyBroadcastReceiver;
- RecentsAppWidgetHost mAppWidgetHost;
- boolean mBootCompleted;
- boolean mStartAnimationTriggered;
- boolean mCanReuseTaskStackViews = true;
-
- // Task launching
- RecentsConfiguration mConfig;
- Rect mSearchBarBounds = new Rect();
- Rect mTaskStackBounds = new Rect();
- Rect mLastTaskViewBounds = new Rect();
- TaskViewTransform mTmpTransform = new TaskViewTransform();
- int mStatusBarHeight;
- int mNavBarHeight;
- int mNavBarWidth;
- int mTaskBarHeight;
-
- // Header (for transition)
- TaskViewHeader mHeaderBar;
- final Object mHeaderBarLock = new Object();
- TaskStackView mDummyStackView;
-
- // Variables to keep track of if we need to start recents after binding
- boolean mTriggeredFromAltTab;
- long mLastToggleTime;
-
- Bitmap mThumbnailTransitionBitmapCache;
- Task mThumbnailTransitionBitmapCacheKey;
-
- public Recents() {
- }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Do nothing
+ }
+ };
/**
- * Gets the singleton instance and starts it if needed. On the primary user on the device, this
- * component gets started as a normal {@link SystemUI} component. On a secondary user, this
- * lifecycle doesn't exist, so we need to start it manually here if needed.
+ * Returns the callbacks interface that non-system users can call.
*/
- public static Recents getInstanceAndStartIfNeeded(Context ctx) {
- if (sInstance == null) {
- sInstance = new Recents();
- sInstance.mContext = ctx;
- sInstance.start();
- sInstance.onBootCompleted();
- }
- return sInstance;
+ public IBinder getSystemUserCallbacks() {
+ return mSystemUserCallbacks;
}
- /** Creates a new broadcast intent */
- static Intent createLocalBroadcastIntent(Context context, String action) {
- Intent intent = new Intent(action);
- intent.setPackage(context.getPackageName());
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
- Intent.FLAG_RECEIVER_FOREGROUND);
- return intent;
- }
-
- /** Initializes the Recents. */
- @ProxyFromSystemToCurrentUser
@Override
public void start() {
- if (sInstance == null) {
- sInstance = this;
- }
- Resources res = mContext.getResources();
- RecentsTaskLoader.initialize(mContext);
- LayoutInflater inflater = LayoutInflater.from(mContext);
mSystemServicesProxy = new SystemServicesProxy(mContext);
mHandler = new Handler();
- mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
+ mImpl = new RecentsImpl(mContext);
- // Register the task stack listener
- mTaskStackListener = new TaskStackListenerImpl(mHandler);
- mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+ // Register with the event bus
+ EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
- // Only the owner has the callback to update the SysUI visibility flags, so all non-owner
- // instances of RecentsComponent needs to notify the owner when the visibility
- // changes.
- if (mSystemServicesProxy.isForegroundUserSystem()) {
- mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction(Recents.ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
- filter.addAction(Recents.ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER);
- mContext.registerReceiverAsUser(mProxyBroadcastReceiver, UserHandle.CURRENT, filter,
- null, mHandler);
+ // Due to the fact that RecentsActivity is per-user, we need to establish and interface for
+ // the system user's Recents component to pass events (like show/hide/toggleRecents) to the
+ // secondary user, and vice versa (like visibility change, screen pinning).
+ final int processUser = mSystemServicesProxy.getProcessUser();
+ if (mSystemServicesProxy.isSystemUser(processUser)) {
+ // For the system user, initialize an instance of the interface that we can pass to the
+ // secondary user
+ mSystemUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+ } else {
+ // For the secondary user, bind to the primary user's service to get a persistent
+ // interface to register its implementation and to later update its state
+ registerWithSystemUser();
}
-
- // Initialize the static configuration resources
- mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy);
- mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
- mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
- mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
- mDummyStackView = new TaskStackView(mContext, new TaskStack());
- mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
- null, false);
- reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
-
- // When we start, preload the data associated with the previous recent tasks.
- // We can use a new plan since the caches will be the same.
- RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
- loader.preloadTasks(plan, true /* isTopTaskHome */);
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
- launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
- launchOpts.onlyLoadForCache = true;
- loader.loadTasks(mContext, plan, launchOpts);
putComponent(Recents.class, this);
}
@Override
public void onBootCompleted() {
- mBootCompleted = true;
- reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
+ mImpl.onBootCompleted();
}
- /** Shows the Recents. */
- @ProxyFromSystemToCurrentUser
+ /**
+ * Shows the Recents.
+ */
@Override
public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
- if (mSystemServicesProxy.isForegroundUserSystem()) {
- showRecentsInternal(triggeredFromAltTab);
+ int currentUser = mSystemServicesProxy.getCurrentUser();
+ if (mSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.showRecents(triggeredFromAltTab);
} else {
- Intent intent = createLocalBroadcastIntent(mContext,
- RecentsUserEventProxyReceiver.ACTION_PROXY_SHOW_RECENTS_TO_USER);
- intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.showRecents(triggeredFromAltTab);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+ }
+ }
}
}
- void showRecentsInternal(boolean triggeredFromAltTab) {
- mTriggeredFromAltTab = triggeredFromAltTab;
-
- try {
- showRecentsActivity();
- } catch (ActivityNotFoundException e) {
- Console.logRawError("Failed to launch RecentAppsIntent", e);
- }
- }
-
- /** Hides the Recents. */
- @ProxyFromSystemToCurrentUser
+ /**
+ * Hides the Recents.
+ */
@Override
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mSystemServicesProxy.isForegroundUserSystem()) {
- hideRecentsInternal(triggeredFromAltTab, triggeredFromHomeKey);
+ int currentUser = mSystemServicesProxy.getCurrentUser();
+ if (mSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
} else {
- Intent intent = createLocalBroadcastIntent(mContext,
- RecentsUserEventProxyReceiver.ACTION_PROXY_HIDE_RECENTS_TO_USER);
- intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
- intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+ }
+ }
}
}
- void hideRecentsInternal(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mBootCompleted) {
- // Defer to the activity to handle hiding recents, if it handles it, then it must still
- // be visible
- Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY);
- intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
- intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
- }
- }
-
- /** Toggles the Recents activity. */
- @ProxyFromSystemToCurrentUser
+ /**
+ * Toggles the Recents activity.
+ */
@Override
public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
- if (mSystemServicesProxy.isForegroundUserSystem()) {
- toggleRecentsInternal();
+ int currentUser = mSystemServicesProxy.getCurrentUser();
+ if (mSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.toggleRecents();
} else {
- Intent intent = createLocalBroadcastIntent(mContext,
- RecentsUserEventProxyReceiver.ACTION_PROXY_TOGGLE_RECENTS_TO_USER);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.toggleRecents();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+ }
+ }
}
}
- void toggleRecentsInternal() {
- mTriggeredFromAltTab = false;
-
- try {
- toggleRecentsActivity();
- } catch (ActivityNotFoundException e) {
- Console.logRawError("Failed to launch RecentAppsIntent", e);
- }
- }
-
- /** Preloads info for the Recents activity. */
- @ProxyFromSystemToCurrentUser
+ /**
+ * Preloads info for the Recents activity.
+ */
@Override
public void preloadRecents() {
- if (mSystemServicesProxy.isForegroundUserSystem()) {
- preloadRecentsInternal();
+ int currentUser = mSystemServicesProxy.getCurrentUser();
+ if (mSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.preloadRecents();
} else {
- Intent intent = createLocalBroadcastIntent(mContext,
- RecentsUserEventProxyReceiver.ACTION_PROXY_PRELOAD_RECENTS_TO_USER);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
- }
- }
-
- void preloadRecentsInternal() {
- // Preload only the raw task list into a new load plan (which will be consumed by the
- // RecentsActivity) only if there is a task to animate to.
- ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
- MutableBoolean topTaskHome = new MutableBoolean(true);
- RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- sInstanceLoadPlan = loader.createLoadPlan(mContext);
- if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
- sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
- loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
- TaskStack stack = sInstanceLoadPlan.getTaskStack();
- if (stack.getTaskCount() > 0) {
- preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView,
- topTaskHome.value);
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.preloadRecents();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+ }
}
}
}
@Override
public void cancelPreloadingRecents() {
- // Do nothing
- }
-
- void showRelativeAffiliatedTask(boolean showNextTask) {
- // Return early if there is no focused stack
- int focusedStackId = mSystemServicesProxy.getFocusedStack();
- RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
- loader.preloadTasks(plan, true /* isTopTaskHome */);
- TaskStack focusedStack = plan.getTaskStack();
-
- // Return early if there are no tasks in the focused stack
- if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
-
- ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
- // Return early if there is no running task (can't determine affiliated tasks in this case)
- if (runningTask == null) return;
- // Return early if the running task is in the home stack (optimization)
- if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
-
- // Find the task in the recents list
- ArrayList<Task> tasks = focusedStack.getTasks();
- Task toTask = null;
- ActivityOptions launchOpts = null;
- int taskCount = tasks.size();
- int numAffiliatedTasks = 0;
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- if (task.key.id == runningTask.id) {
- TaskGrouping group = task.group;
- Task.TaskKey toTaskKey;
- if (showNextTask) {
- toTaskKey = group.getNextTaskInGroup(task);
- launchOpts = ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_launch_next_affiliated_task_target,
- R.anim.recents_launch_next_affiliated_task_source);
- } else {
- toTaskKey = group.getPrevTaskInGroup(task);
- launchOpts = ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_launch_prev_affiliated_task_target,
- R.anim.recents_launch_prev_affiliated_task_source);
- }
- if (toTaskKey != null) {
- toTask = focusedStack.findTaskWithId(toTaskKey.id);
- }
- numAffiliatedTasks = group.getTaskCount();
- break;
- }
- }
-
- // Return early if there is no next task
- if (toTask == null) {
- if (numAffiliatedTasks > 1) {
- if (showNextTask) {
- mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
- ActivityOptions.makeCustomInPlaceAnimation(mContext,
- R.anim.recents_launch_next_affiliated_task_bounce));
- } else {
- mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
- ActivityOptions.makeCustomInPlaceAnimation(mContext,
- R.anim.recents_launch_prev_affiliated_task_bounce));
- }
- }
- return;
- }
-
- // Keep track of actually launched affiliated tasks
- MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
-
- // Launch the task
- if (toTask.isActive) {
- // Bring an active task to the foreground
- mSystemServicesProxy.moveTaskToFront(toTask.key.id, launchOpts);
+ int currentUser = mSystemServicesProxy.getCurrentUser();
+ if (mSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.cancelPreloadingRecents();
} else {
- mSystemServicesProxy.startActivityFromRecents(mContext, toTask.key.id,
- toTask.activityLabel, launchOpts);
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.cancelPreloadingRecents();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+ }
+ }
}
}
@Override
public void showNextAffiliatedTask() {
- // Keep track of when the affiliated task is triggered
- MetricsLogger.count(mContext, "overview_affiliated_task_next", 1);
- showRelativeAffiliatedTask(true);
+ mImpl.showNextAffiliatedTask();
}
@Override
public void showPrevAffiliatedTask() {
- // Keep track of when the affiliated task is triggered
- MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1);
- showRelativeAffiliatedTask(false);
+ mImpl.showPrevAffiliatedTask();
}
- /** Updates on configuration change. */
- @ProxyFromSystemToCurrentUser
+ /**
+ * Updates on configuration change.
+ */
public void onConfigurationChanged(Configuration newConfig) {
- if (mSystemServicesProxy.isForegroundUserSystem()) {
- configurationChanged();
+ int currentUser = mSystemServicesProxy.getCurrentUser();
+ if (mSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.onConfigurationChanged();
} else {
- Intent intent = createLocalBroadcastIntent(mContext,
- RecentsUserEventProxyReceiver.ACTION_PROXY_CONFIG_CHANGE_TO_USER);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
- }
- }
- void configurationChanged() {
- // Don't reuse task stack views if the configuration changes
- mCanReuseTaskStackViews = false;
- mConfig.updateOnConfigurationChange();
- }
-
- /**
- * Prepares the header bar layout for the next transition, if the task view bounds has changed
- * since the last call, it will attempt to re-measure and layout the header bar to the new size.
- *
- * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
- * is not already bound (can be expensive)
- */
- void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
- Rect windowRect = mSystemServicesProxy.getWindowRect();
-
- // Update the configuration for the current state
- mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
-
- if (tryAndBindSearchWidget) {
- // Try and pre-emptively bind the search widget on startup to ensure that we
- // have the right thumbnail bounds to animate to.
- // Note: We have to reload the widget id before we get the task stack bounds below
- if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
- mConfig.getSearchBarBounds(windowRect,
- mStatusBarHeight, mSearchBarBounds);
- }
- }
- Rect systemInsets = new Rect(0, mStatusBarHeight,
- (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
- (mConfig.hasTransposedNavBar ? 0 : mNavBarHeight));
- mConfig.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
- mSearchBarBounds, mTaskStackBounds);
-
- // Rebind the header bar and draw it for the transition
- TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
- Rect taskStackBounds = new Rect(mTaskStackBounds);
- algo.setSystemInsets(systemInsets);
- algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
- Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
- if (!taskViewBounds.equals(mLastTaskViewBounds)) {
- mLastTaskViewBounds.set(taskViewBounds);
-
- int taskViewWidth = taskViewBounds.width();
- synchronized (mHeaderBarLock) {
- mHeaderBar.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
- mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
- }
- }
- }
-
- /** Toggles the recents activity */
- void toggleRecentsActivity() {
- // If the user has toggled it too quickly, then just eat up the event here (it's better than
- // showing a janky screenshot).
- // NOTE: Ideally, the screenshot mechanism would take the window transform into account
- if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
- return;
- }
-
- // If Recents is the front most activity, then we should just communicate with it directly
- // to launch the first task or dismiss itself
- ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
- MutableBoolean isTopTaskHome = new MutableBoolean(true);
- if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
- // Notify recents to toggle itself
- Intent intent = createLocalBroadcastIntent(mContext, ACTION_TOGGLE_RECENTS_ACTIVITY);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
- mLastToggleTime = SystemClock.elapsedRealtime();
- return;
- } else {
- // Otherwise, start the recents activity
- showRecentsActivity(topTask, isTopTaskHome.value);
- }
- }
-
- /** Shows the recents activity if it is not already running */
- void showRecentsActivity() {
- // Check if the top task is in the home stack, and start the recents activity
- ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
- MutableBoolean isTopTaskHome = new MutableBoolean(true);
- if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
- showRecentsActivity(topTask, isTopTaskHome.value);
- }
- }
-
- /**
- * Creates the activity options for a unknown state->recents transition.
- */
- ActivityOptions getUnknownTransitionActivityOptions() {
- mStartAnimationTriggered = false;
- return ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_from_unknown_enter,
- R.anim.recents_from_unknown_exit,
- mHandler, this);
- }
-
- /**
- * Creates the activity options for a home->recents transition.
- */
- ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
- mStartAnimationTriggered = false;
- if (fromSearchHome) {
- return ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_from_search_launcher_enter,
- R.anim.recents_from_search_launcher_exit,
- mHandler, this);
- }
- return ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_from_launcher_enter,
- R.anim.recents_from_launcher_exit,
- mHandler, this);
- }
-
- /**
- * Creates the activity options for an app->recents transition.
- */
- ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
- TaskStack stack, TaskStackView stackView) {
-
- // Update the destination rect
- Task toTask = new Task();
- TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
- topTask.id, toTask);
- Rect toTaskRect = toTransform.rect;
- Bitmap thumbnail;
- if (mThumbnailTransitionBitmapCacheKey != null
- && mThumbnailTransitionBitmapCacheKey.key != null
- && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
- thumbnail = mThumbnailTransitionBitmapCache;
- mThumbnailTransitionBitmapCacheKey = null;
- mThumbnailTransitionBitmapCache = null;
- } else {
- preloadIcon(topTask);
- thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
- }
- if (thumbnail != null) {
- mStartAnimationTriggered = false;
- return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
- toTaskRect.height(), mHandler, this);
- }
-
- // If both the screenshot and thumbnail fails, then just fall back to the default transition
- return getUnknownTransitionActivityOptions();
- }
-
- /**
- * Preloads the icon of a task.
- */
- void preloadIcon(ActivityManager.RunningTaskInfo task) {
-
- // Ensure that we load the running task's icon
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.runningTaskId = task.id;
- launchOpts.loadThumbnails = false;
- launchOpts.onlyLoadForCache = true;
- RecentsTaskLoader.getInstance().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
- }
-
- /**
- * Caches the header thumbnail used for a window animation asynchronously into
- * {@link #mThumbnailTransitionBitmapCache}.
- */
- void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
- TaskStack stack, TaskStackView stackView, boolean isTopTaskHome) {
- preloadIcon(topTask);
-
- // Update the header bar if necessary
- reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
-
- // Update the destination rect
- mDummyStackView.updateMinMaxScrollForStack(stack);
- final Task toTask = new Task();
- final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
- topTask.id, toTask);
- new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- return drawThumbnailTransitionBitmap(toTask, toTransform);
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap) {
- mThumbnailTransitionBitmapCache = bitmap;
- mThumbnailTransitionBitmapCacheKey = toTask;
- }
- }.execute();
- }
-
- /**
- * Draws the header of a task used for the window animation into a bitmap.
- */
- Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
- if (toTransform != null && toTask.key != null) {
- Bitmap thumbnail;
- synchronized (mHeaderBarLock) {
- int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
- int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
- thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
- Bitmap.Config.ARGB_8888);
- if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
- thumbnail.eraseColor(0xFFff0000);
- } else {
- Canvas c = new Canvas(thumbnail);
- c.scale(toTransform.scale, toTransform.scale);
- mHeaderBar.rebindToTask(toTask);
- mHeaderBar.draw(c);
- c.setBitmap(null);
- }
- }
- return thumbnail.createAshmemBitmap();
- }
- return null;
- }
-
- /** Returns the transition rect for the given task id. */
- TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, TaskStackView stackView,
- int runningTaskId, Task runningTaskOut) {
- // Find the running task in the TaskStack
- Task task = null;
- ArrayList<Task> tasks = stack.getTasks();
- if (runningTaskId != -1) {
- // Otherwise, try and find the task with the
- int taskCount = tasks.size();
- for (int i = taskCount - 1; i >= 0; i--) {
- Task t = tasks.get(i);
- if (t.key.id == runningTaskId) {
- task = t;
- runningTaskOut.copyFrom(t);
- break;
- }
- }
- }
- if (task == null) {
- // If no task is specified or we can not find the task just use the front most one
- task = tasks.get(tasks.size() - 1);
- runningTaskOut.copyFrom(task);
- }
-
- // Get the transform for the running task
- stackView.getScroller().setStackScrollToInitialState();
- mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
- stackView.getScroller().getStackScroll(), mTmpTransform, null);
- return mTmpTransform;
- }
-
- /** Shows the recents activity */
- void showRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
- RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-
- // Update the header bar if necessary
- reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
-
- if (sInstanceLoadPlan == null) {
- // Create a new load plan if onPreloadRecents() was never triggered
- sInstanceLoadPlan = loader.createLoadPlan(mContext);
- }
-
- if (!sInstanceLoadPlan.hasTasks()) {
- loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
- }
- TaskStack stack = sInstanceLoadPlan.getTaskStack();
-
- // Prepare the dummy stack for the transition
- mDummyStackView.updateMinMaxScrollForStack(stack);
- TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
- mDummyStackView.computeStackVisibilityReport();
- boolean hasRecentTasks = stack.getTaskCount() > 0;
- boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
-
- if (useThumbnailTransition) {
- // Try starting with a thumbnail transition
- ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
- mDummyStackView);
- if (opts != null) {
- startRecentsActivity(topTask, opts, false /* fromHome */,
- false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
- } else {
- // Fall through below to the non-thumbnail transition
- useThumbnailTransition = false;
- }
- }
-
- if (!useThumbnailTransition) {
- // If there is no thumbnail transition, but is launching from home into recents, then
- // use a quick home transition and do the animation from home
- if (hasRecentTasks) {
- String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
- String searchWidgetPackage =
- Prefs.getString(mContext, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);
-
- // Determine whether we are coming from a search owned home activity
- boolean fromSearchHome = (homeActivityPackage != null) &&
- homeActivityPackage.equals(searchWidgetPackage);
- ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
- startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
- false /* fromThumbnail */, stackVr);
- } else {
- // Otherwise we do the normal fade from an unknown source
- ActivityOptions opts = getUnknownTransitionActivityOptions();
- startRecentsActivity(topTask, opts, true /* fromHome */,
- false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
- }
- }
- mLastToggleTime = SystemClock.elapsedRealtime();
- }
-
- /** Starts the recents activity */
- void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
- ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
- TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
- // Update the configuration based on the launch options
- RecentsActivityLaunchState launchState = mConfig.getLaunchState();
- launchState.launchedFromHome = fromSearchHome || fromHome;
- launchState.launchedFromSearchHome = fromSearchHome;
- launchState.launchedFromAppWithThumbnail = fromThumbnail;
- launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
- launchState.launchedWithAltTab = mTriggeredFromAltTab;
- launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
- launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
- launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
- launchState.launchedHasConfigurationChanged = false;
-
- Intent intent = new Intent(sToggleRecentsAction);
- intent.setClassName(sRecentsPackage, sRecentsActivity);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- if (opts != null) {
- mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
- } else {
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- }
- mCanReuseTaskStackViews = true;
- }
-
- /** Notifies the callbacks that the visibility of Recents has changed. */
- @ProxyFromAnyToSystemUser
- public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp,
- boolean visible) {
- if (ssp.isForegroundUserSystem()) {
- visibilityChanged(context, visible);
- } else {
- Intent intent = createLocalBroadcastIntent(context,
- ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
- intent.putExtra(EXTRA_RECENTS_VISIBILITY, visible);
- context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
- }
- }
- static void visibilityChanged(Context context, boolean visible) {
- // For the primary user, the context for the SystemUI component is the SystemUIApplication
- SystemUIApplication app = (SystemUIApplication)
- getInstanceAndStartIfNeeded(context.getApplicationContext()).mContext;
- PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
- if (statusBar != null) {
- statusBar.updateRecentsVisibility(visible);
- }
- }
-
- /** Notifies the status bar to trigger screen pinning. */
- @ProxyFromAnyToSystemUser
- public static void startScreenPinning(Context context, SystemServicesProxy ssp) {
- if (ssp.isForegroundUserSystem()) {
- onStartScreenPinning(context);
- } else {
- Intent intent = createLocalBroadcastIntent(context,
- ACTION_PROXY_SCREEN_PINNING_REQUEST_TO_OWNER);
- context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
- }
- }
- static void onStartScreenPinning(Context context) {
- // For the primary user, the context for the SystemUI component is the SystemUIApplication
- SystemUIApplication app = (SystemUIApplication)
- getInstanceAndStartIfNeeded(context.getApplicationContext()).mContext;
- PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
- if (statusBar != null) {
- statusBar.showScreenPinningRequest(false);
- }
- }
-
- /**
- * Returns the preloaded load plan and invalidates it.
- */
- public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
- RecentsTaskLoadPlan plan = sInstanceLoadPlan;
- sInstanceLoadPlan = null;
- return plan;
- }
-
- /**** OnAnimationStartedListener Implementation ****/
-
- @Override
- public void onAnimationStarted() {
- // Notify recents to start the enter animation
- if (!mStartAnimationTriggered) {
- // There can be a race condition between the start animation callback and
- // the start of the new activity (where we register the receiver that listens
- // to this broadcast, so we add our own receiver and if that gets called, then
- // we know the activity has not yet started and we can retry sending the broadcast.
- BroadcastReceiver fallbackReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (getResultCode() == Activity.RESULT_OK) {
- mStartAnimationTriggered = true;
- return;
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.onConfigurationChanged();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
}
-
- // Schedule for the broadcast to be sent again after some time
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- onAnimationStarted();
- }
- }, 25);
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
}
- };
-
- // Send the broadcast to notify Recents that the animation has started
- Intent intent = createLocalBroadcastIntent(mContext, ACTION_START_ENTER_ANIMATION);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
- fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
+ }
}
}
+
+ /**
+ * Handle Recents activity visibility changed.
+ */
+ public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
+ int processUser = event.systemServicesProxy.getProcessUser();
+ if (event.systemServicesProxy.isSystemUser(processUser)) {
+ mImpl.onVisibilityChanged(event.applicationContext, event.visible);
+ } else {
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallbacksToSystemUser.updateRecentsVisibility(event.visible);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Handle screen pinning request.
+ */
+ public final void onBusEvent(final ScreenPinningRequestEvent event) {
+ int processUser = event.systemServicesProxy.getProcessUser();
+ if (event.systemServicesProxy.isSystemUser(processUser)) {
+ mImpl.onStartScreenPinning(event.applicationContext);
+ } else {
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallbacksToSystemUser.startScreenPinning();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Attempts to register with the system user.
+ */
+ private void registerWithSystemUser() {
+ final int processUser = mSystemServicesProxy.getProcessUser();
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallbacksToSystemUser.registerNonSystemUserCallbacks(mImpl, processUser);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Runs the runnable in the system user's Recents context, connecting to the service if
+ * necessary.
+ */
+ private void postToSystemUser(final Runnable onConnectRunnable) {
+ mOnConnectRunnables.add(onConnectRunnable);
+ if (mCallbacksToSystemUser == null) {
+ Intent systemUserServiceIntent = new Intent();
+ systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
+ boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
+ mServiceConnectionToSystemUser, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+ if (!bound) {
+ // Retry after a fixed duration
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ registerWithSystemUser();
+ }
+ }, BIND_TO_SYSTEM_USER_RETRY_DELAY);
+ }
+ } else {
+ runAndFlushOnConnectRunnables();
+ }
+ }
+
+ /**
+ * Runs all the queued runnables after a service connection is made.
+ */
+ private void runAndFlushOnConnectRunnables() {
+ for (Runnable r : mOnConnectRunnables) {
+ r.run();
+ }
+ mOnConnectRunnables.clear();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index e647c1f..fa1c887 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -39,6 +39,8 @@
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.DismissTaskEvent;
import com.android.systemui.recents.events.ui.ResizeTaskEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
@@ -127,20 +129,20 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(Recents.ACTION_HIDE_RECENTS_ACTIVITY)) {
- if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
+ if (action.equals(RecentsImpl.ACTION_HIDE_RECENTS_ACTIVITY)) {
+ if (intent.getBooleanExtra(RecentsImpl.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
// If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
dismissRecentsToFocusedTaskOrHome(false);
- } else if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
+ } else if (intent.getBooleanExtra(RecentsImpl.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
// Otherwise, dismiss Recents to Home
dismissRecentsToHome(true);
} else {
// Do nothing
}
- } else if (action.equals(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
+ } else if (action.equals(RecentsImpl.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// If we are toggling Recents, then first unfilter any filtered stacks first
dismissRecentsToFocusedTaskOrHome(true);
- } else if (action.equals(Recents.ACTION_START_ENTER_ANIMATION)) {
+ } else if (action.equals(RecentsImpl.ACTION_START_ENTER_ANIMATION)) {
// Trigger the enter animation
onEnterAnimationTriggered();
// Notify the fallback receiver that we have successfully got the broadcast
@@ -174,7 +176,7 @@
// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
// reconstructing the task stack
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- RecentsTaskLoadPlan plan = Recents.consumeInstanceLoadPlan();
+ RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
if (plan == null) {
plan = loader.createLoadPlan(this);
}
@@ -371,13 +373,15 @@
MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
- Recents.notifyVisibilityChanged(this, ssp, true);
+
+ // Notify that recents is now visible
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
// Register the broadcast receiver to handle messages from our service
IntentFilter filter = new IntentFilter();
- filter.addAction(Recents.ACTION_HIDE_RECENTS_ACTIVITY);
- filter.addAction(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY);
- filter.addAction(Recents.ACTION_START_ENTER_ANIMATION);
+ filter.addAction(RecentsImpl.ACTION_HIDE_RECENTS_ACTIVITY);
+ filter.addAction(RecentsImpl.ACTION_TOGGLE_RECENTS_ACTIVITY);
+ filter.addAction(RecentsImpl.ACTION_START_ENTER_ANIMATION);
registerReceiver(mServiceBroadcastReceiver, filter);
// Register any broadcast receivers for the task loader
@@ -415,7 +419,9 @@
MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
- Recents.notifyVisibilityChanged(this, ssp, false);
+
+ // Notify that recents is now hidden
+ EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
// Notify the views that we are no longer visible
mRecentsView.onRecentsHidden();
@@ -564,7 +570,7 @@
public void onScreenPinningRequest() {
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
- Recents.startScreenPinning(this, ssp);
+ EventBus.getDefault().send(new ScreenPinningRequestEvent(this, ssp));
MetricsLogger.count(this, "overview_screen_pinned", 1);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
new file mode 100644
index 0000000..2c76087
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ITaskStackListener;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.MutableBoolean;
+import android.view.LayoutInflater;
+import android.view.View;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.misc.Console;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskGrouping;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.TaskStackView;
+import com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
+import com.android.systemui.recents.views.TaskViewHeader;
+import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+import java.util.ArrayList;
+
+/**
+ * An implementation of the Recents component for the current user. For secondary users, this can
+ * be called remotely from the system user.
+ */
+public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
+ implements ActivityOptions.OnAnimationStartedListener {
+
+ private final static String TAG = "RecentsImpl";
+
+ final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
+ final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
+
+ final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
+ final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
+ final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
+
+ final static int sMinToggleDelay = 350;
+
+ public final static String RECENTS_PACKAGE = "com.android.systemui";
+ public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
+
+
+ /**
+ * An implementation of ITaskStackListener, that allows us to listen for changes to the system
+ * task stacks and update recents accordingly.
+ */
+ class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
+ Handler mHandler;
+
+ public TaskStackListenerImpl(Handler handler) {
+ mHandler = handler;
+ }
+
+ @Override
+ public void onTaskStackChanged() {
+ // Debounce any task stack changes
+ mHandler.removeCallbacks(this);
+ mHandler.post(this);
+ }
+
+ /** Preloads the next task */
+ public void run() {
+ // TODO: Temporarily skip this if multi stack is enabled
+ /*
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ SystemServicesProxy ssp = loader.getSystemServicesProxy();
+ ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
+
+ // Load the next task only if we aren't svelte
+ RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ loader.preloadTasks(plan, true);
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ // This callback is made when a new activity is launched and the old one is paused
+ // so ignore the current activity and try and preload the thumbnail for the
+ // previous one.
+ if (runningTaskInfo != null) {
+ launchOpts.runningTaskId = runningTaskInfo.id;
+ }
+ launchOpts.numVisibleTasks = 2;
+ launchOpts.numVisibleTaskThumbnails = 2;
+ launchOpts.onlyLoadForCache = true;
+ launchOpts.onlyLoadPausedActivities = true;
+ loader.loadTasks(mContext, plan, launchOpts);
+ }
+ */
+ }
+ }
+
+ static RecentsTaskLoadPlan sInstanceLoadPlan;
+
+ Context mContext;
+ SystemServicesProxy mSystemServicesProxy;
+ Handler mHandler;
+ TaskStackListenerImpl mTaskStackListener;
+ RecentsAppWidgetHost mAppWidgetHost;
+ boolean mBootCompleted;
+ boolean mStartAnimationTriggered;
+ boolean mCanReuseTaskStackViews = true;
+
+ // Task launching
+ RecentsConfiguration mConfig;
+ Rect mSearchBarBounds = new Rect();
+ Rect mTaskStackBounds = new Rect();
+ Rect mLastTaskViewBounds = new Rect();
+ TaskViewTransform mTmpTransform = new TaskViewTransform();
+ int mStatusBarHeight;
+ int mNavBarHeight;
+ int mNavBarWidth;
+ int mTaskBarHeight;
+
+ // Header (for transition)
+ TaskViewHeader mHeaderBar;
+ final Object mHeaderBarLock = new Object();
+ TaskStackView mDummyStackView;
+
+ // Variables to keep track of if we need to start recents after binding
+ boolean mTriggeredFromAltTab;
+ long mLastToggleTime;
+
+ Bitmap mThumbnailTransitionBitmapCache;
+ Task mThumbnailTransitionBitmapCacheKey;
+
+
+ public RecentsImpl(Context context) {
+ mContext = context;
+ mSystemServicesProxy = new SystemServicesProxy(mContext);
+ mHandler = new Handler();
+ mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
+ Resources res = mContext.getResources();
+ RecentsTaskLoader.initialize(mContext);
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+
+ // Register the task stack listener
+ mTaskStackListener = new TaskStackListenerImpl(mHandler);
+ mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+
+ // Initialize the static configuration resources
+ mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy);
+ mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
+ mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
+ mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
+ mDummyStackView = new TaskStackView(mContext, new TaskStack());
+ mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+ null, false);
+ reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
+
+ // When we start, preload the data associated with the previous recent tasks.
+ // We can use a new plan since the caches will be the same.
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ loader.preloadTasks(plan, true /* isTopTaskHome */);
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
+ launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
+ launchOpts.onlyLoadForCache = true;
+ loader.loadTasks(mContext, plan, launchOpts);
+ }
+
+ public void onBootCompleted() {
+ mBootCompleted = true;
+ reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
+ }
+
+ @Override
+ public void onConfigurationChanged() {
+ // Don't reuse task stack views if the configuration changes
+ mCanReuseTaskStackViews = false;
+ mConfig.updateOnConfigurationChange();
+ }
+
+ /**
+ * This is only called from the system user's Recents. Secondary users will instead proxy their
+ * visibility change events through to the system user via
+ * {@link Recents#onBusEvent(RecentsVisibilityChangedEvent)}.
+ */
+ public void onVisibilityChanged(Context context, boolean visible) {
+ SystemUIApplication app = (SystemUIApplication) context;
+ PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
+ if (statusBar != null) {
+ statusBar.updateRecentsVisibility(visible);
+ }
+ }
+
+ /**
+ * This is only called from the system user's Recents. Secondary users will instead proxy their
+ * visibility change events through to the system user via
+ * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}.
+ */
+ public void onStartScreenPinning(Context context) {
+ SystemUIApplication app = (SystemUIApplication) context;
+ PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
+ if (statusBar != null) {
+ statusBar.showScreenPinningRequest(false);
+ }
+ }
+
+ @Override
+ public void showRecents(boolean triggeredFromAltTab) {
+ mTriggeredFromAltTab = triggeredFromAltTab;
+
+ try {
+ // Check if the top task is in the home stack, and start the recents activity
+ ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+ MutableBoolean isTopTaskHome = new MutableBoolean(true);
+ if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
+ startRecentsActivity(topTask, isTopTaskHome.value);
+ }
+ } catch (ActivityNotFoundException e) {
+ Console.logRawError("Failed to launch RecentAppsIntent", e);
+ }
+ }
+
+ @Override
+ public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+ if (mBootCompleted) {
+ // Defer to the activity to handle hiding recents, if it handles it, then it must still
+ // be visible
+ Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY);
+ intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
+ intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
+ mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ }
+ }
+
+ @Override
+ public void toggleRecents() {
+ mTriggeredFromAltTab = false;
+
+ try {
+ // If the user has toggled it too quickly, then just eat up the event here (it's better
+ // than showing a janky screenshot).
+ // NOTE: Ideally, the screenshot mechanism would take the window transform into account
+ if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
+ return;
+ }
+
+ // If Recents is the front most activity, then we should just communicate with it
+ // directly to launch the first task or dismiss itself
+ ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+ MutableBoolean isTopTaskHome = new MutableBoolean(true);
+ if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
+ // Notify recents to toggle itself
+ Intent intent = createLocalBroadcastIntent(mContext, ACTION_TOGGLE_RECENTS_ACTIVITY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ mLastToggleTime = SystemClock.elapsedRealtime();
+ return;
+ } else {
+ // Otherwise, start the recents activity
+ startRecentsActivity(topTask, isTopTaskHome.value);
+ }
+ } catch (ActivityNotFoundException e) {
+ Console.logRawError("Failed to launch RecentAppsIntent", e);
+ }
+ }
+
+ @Override
+ public void preloadRecents() {
+ // Preload only the raw task list into a new load plan (which will be consumed by the
+ // RecentsActivity) only if there is a task to animate to.
+ ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+ MutableBoolean topTaskHome = new MutableBoolean(true);
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ sInstanceLoadPlan = loader.createLoadPlan(mContext);
+ if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
+ sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
+ loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
+ TaskStack stack = sInstanceLoadPlan.getTaskStack();
+ if (stack.getTaskCount() > 0) {
+ preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView);
+ }
+ }
+ }
+
+ @Override
+ public void cancelPreloadingRecents() {
+ // Do nothing
+ }
+
+ public void showRelativeAffiliatedTask(boolean showNextTask) {
+ // Return early if there is no focused stack
+ int focusedStackId = mSystemServicesProxy.getFocusedStack();
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ loader.preloadTasks(plan, true /* isTopTaskHome */);
+ TaskStack focusedStack = plan.getTaskStack();
+
+ // Return early if there are no tasks in the focused stack
+ if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
+
+ ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
+ // Return early if there is no running task (can't determine affiliated tasks in this case)
+ if (runningTask == null) return;
+ // Return early if the running task is in the home stack (optimization)
+ if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
+
+ // Find the task in the recents list
+ ArrayList<Task> tasks = focusedStack.getTasks();
+ Task toTask = null;
+ ActivityOptions launchOpts = null;
+ int taskCount = tasks.size();
+ int numAffiliatedTasks = 0;
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ if (task.key.id == runningTask.id) {
+ TaskGrouping group = task.group;
+ Task.TaskKey toTaskKey;
+ if (showNextTask) {
+ toTaskKey = group.getNextTaskInGroup(task);
+ launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_launch_next_affiliated_task_target,
+ R.anim.recents_launch_next_affiliated_task_source);
+ } else {
+ toTaskKey = group.getPrevTaskInGroup(task);
+ launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_launch_prev_affiliated_task_target,
+ R.anim.recents_launch_prev_affiliated_task_source);
+ }
+ if (toTaskKey != null) {
+ toTask = focusedStack.findTaskWithId(toTaskKey.id);
+ }
+ numAffiliatedTasks = group.getTaskCount();
+ break;
+ }
+ }
+
+ // Return early if there is no next task
+ if (toTask == null) {
+ if (numAffiliatedTasks > 1) {
+ if (showNextTask) {
+ mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
+ ActivityOptions.makeCustomInPlaceAnimation(mContext,
+ R.anim.recents_launch_next_affiliated_task_bounce));
+ } else {
+ mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
+ ActivityOptions.makeCustomInPlaceAnimation(mContext,
+ R.anim.recents_launch_prev_affiliated_task_bounce));
+ }
+ }
+ return;
+ }
+
+ // Keep track of actually launched affiliated tasks
+ MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
+
+ // Launch the task
+ if (toTask.isActive) {
+ // Bring an active task to the foreground
+ mSystemServicesProxy.moveTaskToFront(toTask.key.id, launchOpts);
+ } else {
+ mSystemServicesProxy.startActivityFromRecents(mContext, toTask.key.id,
+ toTask.activityLabel, launchOpts);
+ }
+ }
+
+ public void showNextAffiliatedTask() {
+ // Keep track of when the affiliated task is triggered
+ MetricsLogger.count(mContext, "overview_affiliated_task_next", 1);
+ showRelativeAffiliatedTask(true);
+ }
+
+ public void showPrevAffiliatedTask() {
+ // Keep track of when the affiliated task is triggered
+ MetricsLogger.count(mContext, "overview_affiliated_task_prev", 1);
+ showRelativeAffiliatedTask(false);
+ }
+
+ /**
+ * Returns the preloaded load plan and invalidates it.
+ */
+ public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
+ RecentsTaskLoadPlan plan = sInstanceLoadPlan;
+ sInstanceLoadPlan = null;
+ return plan;
+ }
+
+ /**
+ * Prepares the header bar layout for the next transition, if the task view bounds has changed
+ * since the last call, it will attempt to re-measure and layout the header bar to the new size.
+ *
+ * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
+ * is not already bound (can be expensive)
+ */
+ private void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
+ Rect windowRect = mSystemServicesProxy.getWindowRect();
+
+ // Update the configuration for the current state
+ mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
+
+ if (tryAndBindSearchWidget) {
+ // Try and pre-emptively bind the search widget on startup to ensure that we
+ // have the right thumbnail bounds to animate to.
+ // Note: We have to reload the widget id before we get the task stack bounds below
+ if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
+ mConfig.getSearchBarBounds(windowRect,
+ mStatusBarHeight, mSearchBarBounds);
+ }
+ }
+ Rect systemInsets = new Rect(0, mStatusBarHeight,
+ (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
+ (mConfig.hasTransposedNavBar ? 0 : mNavBarHeight));
+ mConfig.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+ mSearchBarBounds, mTaskStackBounds);
+
+ // Rebind the header bar and draw it for the transition
+ TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
+ Rect taskStackBounds = new Rect(mTaskStackBounds);
+ algo.setSystemInsets(systemInsets);
+ algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
+ Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
+ if (!taskViewBounds.equals(mLastTaskViewBounds)) {
+ mLastTaskViewBounds.set(taskViewBounds);
+
+ int taskViewWidth = taskViewBounds.width();
+ synchronized (mHeaderBarLock) {
+ mHeaderBar.measure(
+ View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
+ mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
+ }
+ }
+ }
+
+ /**
+ * Preloads the icon of a task.
+ */
+ private void preloadIcon(ActivityManager.RunningTaskInfo task) {
+
+ // Ensure that we load the running task's icon
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.runningTaskId = task.id;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoader.getInstance().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
+ }
+
+ /**
+ * Caches the header thumbnail used for a window animation asynchronously into
+ * {@link #mThumbnailTransitionBitmapCache}.
+ */
+ private void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
+ TaskStack stack, TaskStackView stackView) {
+ preloadIcon(topTask);
+
+ // Update the header bar if necessary
+ reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
+
+ // Update the destination rect
+ mDummyStackView.updateMinMaxScrollForStack(stack);
+ final Task toTask = new Task();
+ final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
+ topTask.id, toTask);
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ return drawThumbnailTransitionBitmap(toTask, toTransform);
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ mThumbnailTransitionBitmapCache = bitmap;
+ mThumbnailTransitionBitmapCacheKey = toTask;
+ }
+ }.execute();
+ }
+
+ /**
+ * Creates the activity options for a unknown state->recents transition.
+ */
+ private ActivityOptions getUnknownTransitionActivityOptions() {
+ mStartAnimationTriggered = false;
+ return ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_from_unknown_enter,
+ R.anim.recents_from_unknown_exit,
+ mHandler, this);
+ }
+
+ /**
+ * Creates the activity options for a home->recents transition.
+ */
+ private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
+ mStartAnimationTriggered = false;
+ if (fromSearchHome) {
+ return ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_from_search_launcher_enter,
+ R.anim.recents_from_search_launcher_exit,
+ mHandler, this);
+ }
+ return ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_from_launcher_enter,
+ R.anim.recents_from_launcher_exit,
+ mHandler, this);
+ }
+
+ /**
+ * Creates the activity options for an app->recents transition.
+ */
+ private ActivityOptions getThumbnailTransitionActivityOptions(
+ ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
+
+ // Update the destination rect
+ Task toTask = new Task();
+ TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
+ topTask.id, toTask);
+ Rect toTaskRect = toTransform.rect;
+ Bitmap thumbnail;
+ if (mThumbnailTransitionBitmapCacheKey != null
+ && mThumbnailTransitionBitmapCacheKey.key != null
+ && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
+ thumbnail = mThumbnailTransitionBitmapCache;
+ mThumbnailTransitionBitmapCacheKey = null;
+ mThumbnailTransitionBitmapCache = null;
+ } else {
+ preloadIcon(topTask);
+ thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
+ }
+ if (thumbnail != null) {
+ mStartAnimationTriggered = false;
+ return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+ thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
+ toTaskRect.height(), mHandler, this);
+ }
+
+ // If both the screenshot and thumbnail fails, then just fall back to the default transition
+ return getUnknownTransitionActivityOptions();
+ }
+
+ /**
+ * Returns the transition rect for the given task id.
+ */
+ private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
+ TaskStackView stackView, int runningTaskId, Task runningTaskOut) {
+ // Find the running task in the TaskStack
+ Task task = null;
+ ArrayList<Task> tasks = stack.getTasks();
+ if (runningTaskId != -1) {
+ // Otherwise, try and find the task with the
+ int taskCount = tasks.size();
+ for (int i = taskCount - 1; i >= 0; i--) {
+ Task t = tasks.get(i);
+ if (t.key.id == runningTaskId) {
+ task = t;
+ runningTaskOut.copyFrom(t);
+ break;
+ }
+ }
+ }
+ if (task == null) {
+ // If no task is specified or we can not find the task just use the front most one
+ task = tasks.get(tasks.size() - 1);
+ runningTaskOut.copyFrom(task);
+ }
+
+ // Get the transform for the running task
+ stackView.getScroller().setStackScrollToInitialState();
+ mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
+ stackView.getScroller().getStackScroll(), mTmpTransform, null);
+ return mTmpTransform;
+ }
+
+ /**
+ * Draws the header of a task used for the window animation into a bitmap.
+ */
+ private Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
+ if (toTransform != null && toTask.key != null) {
+ Bitmap thumbnail;
+ synchronized (mHeaderBarLock) {
+ int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
+ int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
+ Bitmap.Config.ARGB_8888);
+ if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
+ thumbnail.eraseColor(0xFFff0000);
+ } else {
+ Canvas c = new Canvas(thumbnail);
+ c.scale(toTransform.scale, toTransform.scale);
+ mHeaderBar.rebindToTask(toTask);
+ mHeaderBar.draw(c);
+ c.setBitmap(null);
+ }
+ }
+ return thumbnail.createAshmemBitmap();
+ }
+ return null;
+ }
+
+ /**
+ * Shows the recents activity
+ */
+ private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+ boolean isTopTaskHome) {
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+
+ // Update the header bar if necessary
+ reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
+
+ if (sInstanceLoadPlan == null) {
+ // Create a new load plan if onPreloadRecents() was never triggered
+ sInstanceLoadPlan = loader.createLoadPlan(mContext);
+ }
+
+ if (!sInstanceLoadPlan.hasTasks()) {
+ loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
+ }
+ TaskStack stack = sInstanceLoadPlan.getTaskStack();
+
+ // Prepare the dummy stack for the transition
+ mDummyStackView.updateMinMaxScrollForStack(stack);
+ TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
+ mDummyStackView.computeStackVisibilityReport();
+ boolean hasRecentTasks = stack.getTaskCount() > 0;
+ boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
+
+ if (useThumbnailTransition) {
+ // Try starting with a thumbnail transition
+ ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
+ mDummyStackView);
+ if (opts != null) {
+ startRecentsActivity(topTask, opts, false /* fromHome */,
+ false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
+ } else {
+ // Fall through below to the non-thumbnail transition
+ useThumbnailTransition = false;
+ }
+ }
+
+ if (!useThumbnailTransition) {
+ // If there is no thumbnail transition, but is launching from home into recents, then
+ // use a quick home transition and do the animation from home
+ if (hasRecentTasks) {
+ String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
+ String searchWidgetPackage =
+ Prefs.getString(mContext, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);
+
+ // Determine whether we are coming from a search owned home activity
+ boolean fromSearchHome = (homeActivityPackage != null) &&
+ homeActivityPackage.equals(searchWidgetPackage);
+ ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
+ startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+ false /* fromThumbnail */, stackVr);
+ } else {
+ // Otherwise we do the normal fade from an unknown source
+ ActivityOptions opts = getUnknownTransitionActivityOptions();
+ startRecentsActivity(topTask, opts, true /* fromHome */,
+ false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
+ }
+ }
+ mLastToggleTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Starts the recents activity.
+ */
+ private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+ ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
+ TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+ // Update the configuration based on the launch options
+ RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+ launchState.launchedFromHome = fromSearchHome || fromHome;
+ launchState.launchedFromSearchHome = fromSearchHome;
+ launchState.launchedFromAppWithThumbnail = fromThumbnail;
+ launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+ launchState.launchedWithAltTab = mTriggeredFromAltTab;
+ launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+ launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
+ launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+ launchState.launchedHasConfigurationChanged = false;
+
+ Intent intent = new Intent();
+ intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ if (opts != null) {
+ mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
+ } else {
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+ mCanReuseTaskStackViews = true;
+ }
+
+ /**
+ * Creates a new broadcast intent to send to the Recents activity.
+ * TODO: Use EventBus
+ */
+ private Intent createLocalBroadcastIntent(Context context, String action) {
+ Intent intent = new Intent(action);
+ intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
+ return intent;
+ }
+
+ /**** OnAnimationStartedListener Implementation ****/
+
+ @Override
+ public void onAnimationStarted() {
+ // Notify recents to start the enter animation
+ // TODO: Use EventBus
+ if (!mStartAnimationTriggered) {
+ // There can be a race condition between the start animation callback and
+ // the start of the new activity (where we register the receiver that listens
+ // to this broadcast, so we add our own receiver and if that gets called, then
+ // we know the activity has not yet started and we can retry sending the broadcast.
+ BroadcastReceiver fallbackReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getResultCode() == Activity.RESULT_OK) {
+ mStartAnimationTriggered = true;
+ return;
+ }
+
+ // Schedule for the broadcast to be sent again after some time
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ onAnimationStarted();
+ }
+ }, 25);
+ }
+ };
+
+ // Send the broadcast to notify Recents that the animation has started
+ Intent intent = createLocalBroadcastIntent(mContext, ACTION_START_ENTER_ANIMATION);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+ fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
new file mode 100644
index 0000000..fb21500
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+/**
+ * An implementation of the system user's Recents interface to be called remotely by secondary
+ * users.
+ */
+public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub {
+
+ private static final String TAG = "RecentsSystemUser";
+
+ private Context mContext;
+ private RecentsImpl mImpl;
+ private final SparseArray<IRecentsNonSystemUserCallbacks> mNonSystemUserRecents =
+ new SparseArray<>();
+
+ public RecentsSystemUser(Context context, RecentsImpl impl) {
+ mContext = context;
+ mImpl = impl;
+ }
+
+ @Override
+ public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks, int userId) {
+ try {
+ final IRecentsNonSystemUserCallbacks callback =
+ IRecentsNonSystemUserCallbacks.Stub.asInterface(nonSystemUserCallbacks);
+ nonSystemUserCallbacks.linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ mNonSystemUserRecents.removeAt(mNonSystemUserRecents.indexOfValue(callback));
+ }
+ }, 0);
+ mNonSystemUserRecents.put(userId, callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register NonSystemUserCallbacks", e);
+ }
+ }
+
+ public IRecentsNonSystemUserCallbacks getNonSystemUserRecentsForUser(int userId) {
+ return mNonSystemUserRecents.get(userId);
+ }
+
+ @Override
+ public void updateRecentsVisibility(boolean visible) {
+ mImpl.onVisibilityChanged(mContext, visible);
+ }
+
+ @Override
+ public void startScreenPinning() {
+ mImpl.onStartScreenPinning(mContext);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
new file mode 100644
index 0000000..39d0d59
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+import com.android.systemui.SystemUIApplication;
+
+/**
+ * A strictly system-user service that is started by the secondary user's Recents (with a limited
+ * lifespan), to get the interface that the secondary user's Recents can call through to the system
+ * user's Recents.
+ */
+public class RecentsSystemUserService extends Service {
+
+ private static final String TAG = "RecentsSystemUserService";
+ private static final boolean DEBUG = false;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ SystemUIApplication app = (SystemUIApplication) getApplication();
+ Recents recents = app.getComponent(Recents.class);
+ if (DEBUG) {
+ Log.d(TAG, "onBind: " + recents);
+ }
+ if (recents != null) {
+ return recents.getSystemUserCallbacks();
+ }
+ return null;
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java
deleted file mode 100644
index 5eefbc7..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * A proxy for Recents events which happens strictly for non-owner users.
- */
-public class RecentsUserEventProxyReceiver extends BroadcastReceiver {
- final public static String ACTION_PROXY_SHOW_RECENTS_TO_USER =
- "com.android.systemui.recents.action.SHOW_RECENTS_FOR_USER";
- final public static String ACTION_PROXY_HIDE_RECENTS_TO_USER =
- "com.android.systemui.recents.action.HIDE_RECENTS_FOR_USER";
- final public static String ACTION_PROXY_TOGGLE_RECENTS_TO_USER =
- "com.android.systemui.recents.action.TOGGLE_RECENTS_FOR_USER";
- final public static String ACTION_PROXY_PRELOAD_RECENTS_TO_USER =
- "com.android.systemui.recents.action.PRELOAD_RECENTS_FOR_USER";
- final public static String ACTION_PROXY_CONFIG_CHANGE_TO_USER =
- "com.android.systemui.recents.action.CONFIG_CHANGED_FOR_USER";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Recents recents = Recents.getInstanceAndStartIfNeeded(context);
- switch (intent.getAction()) {
- case ACTION_PROXY_SHOW_RECENTS_TO_USER: {
- boolean triggeredFromAltTab = intent.getBooleanExtra(
- Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
- recents.showRecentsInternal(triggeredFromAltTab);
- break;
- }
- case ACTION_PROXY_HIDE_RECENTS_TO_USER: {
- boolean triggeredFromAltTab = intent.getBooleanExtra(
- Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
- boolean triggeredFromHome = intent.getBooleanExtra(
- Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false);
- recents.hideRecentsInternal(triggeredFromAltTab, triggeredFromHome);
- break;
- }
- case ACTION_PROXY_TOGGLE_RECENTS_TO_USER:
- recents.toggleRecentsInternal();
- break;
- case ACTION_PROXY_PRELOAD_RECENTS_TO_USER:
- recents.preloadRecentsInternal();
- break;
- case ACTION_PROXY_CONFIG_CHANGE_TO_USER:
- recents.configurationChanged();
- break;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
new file mode 100644
index 0000000..898d1fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.component;
+
+import android.content.Context;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+
+/**
+ * This is sent when the visibility of the RecentsActivity for the current user changes.
+ */
+public class RecentsVisibilityChangedEvent extends EventBus.Event {
+
+ public final Context applicationContext;
+ public final SystemServicesProxy systemServicesProxy;
+ public final boolean visible;
+
+ public RecentsVisibilityChangedEvent(Context context, SystemServicesProxy systemServicesProxy,
+ boolean visible) {
+ this.applicationContext = context.getApplicationContext();
+ this.systemServicesProxy = systemServicesProxy;
+ this.visible = visible;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
new file mode 100644
index 0000000..5cb4ccf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.component;
+
+import android.content.Context;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+
+/**
+ * This is sent when we want to start screen pinning.
+ */
+public class ScreenPinningRequestEvent extends EventBus.Event {
+
+ public final Context applicationContext;
+ public final SystemServicesProxy systemServicesProxy;
+
+ public ScreenPinningRequestEvent(Context context, SystemServicesProxy systemServicesProxy) {
+ this.applicationContext = context.getApplicationContext();
+ this.systemServicesProxy = systemServicesProxy;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 568d2b1..dab2c65 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -16,9 +16,6 @@
package com.android.systemui.recents.misc;
-import static android.app.ActivityManager.DOCKED_STACK_ID;
-import static android.app.ActivityManager.INVALID_STACK_ID;
-
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
@@ -55,6 +52,7 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import android.util.MutableBoolean;
@@ -66,7 +64,7 @@
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsImpl;
import java.io.IOException;
import java.util.ArrayList;
@@ -74,6 +72,9 @@
import java.util.List;
import java.util.Random;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
+
/**
* Acts as a shim around the real system services that we need to access data from, and provides
* a point of injection when testing UI.
@@ -100,6 +101,7 @@
IPackageManager mIpm;
AssistUtils mAssistUtils;
WindowManager mWm;
+ UserManager mUm;
Display mDisplay;
String mRecentsPackage;
ComponentName mAssistComponent;
@@ -122,6 +124,7 @@
mIpm = AppGlobals.getPackageManager();
mAssistUtils = new AssistUtils(context);
mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ mUm = UserManager.get(context);
mDisplay = mWm.getDefaultDisplay();
mRecentsPackage = context.getPackageName();
mBgThreadHandler = new Handler(sBgThread.getLooper());
@@ -244,8 +247,8 @@
ComponentName topActivity = topTask.topActivity;
// Check if the front most activity is recents
- if (topActivity.getPackageName().equals(Recents.sRecentsPackage) &&
- topActivity.getClassName().equals(Recents.sRecentsActivity)) {
+ if (topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
+ topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)) {
if (isHomeTopMost != null) {
isHomeTopMost.value = false;
}
@@ -552,12 +555,27 @@
}
/**
- * Returns whether the foreground user is the owner.
+ * Returns whether the provided {@param userId} represents the system user.
*/
- public boolean isForegroundUserSystem() {
- if (mAm == null) return false;
+ public boolean isSystemUser(int userId) {
+ return userId == UserHandle.USER_SYSTEM;
+ }
- return mAm.getCurrentUser() == UserHandle.USER_SYSTEM;
+ /**
+ * Returns the current user id.
+ */
+ public int getCurrentUser() {
+ if (mAm == null) return 0;
+
+ return mAm.getCurrentUser();
+ }
+
+ /**
+ * Returns the processes user id.
+ */
+ public int getProcessUser() {
+ if (mUm == null) return 0;
+ return mUm.getUserHandle();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 4322f1a..3673131 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -395,8 +395,10 @@
// The user intentionally tapped on the background, which is like a tap on the "desktop".
// Hide recents and transition to the launcher.
+ /* TODO: Use EventBus for this later
Recents recents = Recents.getInstanceAndStartIfNeeded(mSv.getContext());
- recents.hideRecents(false /* altTab */, true /* homeKey */);
+ recents.hideRecents(false, true);
+ */
}
/** Handles generic motion events */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 540b9d0..fa9c4bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -109,6 +109,14 @@
}
};
+ private Runnable mRemoveCastIconRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "updateCast: hiding icon NOW");
+ mService.setIconVisibility(SLOT_CAST, false);
+ }
+ };
+
public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot,
UserInfoController userInfoController, BluetoothController bluetooth) {
mContext = context;
@@ -328,11 +336,17 @@
}
}
if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting);
+ mHandler.removeCallbacks(mRemoveCastIconRunnable);
if (isCasting) {
mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0,
mContext.getString(R.string.accessibility_casting));
+ mService.setIconVisibility(SLOT_CAST, true);
+ } else {
+ // don't turn off the screen-record icon for a few seconds, just to make sure the user
+ // has seen it
+ if (DEBUG) Log.v(TAG, "updateCast: hiding icon in 3 sec...");
+ mHandler.postDelayed(mRemoveCastIconRunnable, 3000);
}
- mService.setIconVisibility(SLOT_CAST, isCasting);
}
private void profileChanged(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 01f0667..662dbd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -20,7 +20,9 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Rect;
import android.graphics.drawable.Animatable;
+import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -28,6 +30,7 @@
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
@@ -86,6 +89,20 @@
mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
+
+ // RenderThread is doing more harm than good when touching the header (to expand quick
+ // settings), so disable it for this view
+ ((RippleDrawable) getBackground()).setForceSoftware(true);
+ ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
+
+ addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right,
+ int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ setClipBounds(new Rect(getPaddingLeft(), 0, getWidth() - getPaddingRight(),
+ getHeight()));
+ }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 56f6036..a515f23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -602,6 +602,13 @@
@Override
public int compareTo(HeadsUpEntry o) {
+ boolean selfFullscreen = hasFullScreenIntent(entry);
+ boolean otherFullscreen = hasFullScreenIntent(o.entry);
+ if (selfFullscreen && !otherFullscreen) {
+ return -1;
+ } else if (!selfFullscreen && otherFullscreen) {
+ return 1;
+ }
return postTime < o.postTime ? 1
: postTime == o.postTime ? entry.key.compareTo(o.entry.key)
: -1;
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index d6d17cb..fdc2543 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -22,7 +22,9 @@
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.systemui:com.android.keyguard
+
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-Iaidl-files-under, src) \
$(call all-java-files-under, ../src) \
$(call all-proto-files-under, ../src) \
src/com/android/systemui/EventLogTags.logtags
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
new file mode 120000
index 0000000..0ea3e91
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -0,0 +1 @@
+../../../../../../src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
new file mode 120000
index 0000000..b1a0963
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -0,0 +1 @@
+../../../../../../src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index 7dff1a8..28121b4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -17,53 +17,146 @@
package com.android.server.accessibility;
import android.content.Context;
+import android.gesture.Gesture;
+import android.gesture.GestureLibraries;
+import android.gesture.GestureLibrary;
+import android.gesture.GesturePoint;
+import android.gesture.GestureStore;
+import android.gesture.GestureStroke;
+import android.gesture.Prediction;
+import android.util.Slog;
import android.view.GestureDetector;
import android.view.MotionEvent;
+import com.android.internal.R;
+
+import java.util.ArrayList;
+
/**
* This class handles gesture detection for the Touch Explorer. It collects
* touch events, and sends events to mListener as gestures are recognized.
*/
class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListener {
- private final GestureDetector mGestureDetector;
+
+ private static final boolean DEBUG = false;
+
+ // Tag for logging received events.
+ private static final String LOG_TAG = "AccessibilityGestureDetector";
+
+ public interface Listener {
+ public void onDoubleTapAndHold(MotionEvent event, int policyFlags);
+ public boolean onDoubleTap(MotionEvent event, int policyFlags);
+ public boolean onGesture(int gestureId);
+ }
+
private final Listener mListener;
+ private final GestureDetector mGestureDetector;
+
+ // The library for gesture detection.
+ private final GestureLibrary mGestureLibrary;
+
+ // Indicates that a single tap has occurred.
private boolean mFirstTapDetected;
+
+ // Indicates that the down event of a double tap has occured.
private boolean mDoubleTapDetected;
+
+ // Indicates that motion events are being collected to match a gesture.
+ private boolean mRecognizingGesture;
+
+ // Policy flags of the previous event.
private int mPolicyFlags;
+ // The X of the previous event.
+ private float mPreviousX;
+
+ // The Y of the previous event.
+ private float mPreviousY;
+
+ // Buffer for storing points for gesture detection.
+ private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
+
+ // The minimal delta between moves to add a gesture point.
+ private static final int TOUCH_TOLERANCE = 3;
+
+ // The minimal score for accepting a predicted gesture.
+ private static final float MIN_PREDICTION_SCORE = 2.0f;
+
AccessibilityGestureDetector(Context context, Listener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, this);
mGestureDetector.setOnDoubleTapListener(this);
+
+ mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
+ mGestureLibrary.setOrientationStyle(8 /* GestureStore.ORIENTATION_SENSITIVE_8 */);
+ mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE);
+ mGestureLibrary.load();
}
- public void onMotionEvent(MotionEvent event, int policyFlags) {
+ public boolean onMotionEvent(MotionEvent event, int policyFlags) {
+ final float x = event.getX();
+ final float y = event.getY();
+
mPolicyFlags = policyFlags;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mDoubleTapDetected = false;
+ mRecognizingGesture = true;
+ mPreviousX = x;
+ mPreviousY = y;
+ mStrokeBuffer.clear();
+ mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mRecognizingGesture) {
+ final float dX = Math.abs(x - mPreviousX);
+ final float dY = Math.abs(y - mPreviousY);
+ if (dX >= TOUCH_TOLERANCE || dY >= TOUCH_TOLERANCE) {
+ mPreviousX = x;
+ mPreviousY = y;
+ mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+ }
+ }
break;
case MotionEvent.ACTION_UP:
- maybeFinishDoubleTap(event, policyFlags);
+ if (maybeFinishDoubleTap(event, policyFlags)) {
+ return true;
+ }
+ if (mRecognizingGesture) {
+ mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
+
+ if (recognizeGesture()) {
+ return true;
+ }
+ }
break;
}
- mGestureDetector.onTouchEvent(event);
+
+ if (!mRecognizingGesture) {
+ return false;
+ }
+
+ // Pass the event on to the standard gesture detector.
+ return mGestureDetector.onTouchEvent(event);
}
public void clear() {
mFirstTapDetected = false;
mDoubleTapDetected = false;
+ cancelGesture();
+ mStrokeBuffer.clear();
}
public boolean firstTapDetected() {
return mFirstTapDetected;
}
- @Override
- public boolean onDown(MotionEvent event) {
- return true;
+ public void cancelGesture() {
+ mRecognizingGesture = false;
+ mStrokeBuffer.clear();
}
@Override
@@ -101,18 +194,39 @@
mListener.onDoubleTapAndHold(event, policyFlags);
}
- private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
+ private boolean maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
if (!mDoubleTapDetected) {
- return;
+ return false;
}
clear();
- mListener.onDoubleTap(event, policyFlags);
+ return mListener.onDoubleTap(event, policyFlags);
}
- public interface Listener {
- public void onDoubleTapAndHold(MotionEvent event, int policyFlags);
- public void onDoubleTap(MotionEvent event, int policyFlags);
+ private boolean recognizeGesture() {
+ Gesture gesture = new Gesture();
+ gesture.addStroke(new GestureStroke(mStrokeBuffer));
+
+ ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture);
+ if (!predictions.isEmpty()) {
+ Prediction bestPrediction = predictions.get(0);
+ if (bestPrediction.score >= MIN_PREDICTION_SCORE) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "gesture: " + bestPrediction.name + " score: "
+ + bestPrediction.score);
+ }
+ try {
+ final int gestureId = Integer.parseInt(bestPrediction.name);
+ if (mListener.onGesture(gestureId)) {
+ return true;
+ }
+ } catch (NumberFormatException nfe) {
+ Slog.w(LOG_TAG, "Non numeric gesture id:" + bestPrediction.name);
+ }
+ }
+ }
+
+ return false;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 954536f..ca30349 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -17,13 +17,6 @@
package com.android.server.accessibility;
import android.content.Context;
-import android.gesture.Gesture;
-import android.gesture.GestureLibraries;
-import android.gesture.GestureLibrary;
-import android.gesture.GesturePoint;
-import android.gesture.GestureStore;
-import android.gesture.GestureStroke;
-import android.gesture.Prediction;
import android.graphics.Point;
import android.os.Handler;
import android.util.Slog;
@@ -38,8 +31,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
-import com.android.internal.R;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -167,24 +158,6 @@
// Context in which this explorer operates.
private final Context mContext;
- // The X of the previous event.
- private float mPreviousX;
-
- // The Y of the previous event.
- private float mPreviousY;
-
- // Buffer for storing points for gesture detection.
- private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
-
- // The minimal delta between moves to add a gesture point.
- private static final int TOUCH_TOLERANCE = 3;
-
- // The minimal score for accepting a predicted gesture.
- private static final float MIN_PREDICTION_SCORE = 2.0f;
-
- // The library for gesture detection.
- private GestureLibrary mGestureLibrary;
-
// The long pressing pointer id if coordinate remapping is needed.
private int mLongPressingPointerId = -1;
@@ -215,10 +188,6 @@
mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
mHandler = new Handler(context.getMainLooper());
mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed();
- mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
- mGestureLibrary.setOrientationStyle(8);
- mGestureLibrary.setSequenceType(GestureStore.SEQUENCE_SENSITIVE);
- mGestureLibrary.load();
mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed();
mSendHoverExitDelayed = new SendHoverExitDelayed();
mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
@@ -274,8 +243,7 @@
sendUpForInjectedDownPointers(event, policyFlags);
} break;
case STATE_GESTURE_DETECTING: {
- // Clear the current stroke.
- mStrokeBuffer.clear();
+ // No state specific cleanup required.
} break;
}
// Remove all pending callbacks.
@@ -321,6 +289,11 @@
mReceivedPointerTracker.onMotionEvent(rawEvent);
+ if (mGestureDetector.onMotionEvent(event, policyFlags)) {
+ // Event was handled by the gesture detector.
+ return;
+ }
+
switch(mCurrentState) {
case STATE_TOUCH_EXPLORING: {
handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
@@ -389,6 +362,11 @@
@Override
public void onDoubleTapAndHold(MotionEvent event, int policyFlags) {
+ // Ignore the event if we aren't touch exploring.
+ if (mCurrentState != STATE_TOUCH_EXPLORING) {
+ return;
+ }
+
// Pointers should not be zero when running this command.
if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
return;
@@ -415,10 +393,10 @@
}
@Override
- public void onDoubleTap(MotionEvent event, int policyFlags) {
- // This should never be called when more than two pointers are down.
- if (event.getPointerCount() > 2) {
- return;
+ public boolean onDoubleTap(MotionEvent event, int policyFlags) {
+ // Ignore the event if we aren't touch exploring.
+ if (mCurrentState != STATE_TOUCH_EXPLORING) {
+ return false;
}
// Remove pending event deliveries.
@@ -438,7 +416,9 @@
Point clickLocation = mTempPoint;
final int result = computeClickLocation(clickLocation);
if (result == CLICK_LOCATION_NONE) {
- return;
+ // We can't send a click to no location, but the gesture was still
+ // consumed.
+ return true;
}
// Do the click.
@@ -456,6 +436,28 @@
final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
click_event.recycle();
+ return true;
+ }
+
+ @Override
+ public boolean onGesture(int gestureId) {
+ if (mCurrentState != STATE_GESTURE_DETECTING) {
+ return false;
+ }
+
+ mAms.onTouchInteractionEnd();
+
+ // Announce the end of the gesture recognition.
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+ // Announce the end of a the touch interaction.
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+
+ mAms.onGesture(gestureId);
+
+ mExitGestureDetectionModeDelayed.cancel();
+ mCurrentState = STATE_TOUCH_EXPLORING;
+
+ return true;
}
/**
@@ -471,17 +473,10 @@
mVelocityTracker.addMovement(rawEvent);
- mGestureDetector.onMotionEvent(event, policyFlags);
-
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mAms.onTouchInteractionStart();
- // Pre-feed the motion events to the gesture detector since we
- // have a distance slop before getting into gesture detection
- // mode and not using the points within this slop significantly
- // decreases the quality of gesture recognition.
- handleMotionEventGestureDetecting(rawEvent, policyFlags);
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
// If we still have not notified the user for the last
@@ -528,12 +523,6 @@
// We have not started sending events since we try to
// figure out what the user is doing.
if (mSendHoverEnterAndMoveDelayed.isPending()) {
- // Pre-feed the motion events to the gesture detector since we
- // have a distance slop before getting into gesture detection
- // mode and not using the points within this slop significantly
- // decreases the quality of gesture recognition.
- handleMotionEventGestureDetecting(rawEvent, policyFlags);
-
// Cache the event until we discern exploration from gesturing.
mSendHoverEnterAndMoveDelayed.addEvent(event);
@@ -568,6 +557,7 @@
} else {
// We have just decided that the user is touch,
// exploring so start sending events.
+ mGestureDetector.cancelGesture();
mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
mSendHoverExitDelayed.cancel();
sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
@@ -613,9 +603,9 @@
}
// We know that a new state transition is to happen and the
- // new state will not be gesture recognition, so clear the
- // stashed gesture strokes.
- mStrokeBuffer.clear();
+ // new state will not be gesture recognition, so cancel
+ // the gesture.
+ mGestureDetector.cancelGesture();
if (isDraggingGesture(event)) {
// Two pointers moving in the same direction within
@@ -655,9 +645,6 @@
} break;
case MotionEvent.ACTION_UP: {
mAms.onTouchInteractionEnd();
- // We know that we do not need the pre-fed gesture points are not
- // needed anymore since the last pointer just went up.
- mStrokeBuffer.clear();
final int pointerId = event.getPointerId(event.getActionIndex());
final int pointerIdBits = (1 << pointerId);
@@ -820,24 +807,6 @@
private void handleMotionEventGestureDetecting(MotionEvent event, int policyFlags) {
switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- final float x = event.getX();
- final float y = event.getY();
- mPreviousX = x;
- mPreviousY = y;
- mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
- } break;
- case MotionEvent.ACTION_MOVE: {
- final float x = event.getX();
- final float y = event.getY();
- final float dX = Math.abs(x - mPreviousX);
- final float dY = Math.abs(y - mPreviousY);
- if (dX >= TOUCH_TOLERANCE || dY >= TOUCH_TOLERANCE) {
- mPreviousX = x;
- mPreviousY = y;
- mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
- }
- } break;
case MotionEvent.ACTION_UP: {
mAms.onTouchInteractionEnd();
// Announce the end of the gesture recognition.
@@ -845,31 +814,6 @@
// Announce the end of a the touch interaction.
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- float x = event.getX();
- float y = event.getY();
- mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
-
- Gesture gesture = new Gesture();
- gesture.addStroke(new GestureStroke(mStrokeBuffer));
-
- ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture);
- if (!predictions.isEmpty()) {
- Prediction bestPrediction = predictions.get(0);
- if (bestPrediction.score >= MIN_PREDICTION_SCORE) {
- if (DEBUG) {
- Slog.i(LOG_TAG, "gesture: " + bestPrediction.name + " score: "
- + bestPrediction.score);
- }
- try {
- final int gestureId = Integer.parseInt(bestPrediction.name);
- mAms.onGesture(gestureId);
- } catch (NumberFormatException nfe) {
- Slog.w(LOG_TAG, "Non numeric gesture id:" + bestPrediction.name);
- }
- }
- }
-
- mStrokeBuffer.clear();
mExitGestureDetectionModeDelayed.cancel();
mCurrentState = STATE_TOUCH_EXPLORING;
} break;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d031165..c712a56 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1450,10 +1450,7 @@
}
private void enforceChangePermission() {
- int uid = Binder.getCallingUid();
- Settings.checkAndNoteChangeNetworkStateOperation(mContext, uid, Settings
- .getPackageNameForUid(mContext, uid), true);
-
+ ConnectivityManager.enforceChangePermission(mContext);
}
private void enforceTetherAccessPermission() {
@@ -3366,7 +3363,7 @@
.setPriority(highPriority ?
Notification.PRIORITY_HIGH :
Notification.PRIORITY_DEFAULT)
- .setDefaults(Notification.DEFAULT_ALL)
+ .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
.setOnlyAlertOnce(true)
.build();
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 4d32599..85187c7 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2442,8 +2442,13 @@
}
try {
- mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type],
- new SensitiveArg(password));
+ if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
+ mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
+ CRYPTO_TYPES[type]);
+ } else {
+ mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
+ CRYPTO_TYPES[type], new SensitiveArg(password));
+ }
} catch (NativeDaemonConnectorException e) {
// Encryption failed
return e.getCode();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4949138..465118c2 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1314,6 +1314,15 @@
if (!mRestartingServices.contains(r)) {
return;
}
+ if (!isServiceNeeded(r, false, false)) {
+ // Paranoia: is this service actually needed? In theory a service that is not
+ // needed should never remain on the restart list. In practice... well, there
+ // have been bugs where this happens, and bad things happen because the process
+ // ends up just being cached, so quickly killed, then restarted again and again.
+ // Let's not let that happen.
+ Slog.wtf(TAG, "Restarting service that is not needed: " + r);
+ return;
+ }
try {
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
} catch (TransactionTooLargeException e) {
@@ -2043,6 +2052,13 @@
mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
+ if (!isServiceNeeded(sr, false, false)) {
+ // We were waiting for this service to start, but it is actually no
+ // longer needed. This could happen because bringDownServiceIfNeeded
+ // won't bring down a service that is pending... so now the pending
+ // is done, so let's drop it.
+ bringDownServiceLocked(sr);
+ }
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
@@ -2055,7 +2071,7 @@
// be weird to bring up the process but arbitrarily not let the services
// run at this point just because their restart time hasn't come up.
if (mRestartingServices.size() > 0) {
- ServiceRecord sr = null;
+ ServiceRecord sr;
for (int i=0; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7df50d5..bb1b6b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5794,7 +5794,7 @@
}
boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
- -100, callerWillRestart, true, doit, evenPersistent,
+ ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
@@ -6110,7 +6110,7 @@
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.makeActive(thread, mProcessStats);
- app.curAdj = app.setAdj = -100;
+ app.curAdj = app.setAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
updateProcessForegroundLocked(app, false, false);
@@ -18057,6 +18057,7 @@
// Examine all activities if not already foreground.
if (!foregroundActivities && activitiesSize > 0) {
+ int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX;
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
if (r.app != app) {
@@ -18077,6 +18078,12 @@
app.cached = false;
app.empty = false;
foregroundActivities = true;
+ if (r.task != null && minLayer > 0) {
+ final int layer = r.task.mLayerRank;
+ if (layer >= 0 && minLayer > layer) {
+ minLayer = layer;
+ }
+ }
break;
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -18117,6 +18124,9 @@
}
}
}
+ if (adj == ProcessList.VISIBLE_APP_ADJ) {
+ adj += minLayer;
+ }
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -18326,11 +18336,11 @@
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
+ } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = clientAdj;
} else {
if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
+ adj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
}
}
if (!client.cached) {
@@ -19368,6 +19378,8 @@
uidRec.reset();
}
+ mStackSupervisor.rankTaskLayersIfNeeded();
+
mAdjSeq++;
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a59f7ef..1721470 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -993,10 +993,13 @@
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
- if (r.finishing && r.state == ActivityState.PAUSING) {
- if (DEBUG_PAUSE) Slog.v(TAG,
- "Executing finish of failed to pause activity: " + r);
- finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ if (r.state == ActivityState.PAUSING) {
+ r.state = ActivityState.PAUSED;
+ if (r.finishing) {
+ if (DEBUG_PAUSE) Slog.v(TAG,
+ "Executing finish of failed to pause activity: " + r);
+ finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ }
}
}
}
@@ -1375,6 +1378,20 @@
return true;
}
+ final int rankTaskLayers(int baseLayer) {
+ int layer = 0;
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ ActivityRecord r = task.topRunningActivityLocked();
+ if (r == null || r.finishing || !r.visible) {
+ task.mLayerRank = -1;
+ } else {
+ task.mLayerRank = baseLayer + layer++;
+ }
+ }
+ return layer;
+ }
+
/**
* Make sure that all activities that need to be visible (that is, they
* currently can be seen by the user) actually are.
@@ -3781,6 +3798,7 @@
task.mLastTimeMoved *= -1;
}
}
+ mStackSupervisor.invalidateTaskLayers();
}
void moveHomeStackTaskToTop(int homeStackTaskType) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d6ad547..54ac58a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -357,6 +357,9 @@
// It will be calculated when the default display gets added.
private int mDefaultMinimalSizeOfResizeableTask = -1;
+ // Whether tasks have moved and we need to rank the tasks before next OOM scoring
+ private boolean mTaskLayersChanged = true;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -2539,8 +2542,13 @@
final void doPendingActivityLaunchesLocked(boolean doResume) {
while (!mPendingActivityLaunches.isEmpty()) {
PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
- startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
- doResume && mPendingActivityLaunches.isEmpty(), null, null);
+
+ try {
+ startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+ doResume && mPendingActivityLaunches.isEmpty(), null, null);
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception during pending activity launch pal=" + pal, e);
+ }
}
}
@@ -3608,6 +3616,24 @@
}
}
+ void invalidateTaskLayers() {
+ mTaskLayersChanged = true;
+ }
+
+ void rankTaskLayersIfNeeded() {
+ if (!mTaskLayersChanged) {
+ return;
+ }
+ mTaskLayersChanged = false;
+ for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) {
+ final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ int baseLayer = 0;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ baseLayer += stacks.get(stackNdx).rankTaskLayers(baseLayer);
+ }
+ }
+ }
+
void clearOtherAppTimeTrackers(AppTimeTracker except) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 960cbf1..6de8579 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -44,6 +44,7 @@
import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
+import android.util.TimeUtils;
import com.android.server.DeviceIdleController;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -1284,6 +1285,7 @@
final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
|| mPendingBroadcast != null) {
boolean printed = false;
@@ -1301,7 +1303,7 @@
pw.println(" Active broadcasts [" + mQueueName + "]:");
}
pw.println(" Active Broadcast " + mQueueName + " #" + i + ":");
- br.dump(pw, " ");
+ br.dump(pw, " ", sdf);
}
printed = false;
needSep = true;
@@ -1319,7 +1321,7 @@
pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
}
pw.println(" Active Ordered Broadcast " + mQueueName + " #" + i + ":");
- mOrderedBroadcasts.get(i).dump(pw, " ");
+ mOrderedBroadcasts.get(i).dump(pw, " ", sdf);
}
if (dumpPackage == null || (mPendingBroadcast != null
&& dumpPackage.equals(mPendingBroadcast.callerPackage))) {
@@ -1328,7 +1330,7 @@
}
pw.println(" Pending broadcast [" + mQueueName + "]:");
if (mPendingBroadcast != null) {
- mPendingBroadcast.dump(pw, " ");
+ mPendingBroadcast.dump(pw, " ", sdf);
} else {
pw.println(" (null)");
}
@@ -1366,7 +1368,7 @@
if (dumpAll) {
pw.print(" Historical Broadcast " + mQueueName + " #");
pw.print(i); pw.println(":");
- r.dump(pw, " ");
+ r.dump(pw, " ", sdf);
} else {
pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
pw.print(" ");
@@ -1400,7 +1402,6 @@
}
// done skipping; dump the remainder of the ring. 'i' is still the ordinal within
// the overall broadcast history.
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
do {
ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
Intent intent = mBroadcastSummaryHistory[ringIndex];
@@ -1422,9 +1423,19 @@
i++;
pw.print(" #"); pw.print(i); pw.print(": ");
pw.println(intent.toShortString(false, true, true, false));
- pw.print(" enq="); pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
- pw.print(" disp="); pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
- pw.print(" fin="); pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
+ pw.print(" ");
+ TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
+ - mSummaryHistoryEnqueueTime[ringIndex], pw);
+ pw.print(" dispatch ");
+ TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
+ - mSummaryHistoryDispatchTime[ringIndex], pw);
+ pw.println(" finish");
+ pw.print(" enq=");
+ pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
+ pw.print(" disp=");
+ pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
+ pw.print(" fin=");
+ pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
Bundle bundle = intent.getExtras();
if (bundle != null) {
pw.print(" extras: "); pw.println(bundle.toString());
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 1fbfd9f..b42bcff 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -32,6 +32,7 @@
import android.util.TimeUtils;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -88,7 +89,7 @@
ComponentName curComponent; // the receiver class that is currently running.
ActivityInfo curReceiver; // info about the receiver that is currently running.
- void dump(PrintWriter pw, String prefix) {
+ void dump(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
@@ -114,13 +115,19 @@
pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
}
pw.print(prefix); pw.print("enqueueClockTime=");
- pw.print(new Date(enqueueClockTime));
+ pw.print(sdf.format(new Date(enqueueClockTime)));
pw.print(" dispatchClockTime=");
- pw.println(new Date(dispatchClockTime));
+ pw.println(sdf.format(new Date(dispatchClockTime)));
pw.print(prefix); pw.print("dispatchTime=");
TimeUtils.formatDuration(dispatchTime, now, pw);
+ pw.print(" (");
+ TimeUtils.formatDuration(dispatchClockTime-enqueueClockTime, pw);
+ pw.print(" since enq)");
if (finishTime != 0) {
pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
+ pw.print(" (");
+ TimeUtils.formatDuration(finishTime-dispatchTime, pw);
+ pw.print(" since disp)");
} else {
pw.print(" receiverTime="); TimeUtils.formatDuration(receiverTime, now, pw);
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0e24952..b49370b 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -49,19 +49,22 @@
// OOM adjustments for processes in various states:
+ // Uninitialized value for any major or minor adj fields
+ static final int INVALID_ADJ = -10000;
+
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
- static final int UNKNOWN_ADJ = 16;
+ static final int UNKNOWN_ADJ = 1001;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
- static final int CACHED_APP_MAX_ADJ = 15;
- static final int CACHED_APP_MIN_ADJ = 9;
+ static final int CACHED_APP_MAX_ADJ = 906;
+ static final int CACHED_APP_MIN_ADJ = 900;
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
- static final int SERVICE_B_ADJ = 8;
+ static final int SERVICE_B_ADJ = 800;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
@@ -69,34 +72,35 @@
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
- static final int PREVIOUS_APP_ADJ = 7;
+ static final int PREVIOUS_APP_ADJ = 700;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
- static final int HOME_APP_ADJ = 6;
+ static final int HOME_APP_ADJ = 600;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
- static final int SERVICE_ADJ = 5;
+ static final int SERVICE_ADJ = 500;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 4;
+ static final int HEAVY_WEIGHT_APP_ADJ = 400;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 3;
+ static final int BACKUP_APP_ADJ = 300;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
- static final int PERCEPTIBLE_APP_ADJ = 2;
+ static final int PERCEPTIBLE_APP_ADJ = 200;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
- static final int VISIBLE_APP_ADJ = 1;
+ static final int VISIBLE_APP_ADJ = 100;
+ static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
// This is the process running the current foreground app. We'd really
// rather not kill it!
@@ -104,18 +108,18 @@
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
- static final int PERSISTENT_SERVICE_ADJ = -11;
+ static final int PERSISTENT_SERVICE_ADJ = -700;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
- static final int PERSISTENT_PROC_ADJ = -12;
+ static final int PERSISTENT_PROC_ADJ = -800;
// The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -16;
+ static final int SYSTEM_ADJ = -900;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
- static final int NATIVE_ADJ = -17;
+ static final int NATIVE_ADJ = -1000;
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
@@ -159,7 +163,7 @@
// These must be kept in sync with the definitions in lmkd.c
//
// LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
- // LMK_PROCPRIO <pid> <prio>
+ // LMK_PROCPRIO <pid> <uid> <prio>
// LMK_PROCREMOVE <pid>
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index bd31a21..08203c55b 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -171,10 +171,10 @@
boolean debugging; // was app launched for debugging?
boolean waitedForDebugger; // has process show wait for debugger dialog?
Dialog waitDialog; // current wait for debugger dialog
-
+
String shortStringName; // caching of toShortString() result.
String stringName; // caching of toString() result.
-
+
// These reports are generated & stored when an app gets into an error condition.
// They will be "null" when all is OK.
ActivityManager.ProcessErrorStateInfo crashingReport;
@@ -402,7 +402,7 @@
}
}
}
-
+
ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,
String _processName, int _uid) {
mBatteryStats = _batteryStats;
@@ -413,8 +413,8 @@
processName = _processName;
pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.versionCode));
maxAdj = ProcessList.UNKNOWN_ADJ;
- curRawAdj = setRawAdj = -100;
- curAdj = setAdj = -100;
+ curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
+ curAdj = setAdj = ProcessList.INVALID_ADJ;
persistent = false;
removed = false;
lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
@@ -560,7 +560,7 @@
toShortString(sb);
return shortStringName = sb.toString();
}
-
+
void toShortString(StringBuilder sb) {
sb.append(pid);
sb.append(':');
@@ -585,7 +585,7 @@
}
}
}
-
+
public String toString() {
if (stringName != null) {
return stringName;
@@ -695,7 +695,7 @@
pkgList.put(info.packageName, new ProcessStats.ProcessStateHolder(info.versionCode));
}
}
-
+
public String[] getPackageList() {
int size = pkgList.size();
if (size == 0) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 1999f49..fe87a93 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -221,6 +221,10 @@
// default minimal size.
final int mMinimalSize;
+ // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
+ // This number will be assigned when we evaluate OOM scores for all visible tasks.
+ int mLayerRank = -1;
+
Configuration mOverrideConfig = Configuration.EMPTY;
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5b40375..81ae8ac 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -793,8 +793,17 @@
}
@Override // Binder call
+ public int isInTabletMode() {
+ if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
+ "isInTabletMode()")) {
+ throw new SecurityException("Requires TABLET_MODE permission");
+ }
+ return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_TABLET_MODE);
+ }
+
+ @Override // Binder call
public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
- if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE_LISTENER,
+ if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
"registerTabletModeChangedListener()")) {
throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
}
@@ -1495,7 +1504,7 @@
switchMask);
}
- if ((switchMask & SW_TABLET_MODE) != 0) {
+ if ((switchMask & SW_TABLET_MODE_BIT) != 0) {
SomeArgs args = SomeArgs.obtain();
args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
args.argi2 = (int) (whenNanos >> 32);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index ccd2b6e..5376043 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -109,7 +109,13 @@
int mVerb;
private AtomicBoolean mCancelled = new AtomicBoolean();
- /** All the information maintained about the job currently being executed. */
+ /**
+ * All the information maintained about the job currently being executed.
+ *
+ * Any reads (dereferences) not done from the handler thread must be synchronized on
+ * {@link #mLock}.
+ * Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
+ */
private JobStatus mRunningJob;
/** Binder to the client service. */
IJobService service;
@@ -194,7 +200,8 @@
*/
JobStatus getRunningJob() {
synchronized (mLock) {
- return mRunningJob;
+ return mRunningJob == null ?
+ null : new JobStatus(mRunningJob);
}
}
@@ -255,15 +262,22 @@
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- if (!name.equals(mRunningJob.getServiceComponent())) {
+ JobStatus runningJob;
+ synchronized (mLock) {
+ // This isn't strictly necessary b/c the JobServiceHandler is running on the main
+ // looper and at this point we can't get any binder callbacks from the client. Better
+ // safe than sorry.
+ runningJob = mRunningJob;
+ }
+ if (runningJob == null || !name.equals(runningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
this.service = IJobService.Stub.asInterface(service);
final PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mRunningJob.getTag());
- mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
+ mWakeLock.setWorkSource(new WorkSource(runningJob.getUid()));
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
@@ -281,13 +295,15 @@
* @return True if the binder calling is coming from the client we expect.
*/
private boolean verifyCallingUid() {
- if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
- if (DEBUG) {
- Slog.d(TAG, "Stale callback received, ignoring.");
+ synchronized (mLock) {
+ if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stale callback received, ignoring.");
+ }
+ return false;
}
- return false;
+ return true;
}
- return true;
}
/**
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 69c63f3..c02611f 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -82,6 +82,13 @@
this.numFailures = numFailures;
}
+ /** Copy constructor. */
+ public JobStatus(JobStatus jobStatus) {
+ this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
+ this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
+ this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
+ }
+
/** Create a newly scheduled job. */
public JobStatus(JobInfo job, int uId) {
this(job, uId, 0);
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index 88ef366..a4d5bce 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -176,7 +176,7 @@
}
mTrackers.clear();
for (UserHandle user : UserManager.get(mContext).getUserProfiles()) {
- final Context context = user.isOwner() ? mContext : getContextForUser(mContext, user);
+ final Context context = user.isSystem() ? mContext : getContextForUser(mContext, user);
if (context == null) {
Slog.w(TAG, "Unable to create context for user " + user.getIdentifier());
continue;
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 8176aff..8abc8fc 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -586,6 +586,8 @@
grantRuntimePermissionsLPw(wearHomePackage, PHONE_PERMISSIONS, true, userId);
grantRuntimePermissionsLPw(wearHomePackage, MICROPHONE_PERMISSIONS, false,
userId);
+ grantRuntimePermissionsLPw(wearHomePackage, LOCATION_PERMISSIONS, false,
+ userId);
}
}
@@ -596,7 +598,10 @@
private void grantDefaultPermissionsToDefaultSystemDialerAppLPr(
PackageParser.Package dialerPackage, int userId) {
if (doesPackageSupportRuntimePermissions(dialerPackage)) {
- grantRuntimePermissionsLPw(dialerPackage, PHONE_PERMISSIONS, userId);
+ boolean isPhonePermFixed =
+ mService.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ grantRuntimePermissionsLPw(
+ dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, userId);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 6c6871f..56c4fb1 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -28,7 +28,6 @@
import android.util.Slog;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -166,12 +165,7 @@
String oatDir = null;
if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
dexoptType = "dex2oat";
- try {
- oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
- } catch (IOException ioe) {
- Slog.w(TAG, "Unable to create oatDir for package: " + pkg.packageName);
- return DEX_OPT_FAILED;
- }
+ oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
} else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
dexoptType = "patchoat";
} else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
@@ -230,8 +224,7 @@
* cannot be created.
*/
@Nullable
- private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)
- throws IOException {
+ private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet) {
if (!pkg.canHaveOatDir()) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6e32e5c..b0e43a5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -481,6 +481,7 @@
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
"Failed to resolve stage location", e);
}
+ final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
// Verify that stage looks sane with respect to existing application.
// This currently only ensures packageName, versionCode, and certificate
@@ -488,7 +489,10 @@
validateInstallLocked();
Preconditions.checkNotNull(mPackageName);
- Preconditions.checkNotNull(mSignatures);
+ // TODO: fix b/25118622; don't bypass signature check
+ if (!quickInstall) {
+ Preconditions.checkNotNull(mSignatures);
+ }
Preconditions.checkNotNull(mResolvedBaseFile);
if (!mPermissionsAccepted) {
@@ -598,6 +602,7 @@
* {@link PackageManagerService}.
*/
private void validateInstallLocked() throws PackageManagerException {
+ final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
mPackageName = null;
mVersionCode = -1;
mSignatures = null;
@@ -621,7 +626,9 @@
final ApkLite apk;
try {
- apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ // TODO: fix b/25118622; always use PARSE_COLLECT_CERTIFICATES
+ final int parseFlags = quickInstall ? 0 : PackageParser.PARSE_COLLECT_CERTIFICATES;
+ apk = PackageParser.parseApkLite(file, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
@@ -742,6 +749,7 @@
}
private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
+ final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
if (!mPackageName.equals(apk.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
+ apk.packageName + " inconsistent with " + mPackageName);
@@ -751,7 +759,8 @@
+ " version code " + apk.versionCode + " inconsistent with "
+ mVersionCode);
}
- if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
+ // TODO: fix b/25118622; don't bypass signature check
+ if (!quickInstall && !Signature.areExactMatch(mSignatures, apk.signatures)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
tag + " signatures are inconsistent");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f7f38db..496653e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2321,7 +2321,7 @@
+ mSdkVersion + "; regranting permissions for internal storage");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, updateFlags);
+ updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
// If this is the first boot or an update from pre-M, and it is a normal
@@ -7685,8 +7685,8 @@
// We would never need to extract libs for forward-locked and external packages,
// since the container service will do it for us. We shouldn't attempt to
// extract libs from system app when it was not updated.
- if (pkg.isForwardLocked() || isExternal(pkg) ||
- (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) ) {
+ if (pkg.isForwardLocked() || pkg.applicationInfo.isExternalAsec() ||
+ (isSystemApp(pkg) && !pkg.isUpdatedSystemApp())) {
extractLibs = false;
}
@@ -7967,7 +7967,7 @@
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
- final boolean asecApp = info.isForwardLocked() || isExternal(info);
+ final boolean asecApp = info.isForwardLocked() || info.isExternalAsec();
info.nativeLibraryRootDir = null;
info.nativeLibraryRootRequiresIsa = false;
@@ -8365,8 +8365,14 @@
static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1;
static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2;
+ private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo,
+ int flags) {
+ final String volumeUuid = (pkgInfo != null) ? getVolumeUuidForPackage(pkgInfo) : null;
+ updatePermissionsLPw(changingPkg, pkgInfo, volumeUuid, flags);
+ }
+
private void updatePermissionsLPw(String changingPkg,
- PackageParser.Package pkgInfo, int flags) {
+ PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) {
// Make sure there are no dangling permission trees.
Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
@@ -8435,14 +8441,21 @@
if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
- grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
- changingPkg);
+ // Only replace for packages on requested volume
+ final String volumeUuid = getVolumeUuidForPackage(pkg);
+ final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
+ && Objects.equals(replaceVolumeUuid, volumeUuid);
+ grantPermissionsLPw(pkg, replace, changingPkg);
}
}
}
if (pkgInfo != null) {
- grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
+ // Only replace for packages on requested volume
+ final String volumeUuid = getVolumeUuidForPackage(pkgInfo);
+ final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0)
+ && Objects.equals(replaceVolumeUuid, volumeUuid);
+ grantPermissionsLPw(pkgInfo, replace, changingPkg);
}
}
@@ -10087,6 +10100,10 @@
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
+ // TODO: fix b/25118622; don't bypass verification
+ if (Build.IS_DEBUGGABLE && (installFlags & PackageManager.INSTALL_QUICK) != 0) {
+ return false;
+ }
boolean ensureVerifyAppsEnabled = isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS);
@@ -12412,6 +12429,7 @@
final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
|| (args.volumeUuid != null));
+ final boolean quickInstall = ((installFlags & PackageManager.INSTALL_QUICK) != 0);
boolean replace = false;
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
if (args.move != null) {
@@ -12427,7 +12445,8 @@
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
- | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
+ | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
+ | (quickInstall ? PackageParser.PARSE_SKIP_VERIFICATION : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
@@ -12457,7 +12476,6 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
pp.collectCertificates(pkg, parseFlags);
- pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
@@ -12467,6 +12485,16 @@
/* If the installer passed in a manifest digest, compare it now. */
if (args.manifestDigest != null) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectManifestDigest");
+ try {
+ pp.collectManifestDigest(pkg);
+ } catch (PackageParserException e) {
+ res.setError("Failed collect during installPackageLI", e);
+ return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
if (DEBUG_INSTALL) {
final String parsedManifest = pkg.manifestDigest == null ? "null"
: pkg.manifestDigest.toString();
@@ -12644,7 +12672,7 @@
int result = mPackageDexOptimizer
.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
false /* defer */, false /* inclDependencies */,
- true /*bootComplete*/, false /*useJit*/);
+ true /*bootComplete*/, quickInstall /*useJit*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
@@ -12846,6 +12874,18 @@
return installFlags;
}
+ private String getVolumeUuidForPackage(PackageParser.Package pkg) {
+ if (isExternal(pkg)) {
+ if (TextUtils.isEmpty(pkg.volumeUuid)) {
+ return StorageManager.UUID_PRIMARY_PHYSICAL;
+ } else {
+ return pkg.volumeUuid;
+ }
+ } else {
+ return StorageManager.UUID_PRIVATE_INTERNAL;
+ }
+ }
+
private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) {
if (isExternal(pkg)) {
if (TextUtils.isEmpty(pkg.volumeUuid)) {
@@ -13862,7 +13902,7 @@
if (ps != null) {
libDirRoot = ps.legacyNativeLibraryPathString;
}
- if (p != null && (isExternal(p) || p.isForwardLocked())) {
+ if (p != null && (p.isForwardLocked() || p.applicationInfo.isExternalAsec())) {
final long token = Binder.clearCallingIdentity();
try {
String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
@@ -15716,7 +15756,7 @@
if (isMounted) {
if (DEBUG_SD_INSTALL)
Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr);
+ loadMediaPackages(processCids, uidArr, externalStorage);
startCleaningPackages();
mInstallerService.onSecureContainersAvailable();
} else {
@@ -15771,7 +15811,8 @@
* the cid is added to list of removeCids. We currently don't delete stale
* containers.
*/
- private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr) {
+ private void loadMediaPackages(ArrayMap<AsecInstallArgs, String> processCids, int[] uidArr,
+ boolean externalStorage) {
ArrayList<String> pkgList = new ArrayList<String>();
Set<AsecInstallArgs> keys = processCids.keySet();
@@ -15844,7 +15885,10 @@
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
- final VersionInfo ver = mSettings.getExternalVersion();
+ final VersionInfo ver = externalStorage ? mSettings.getExternalVersion()
+ : mSettings.getInternalVersion();
+ final String volumeUuid = externalStorage ? StorageManager.UUID_PRIMARY_PHYSICAL
+ : StorageManager.UUID_PRIVATE_INTERNAL;
int updateFlags = UPDATE_PERMISSIONS_ALL;
if (ver.sdkVersion != mSdkVersion) {
@@ -15852,7 +15896,7 @@
+ mSdkVersion + "; regranting permissions for external");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, updateFlags);
+ updatePermissionsLPw(null, null, volumeUuid, updateFlags);
// Yay, everything is now upgraded
ver.forceCurrent();
@@ -15986,7 +16030,7 @@
+ mSdkVersion + "; regranting permissions for " + vol.fsUuid);
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
- updatePermissionsLPw(null, null, updateFlags);
+ updatePermissionsLPw(null, null, vol.fsUuid, updateFlags);
// Yay, everything is now upgraded
ver.forceCurrent();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 61d2676..d148a4f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -514,7 +514,18 @@
ArrayList<String> removeStage = new ArrayList<String>();
for (Map.Entry<String,SharedUserSetting> entry : mSharedUsers.entrySet()) {
final SharedUserSetting sus = entry.getValue();
- if (sus == null || sus.packages.size() == 0) {
+ if (sus == null) {
+ removeStage.add(entry.getKey());
+ continue;
+ }
+ // remove packages that are no longer installed
+ for (Iterator<PackageSetting> iter = sus.packages.iterator(); iter.hasNext();) {
+ PackageSetting ps = iter.next();
+ if (mPackages.get(ps.name) == null) {
+ iter.remove();
+ }
+ }
+ if (sus.packages.size() == 0) {
removeStage.add(entry.getKey());
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 80697ed..b36a22e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -598,8 +598,6 @@
@Override
public Bundle getUserRestrictions(int userId) {
- // checkManageUsersPermission("getUserRestrictions");
-
synchronized (mPackagesLock) {
Bundle restrictions = mUserRestrictions.get(userId);
return restrictions != null ? new Bundle(restrictions) : new Bundle();
@@ -1588,7 +1586,7 @@
public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkManageUsersPermission("Only system can get restrictions for other users/apps");
+ checkManageUsersPermission("get application restrictions for other users/apps");
}
synchronized (mPackagesLock) {
// Read the restrictions from XML
@@ -1599,10 +1597,7 @@
@Override
public void setApplicationRestrictions(String packageName, Bundle restrictions,
int userId) {
- if (UserHandle.getCallingUserId() != userId
- || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkManageUsersPermission("Only system can set restrictions for other users/apps");
- }
+ checkManageUsersPermission("set application restrictions");
synchronized (mPackagesLock) {
if (restrictions == null || restrictions.isEmpty()) {
cleanAppRestrictionsForPackage(packageName, userId);
@@ -1623,7 +1618,7 @@
@Override
public void removeRestrictions() {
- checkManageUsersPermission("Only system can remove restrictions");
+ checkManageUsersPermission("remove restrictions");
final int userHandle = UserHandle.getCallingUserId();
removeRestrictionsForUser(userHandle, true);
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 276d7cd..ecc1f2c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1283,8 +1283,6 @@
mDtDy = tmpFloats[Matrix.MSCALE_Y];
float x = tmpFloats[Matrix.MTRANS_X];
float y = tmpFloats[Matrix.MTRANS_Y];
- int w = frame.width();
- int h = frame.height();
mWin.mShownPosition.set((int) x, (int) y);
mShownAlpha = mAlpha;
@@ -1381,7 +1379,6 @@
// avoid premature clipping with the system decor rect.
clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
}
-
// Expand the clip rect for surface insets.
final WindowManager.LayoutParams attrs = w.mAttrs;
clipRect.left -= attrs.surfaceInsets.left;
@@ -1395,17 +1392,14 @@
// clip rect extends outside the system decor rect.
clipRect.intersect(mClipRect);
}
-
// The clip rect was generated assuming (0,0) as the window origin,
// so we need to translate to match the actual surface coordinates.
clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
-
// We don't want to clip to stack bounds windows that are currently doing entrance
// animation for docked window, otherwise the animating window will be suddenly cut off.
if (!(mAnimator.mAnimating && w.inDockedWorkspace())) {
adjustCropToStackBounds(w, clipRect);
}
-
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
try {
@@ -1437,18 +1431,24 @@
if (appToken != null && appToken.mCropWindowsToStack && !appToken.mReplacingWindow) {
TaskStack stack = w.getTask().mStack;
stack.getBounds(mTmpStackBounds);
- final int surfaceX = (int) mSurfaceX;
- final int surfaceY = (int) mSurfaceY;
+ // When we resize we use the big surface approach, which means we can't trust the
+ // window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
+ // hardcoding it, we use surface coordinates.
+ final boolean isResizing = w.isDragResizing();
+ final int frameX = isResizing ? (int) mSurfaceX :
+ w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
+ final int frameY = isResizing ? (int) mSurfaceY :
+ w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
// We need to do some acrobatics with surface position, because their clip region is
// relative to the inside of the surface, but the stack bounds aren't.
clipRect.left = Math.max(0,
- Math.max(mTmpStackBounds.left, surfaceX + clipRect.left) - surfaceX);
+ Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
clipRect.top = Math.max(0,
- Math.max(mTmpStackBounds.top, surfaceY + clipRect.top) - surfaceY);
+ Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
clipRect.right = Math.max(0,
- Math.min(mTmpStackBounds.right, surfaceX + clipRect.right) - surfaceX);
+ Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
clipRect.bottom = Math.max(0,
- Math.min(mTmpStackBounds.bottom, surfaceY + clipRect.bottom) - surfaceY);
+ Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
}
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8cb0a13..be190cb 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -238,7 +238,8 @@
/* --- PointerControllerPolicyInterface implementation --- */
virtual void loadPointerResources(PointerResources* outResources);
- virtual void loadAdditionalMouseResources(std::map<int, SpriteIcon>* outResources);
+ virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources);
+ virtual int32_t getDefaultPointerIconId();
private:
sp<InputManager> mInputManager;
@@ -786,7 +787,7 @@
sp<PointerController> controller = mLocked.pointerController.promote();
if (controller != NULL) {
// Use 0 (the default icon) for ARROW.
- controller->updatePointerShape((iconId == POINTER_ICON_STYLE_ARROW) ? 0 : iconId);
+ controller->updatePointerShape(iconId);
}
}
@@ -1040,15 +1041,19 @@
&outResources->spotAnchor);
}
-void NativeInputManager::loadAdditionalMouseResources(std::map<int, SpriteIcon>* outResources) {
+void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources) {
JNIEnv* env = jniEnv();
for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING;
++iconId) {
loadSystemIconAsSprite(env, mContextObj, iconId, &((*outResources)[iconId]));
}
+ loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL, &((*outResources)[POINTER_ICON_STYLE_NULL]));
}
+int32_t NativeInputManager::getDefaultPointerIconId() {
+ return POINTER_ICON_STYLE_ARROW;
+}
// ----------------------------------------------------------------------------
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4748c96..8385685 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3494,7 +3494,7 @@
final UserHandle caller = mInjector.binderGetCallingUserHandle();
// If there is a profile owner, redirect to that; otherwise query the device owner.
ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
- if (aliasChooser == null && caller.isOwner()) {
+ if (aliasChooser == null && caller.isSystem()) {
ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
if (deviceOwnerAdmin != null) {
aliasChooser = deviceOwnerAdmin.info.getComponent();
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 703564c..5ecd2b5 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -52,6 +52,32 @@
public final class PhoneAccount implements Parcelable {
/**
+ * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
+ * maximum permitted length of a call subject specified via the
+ * {@link TelecomManager#EXTRA_CALL_SUBJECT} extra on an
+ * {@link android.content.Intent#ACTION_CALL} intent. Ultimately a {@link ConnectionService} is
+ * responsible for enforcing the maximum call subject length when sending the message, however
+ * this extra is provided so that the user interface can proactively limit the length of the
+ * call subject as the user types it.
+ */
+ public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH =
+ "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+
+ /**
+ * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
+ * character encoding to be used when determining the length of messages.
+ * The user interface can use this when determining the number of characters the user may type
+ * in a call subject. If empty-string, the call subject message size limit will be enforced on
+ * a 1:1 basis. That is, each character will count towards the messages size limit as a single
+ * character. If a character encoding is specified, the message size limit will be based on the
+ * number of bytes in the message per the specified encoding. See
+ * {@link #EXTRA_CALL_SUBJECT_MAX_LENGTH} for more information on the call subject maximum
+ * length.
+ */
+ public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING =
+ "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
+
+ /**
* Flag indicating that this {@code PhoneAccount} can act as a connection manager for
* other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
* will be allowed to manage phone calls including using its own proprietary phone-call
@@ -213,6 +239,7 @@
mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
mIcon = phoneAccount.getIcon();
mIsEnabled = phoneAccount.isEnabled();
+ mExtras = phoneAccount.getExtras();
}
/**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7cf5f73..8ebef32 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -268,6 +268,13 @@
= "carrier_allow_turnoff_ims_bool";
/**
+ * Flag specifying whether Generic Bootstrapping Architecture capable SIM is required for IMS.
+ * @hide
+ */
+ public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
+ = "carrier_ims_gba_required_bool";
+
+ /**
* Flag specifying whether IMS instant lettering is available for the carrier. {@code True} if
* instant lettering is available for the carrier, {@code false} otherwise.
* @hide
@@ -535,6 +542,7 @@
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
+ sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true);
sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, "");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d22727d..6b1b6296 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2874,7 +2874,7 @@
/**
* Returns all observed cell information from all radios on the
* device including the primary and neighboring cells. This does
- * not cause or change the rate of PhoneStateListner#onCellInfoChanged.
+ * not cause or change the rate of PhoneStateListener#onCellInfoChanged.
*<p>
* The list can include one or more of {@link android.telephony.CellInfoGsm CellInfoGsm},
* {@link android.telephony.CellInfoCdma CellInfoCdma},
@@ -2888,6 +2888,9 @@
* devices this may return null in which case getCellLocation should
* be called.
*<p>
+ * This API will return valid data for registered cells on devices with
+ * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}
+ *<p>
* @return List of CellInfo or null if info unavailable.
*
* <p>Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}