summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/ActivityManager.java13
-rw-r--r--core/java/android/app/ActivityManagerNative.java27
-rw-r--r--core/java/android/app/ActivityThread.java3
-rw-r--r--core/java/android/app/ContextImpl.java9
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/app/IStopUserCallback.aidl27
-rwxr-xr-xcore/java/android/bluetooth/BluetoothAdapter.java3
-rw-r--r--core/java/android/bluetooth/BluetoothTetheringDataTracker.java5
-rw-r--r--core/java/android/content/Intent.java10
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/hardware/Camera.java51
-rw-r--r--core/java/android/hardware/display/DisplayManager.java206
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java273
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl6
-rw-r--r--core/java/android/hardware/display/IDisplayManagerCallback.aidl22
-rw-r--r--core/java/android/net/BaseNetworkStateTracker.java5
-rw-r--r--core/java/android/net/CaptivePortalTracker.java282
-rw-r--r--core/java/android/net/ConnectivityManager.java11
-rw-r--r--core/java/android/net/DhcpStateMachine.java8
-rw-r--r--core/java/android/net/DummyDataStateTracker.java4
-rw-r--r--core/java/android/net/EthernetDataTracker.java5
-rw-r--r--core/java/android/net/IConnectivityManager.aidl2
-rw-r--r--core/java/android/net/MobileDataStateTracker.java5
-rw-r--r--core/java/android/net/NetworkInfo.java5
-rw-r--r--core/java/android/net/NetworkStateTracker.java5
-rw-r--r--core/java/android/net/VpnService.java2
-rw-r--r--core/java/android/os/Handler.java81
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/provider/Settings.java58
-rw-r--r--core/java/android/speech/tts/BlockingAudioTrack.java35
-rw-r--r--core/java/android/view/Choreographer.java10
-rw-r--r--core/java/android/view/Display.java63
-rw-r--r--core/java/android/view/DisplayEventReceiver.java10
-rw-r--r--core/java/android/view/DisplayInfo.java4
-rw-r--r--core/java/android/view/GestureDetector.java118
-rw-r--r--core/java/android/view/InputEventReceiver.java10
-rw-r--r--core/java/android/view/ScaleGestureDetector.java446
-rw-r--r--core/java/android/view/Surface.java936
-rw-r--r--core/java/android/view/SurfaceSession.java42
-rw-r--r--core/java/android/view/View.java39
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/view/WindowManager.java9
-rw-r--r--core/java/android/view/WindowManagerImpl.java3
-rw-r--r--core/java/android/webkit/AccessibilityInjector.java18
-rw-r--r--core/java/android/webkit/BrowserDownloadListener.java57
-rw-r--r--core/java/android/webkit/BrowserFrame.java4
-rw-r--r--core/java/android/webkit/CallbackProxy.java14
-rw-r--r--core/java/android/webkit/WebSettingsClassic.java1
-rw-r--r--core/java/android/webkit/WebViewClassic.java24
-rw-r--r--core/java/android/widget/AbsListView.java4
-rw-r--r--core/java/android/widget/MediaController.java3
-rw-r--r--core/java/android/widget/Toast.java9
-rw-r--r--core/java/android/widget/ViewAnimator.java15
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java8
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java2
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/Bitmap.cpp14
-rw-r--r--core/jni/android_app_NativeActivity.cpp2
-rw-r--r--core/jni/android_opengl_EGL14.cpp2
-rw-r--r--core/jni/android_view_Surface.cpp1015
-rw-r--r--core/jni/android_view_SurfaceSession.cpp79
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp2
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/res/res/anim/keyguard_security_animate_in.xml33
-rw-r--r--core/res/res/anim/keyguard_security_animate_out.xml32
-rw-r--r--core/res/res/drawable-nodpi/kg_widget_overscroll_layer_left.9.pngbin0 -> 2212 bytes
-rw-r--r--core/res/res/drawable-nodpi/kg_widget_overscroll_layer_right.9.pngbin0 -> 1451 bytes
-rw-r--r--core/res/res/layout-land/keyguard_host_view.xml58
-rw-r--r--core/res/res/layout-port/keyguard_host_view.xml47
-rw-r--r--core/res/res/layout-sw600dp-land/keyguard_host_view.xml67
-rw-r--r--core/res/res/layout-sw600dp-port/keyguard_host_view.xml61
-rw-r--r--core/res/res/layout/keyguard_account_view.xml72
-rw-r--r--core/res/res/layout/keyguard_face_unlock_view.xml31
-rw-r--r--core/res/res/layout/keyguard_navigation.xml61
-rw-r--r--core/res/res/layout/keyguard_password_view.xml100
-rw-r--r--core/res/res/layout/keyguard_pattern_view.xml55
-rw-r--r--core/res/res/layout/keyguard_selector_view.xml82
-rw-r--r--core/res/res/layout/keyguard_sim_pin_view.xml82
-rw-r--r--core/res/res/layout/keyguard_sim_puk_view.xml133
-rw-r--r--core/res/res/layout/keyguard_status_view.xml119
-rw-r--r--core/res/res/layout/overlay_display_window.xml27
-rw-r--r--core/res/res/values-af/strings.xml8
-rw-r--r--core/res/res/values-am/strings.xml10
-rw-r--r--core/res/res/values-ar/strings.xml8
-rw-r--r--core/res/res/values-be/strings.xml8
-rw-r--r--core/res/res/values-bg/strings.xml8
-rw-r--r--core/res/res/values-ca/strings.xml8
-rw-r--r--core/res/res/values-cs/strings.xml8
-rw-r--r--core/res/res/values-da/strings.xml8
-rw-r--r--core/res/res/values-de/strings.xml8
-rw-r--r--core/res/res/values-el/strings.xml8
-rw-r--r--core/res/res/values-en-rGB/strings.xml8
-rw-r--r--core/res/res/values-es-rUS/strings.xml12
-rw-r--r--core/res/res/values-es/strings.xml8
-rw-r--r--core/res/res/values-et/strings.xml8
-rw-r--r--core/res/res/values-fa/strings.xml8
-rw-r--r--core/res/res/values-fi/strings.xml8
-rw-r--r--core/res/res/values-fr/strings.xml8
-rw-r--r--core/res/res/values-hi/strings.xml10
-rw-r--r--core/res/res/values-hr/strings.xml8
-rw-r--r--core/res/res/values-hu/strings.xml8
-rw-r--r--core/res/res/values-in/strings.xml8
-rw-r--r--core/res/res/values-it/strings.xml8
-rw-r--r--core/res/res/values-iw/strings.xml8
-rw-r--r--core/res/res/values-ja/strings.xml8
-rw-r--r--core/res/res/values-ko/strings.xml10
-rw-r--r--core/res/res/values-lt/strings.xml8
-rw-r--r--core/res/res/values-lv/strings.xml10
-rw-r--r--core/res/res/values-ms/strings.xml8
-rw-r--r--core/res/res/values-nb/strings.xml8
-rw-r--r--core/res/res/values-nl/strings.xml8
-rw-r--r--core/res/res/values-pl/strings.xml8
-rw-r--r--core/res/res/values-pt-rPT/strings.xml8
-rw-r--r--core/res/res/values-pt/strings.xml8
-rw-r--r--core/res/res/values-rm/strings.xml8
-rw-r--r--core/res/res/values-ro/strings.xml8
-rw-r--r--core/res/res/values-ru/strings.xml8
-rw-r--r--core/res/res/values-sk/strings.xml8
-rw-r--r--core/res/res/values-sl/strings.xml8
-rw-r--r--core/res/res/values-sr/strings.xml8
-rw-r--r--core/res/res/values-sv/strings.xml8
-rw-r--r--core/res/res/values-sw/strings.xml8
-rw-r--r--core/res/res/values-th/strings.xml8
-rw-r--r--core/res/res/values-tl/strings.xml8
-rw-r--r--core/res/res/values-tr/strings.xml8
-rw-r--r--core/res/res/values-uk/strings.xml8
-rw-r--r--core/res/res/values-vi/strings.xml8
-rw-r--r--core/res/res/values-zh-rCN/strings.xml8
-rw-r--r--core/res/res/values-zh-rTW/strings.xml8
-rw-r--r--core/res/res/values-zu/strings.xml8
-rwxr-xr-xcore/res/res/values/attrs.xml18
-rw-r--r--core/res/res/values/dimens.xml16
-rw-r--r--core/res/res/values/integers.xml21
-rw-r--r--core/res/res/values/public.xml64
-rwxr-xr-xcore/res/res/values/strings.xml43
136 files changed, 4290 insertions, 1495 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e644db4..26d8c17 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -31,6 +31,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -210,6 +211,15 @@ public class ActivityManager {
*/
public static final int INTENT_SENDER_SERVICE = 4;
+ /** @hide User operation call: success! */
+ public static final int USER_OP_SUCCESS = 0;
+
+ /** @hide User operation call: given user id is not known. */
+ public static final int USER_OP_UNKNOWN_USER = -1;
+
+ /** @hide User operation call: given user id is the current user, can't be stopped. */
+ public static final int USER_OP_IS_CURRENT = -2;
+
/*package*/ ActivityManager(Context context, Handler handler) {
mContext = context;
mHandler = handler;
@@ -376,7 +386,8 @@ public class ActivityManager {
return true;
}
- Display display = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+ Display display = DisplayManagerGlobal.getInstance().getRealDisplay(
+ Display.DEFAULT_DISPLAY);
Point p = new Point();
display.getRealSize(p);
int pixels = p.x * p.y;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index adc9434..05c009f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1570,6 +1570,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case STOP_USER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int userid = data.readInt();
+ IStopUserCallback callback = IStopUserCallback.Stub.asInterface(
+ data.readStrongBinder());
+ int result = stopUser(userid, callback);
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
+
case GET_CURRENT_USER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
UserInfo userInfo = getCurrentUser();
@@ -3756,11 +3767,25 @@ class ActivityManagerProxy implements IActivityManager
return result;
}
+ public int stopUser(int userid, IStopUserCallback callback) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(userid);
+ data.writeStrongInterface(callback);
+ mRemote.transact(STOP_USER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int result = reply.readInt();
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
+
public UserInfo getCurrentUser() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(SWITCH_USER_TRANSACTION, data, reply, 0);
+ mRemote.transact(GET_CURRENT_USER_TRANSACTION, data, reply, 0);
reply.readException();
UserInfo userInfo = UserInfo.CREATOR.createFromParcel(reply);
reply.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b8e16c5..4a1bf75 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -43,6 +43,7 @@ import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.net.IConnectivityManager;
import android.net.Proxy;
import android.net.ProxyProperties;
@@ -1557,7 +1558,7 @@ public final class ActivityThread {
return dm;
}
- DisplayManager displayManager = DisplayManager.getInstance();
+ DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
if (displayManager == null) {
// may be null early in system startup
dm = new DisplayMetrics();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 32086d7..efe4b7b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -349,10 +349,11 @@ class ContextImpl extends Context {
return InputManager.getInstance();
}});
- registerService(DISPLAY_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
- return DisplayManager.getInstance();
- }});
+ registerService(DISPLAY_SERVICE, new ServiceFetcher() {
+ @Override
+ public Object createService(ContextImpl ctx) {
+ return new DisplayManager(ctx.getOuterContext());
+ }});
registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c3e911e..70d8445 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -331,6 +331,7 @@ public interface IActivityManager extends IInterface {
// Multi-user APIs
public boolean switchUser(int userid) throws RemoteException;
+ public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
public UserInfo getCurrentUser() throws RemoteException;
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
@@ -611,4 +612,5 @@ public interface IActivityManager extends IInterface {
int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+150;
int IS_INTENT_SENDER_AN_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+151;
int START_ACTIVITY_AS_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+152;
+ int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153;
}
diff --git a/core/java/android/app/IStopUserCallback.aidl b/core/java/android/app/IStopUserCallback.aidl
new file mode 100644
index 0000000..19ac1d5
--- /dev/null
+++ b/core/java/android/app/IStopUserCallback.aidl
@@ -0,0 +1,27 @@
+/*
+** 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.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app;
+
+/**
+ * Callback to find out when we have finished stopping a user.
+ * {@hide}
+ */
+interface IStopUserCallback
+{
+ void userStopped(int userId);
+ void userStopAborted(int userId);
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 17d404d..f817fb4 100755
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -75,6 +75,7 @@ import java.util.UUID;
public final class BluetoothAdapter {
private static final String TAG = "BluetoothAdapter";
private static final boolean DBG = true;
+ private static final boolean VDBG = false;
/**
* Sentinel error value for this class. Guaranteed to not equal any other
@@ -465,7 +466,7 @@ public final class BluetoothAdapter {
if (mService != null)
{
int state= mService.getState();
- if (DBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+ if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
return state;
}
// TODO(BT) there might be a small gap during STATE_TURNING_ON that
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index b2b5d81..30406e9 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -133,6 +133,11 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
return true;
}
+ @Override
+ public void captivePortalCheckComplete() {
+ // not implemented
+ }
+
/**
* Re-enable connectivity to a network after a {@link #teardown()}.
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 06edf32..53e0a75 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -27,7 +27,6 @@ import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
-import android.media.RemoteControlClient;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -2287,6 +2286,15 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.USER_ADDED";
/**
+ * Broadcast sent to the system when a user is stopped. Carries an extra EXTRA_USER_HANDLE that has
+ * the userHandle of the user. This is similar to {@link #ACTION_PACKAGE_RESTARTED},
+ * but for an entire user instead of a specific package.
+ * @hide
+ */
+ public static final String ACTION_USER_STOPPED =
+ "android.intent.action.USER_STOPPED";
+
+ /**
* Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USER_HANDLE that has
* the userHandle of the user.
* @hide
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0d99d3f..0aa094f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2319,6 +2319,9 @@ public abstract class PackageManager {
* {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
* @param verificationCode either {@link PackageManager#VERIFICATION_ALLOW}
* or {@link PackageManager#VERIFICATION_REJECT}.
+ * @throws SecurityException if the caller does not have the
+ * {@link android.Manifest.permission#PACKAGE_VERIFICATION_AGENT}
+ * permission.
*/
public abstract void verifyPendingInstall(int id, int verificationCode);
@@ -2342,9 +2345,11 @@ public abstract class PackageManager {
* @param millisecondsToDelay the amount of time requested for the timeout.
* Must be positive and less than
* {@link PackageManager#MAXIMUM_VERIFICATION_TIMEOUT}.
- *
* @throws IllegalArgumentException if {@code millisecondsToDelay} is out
* of bounds or {@code verificationCodeAtTimeout} is unknown.
+ * @throws SecurityException if the caller does not have the
+ * {@link android.Manifest.permission#PACKAGE_VERIFICATION_AGENT}
+ * permission.
*/
public abstract void extendVerificationTimeout(int id,
int verificationCodeAtTimeout, long millisecondsToDelay);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 4d9077f..829620b 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -26,6 +26,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
+import android.text.TextUtils;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -34,7 +35,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import java.util.StringTokenizer;
import java.util.concurrent.locks.ReentrantLock;
/**
@@ -1905,7 +1905,7 @@ public class Camera {
private HashMap<String, String> mMap;
private Parameters() {
- mMap = new HashMap<String, String>();
+ mMap = new HashMap<String, String>(64);
}
/**
@@ -1929,7 +1929,7 @@ public class Camera {
* semi-colon delimited key-value pairs
*/
public String flatten() {
- StringBuilder flattened = new StringBuilder();
+ StringBuilder flattened = new StringBuilder(128);
for (String k : mMap.keySet()) {
flattened.append(k);
flattened.append("=");
@@ -1952,9 +1952,9 @@ public class Camera {
public void unflatten(String flattened) {
mMap.clear();
- StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
- while (tokenizer.hasMoreElements()) {
- String kv = tokenizer.nextToken();
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(';');
+ splitter.setString(flattened);
+ for (String kv : splitter) {
int pos = kv.indexOf('=');
if (pos == -1) {
continue;
@@ -3488,11 +3488,11 @@ public class Camera {
private ArrayList<String> split(String str) {
if (str == null) return null;
- // Use StringTokenizer because it is faster than split.
- StringTokenizer tokenizer = new StringTokenizer(str, ",");
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
ArrayList<String> substrings = new ArrayList<String>();
- while (tokenizer.hasMoreElements()) {
- substrings.add(tokenizer.nextToken());
+ for (String s : splitter) {
+ substrings.add(s);
}
return substrings;
}
@@ -3502,11 +3502,11 @@ public class Camera {
private ArrayList<Integer> splitInt(String str) {
if (str == null) return null;
- StringTokenizer tokenizer = new StringTokenizer(str, ",");
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
ArrayList<Integer> substrings = new ArrayList<Integer>();
- while (tokenizer.hasMoreElements()) {
- String token = tokenizer.nextToken();
- substrings.add(Integer.parseInt(token));
+ for (String s : splitter) {
+ substrings.add(Integer.parseInt(s));
}
if (substrings.size() == 0) return null;
return substrings;
@@ -3515,11 +3515,11 @@ public class Camera {
private void splitInt(String str, int[] output) {
if (str == null) return;
- StringTokenizer tokenizer = new StringTokenizer(str, ",");
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
int index = 0;
- while (tokenizer.hasMoreElements()) {
- String token = tokenizer.nextToken();
- output[index++] = Integer.parseInt(token);
+ for (String s : splitter) {
+ output[index++] = Integer.parseInt(s);
}
}
@@ -3527,11 +3527,11 @@ public class Camera {
private void splitFloat(String str, float[] output) {
if (str == null) return;
- StringTokenizer tokenizer = new StringTokenizer(str, ",");
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
int index = 0;
- while (tokenizer.hasMoreElements()) {
- String token = tokenizer.nextToken();
- output[index++] = Float.parseFloat(token);
+ for (String s : splitter) {
+ output[index++] = Float.parseFloat(s);
}
}
@@ -3558,10 +3558,11 @@ public class Camera {
private ArrayList<Size> splitSize(String str) {
if (str == null) return null;
- StringTokenizer tokenizer = new StringTokenizer(str, ",");
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
ArrayList<Size> sizeList = new ArrayList<Size>();
- while (tokenizer.hasMoreElements()) {
- Size size = strToSize(tokenizer.nextToken());
+ for (String s : splitter) {
+ Size size = strToSize(s);
if (size != null) sizeList.add(size);
}
if (sizeList.size() == 0) return null;
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 98d2f69..74996da 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -18,20 +18,12 @@ package android.hardware.display;
import android.content.Context;
import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
+import android.util.SparseArray;
import android.view.CompatibilityInfoHolder;
import android.view.Display;
-import android.view.DisplayInfo;
-
-import java.util.ArrayList;
/**
- * Manages the properties, media routing and power state of attached displays.
+ * Manages the properties of attached displays.
* <p>
* Get an instance of this class by calling
* {@link android.content.Context#getSystemService(java.lang.String)
@@ -43,110 +35,79 @@ public final class DisplayManager {
private static final String TAG = "DisplayManager";
private static final boolean DEBUG = false;
- private static final int MSG_DISPLAY_ADDED = 1;
- private static final int MSG_DISPLAY_REMOVED = 2;
- private static final int MSG_DISPLAY_CHANGED = 3;
-
- private static DisplayManager sInstance;
-
- private final IDisplayManager mDm;
-
- // Guarded by mDisplayLock
- private final Object mDisplayLock = new Object();
- private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
- new ArrayList<DisplayListenerDelegate>();
+ private final Context mContext;
+ private final DisplayManagerGlobal mGlobal;
+ private final Object mLock = new Object();
+ private final SparseArray<Display> mDisplays = new SparseArray<Display>();
- private DisplayManager(IDisplayManager dm) {
- mDm = dm;
+ /** @hide */
+ public DisplayManager(Context context) {
+ mContext = context;
+ mGlobal = DisplayManagerGlobal.getInstance();
}
/**
- * Gets an instance of the display manager.
+ * Gets information about a logical display.
*
- * @return The display manager instance, may be null early in system startup
- * before the display manager has been fully initialized.
+ * The display metrics may be adjusted to provide compatibility
+ * for legacy applications.
*
- * @hide
+ * @param displayId The logical display id.
+ * @return The display object, or null if there is no valid display with the given id.
*/
- public static DisplayManager getInstance() {
- synchronized (DisplayManager.class) {
- if (sInstance == null) {
- IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
- if (b != null) {
- sInstance = new DisplayManager(IDisplayManager.Stub.asInterface(b));
- }
- }
- return sInstance;
+ public Display getDisplay(int displayId) {
+ synchronized (mLock) {
+ return getOrCreateDisplayLocked(displayId, false /*assumeValid*/);
}
}
/**
- * Get information about a particular logical display.
+ * Gets all currently valid logical displays.
*
- * @param displayId The logical display id.
- * @param outInfo A structure to populate with the display info.
- * @return True if the logical display exists, false otherwise.
- * @hide
+ * @return An array containing all displays.
*/
- public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) {
- try {
- return mDm.getDisplayInfo(displayId, outInfo);
- } catch (RemoteException ex) {
- Log.e(TAG, "Could not get display information from display manager.", ex);
- return false;
+ public Display[] getDisplays() {
+ int[] displayIds = mGlobal.getDisplayIds();
+ int expectedCount = displayIds.length;
+ Display[] displays = new Display[expectedCount];
+ synchronized (mLock) {
+ int actualCount = 0;
+ for (int i = 0; i < expectedCount; i++) {
+ Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
+ if (display != null) {
+ displays[actualCount++] = display;
+ }
+ }
+ if (actualCount != expectedCount) {
+ Display[] oldDisplays = displays;
+ displays = new Display[actualCount];
+ System.arraycopy(oldDisplays, 0, displays, 0, actualCount);
+ }
}
+ return displays;
}
- /**
- * Gets information about a logical display.
- *
- * The display metrics may be adjusted to provide compatibility
- * for legacy applications.
- *
- * @param displayId The logical display id.
- * @param applicationContext The application context from which to obtain
- * compatible metrics.
- * @return The display object.
- */
- public Display getDisplay(int displayId, Context applicationContext) {
- if (applicationContext == null) {
- throw new IllegalArgumentException("applicationContext must not be null");
+ private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) {
+ Display display = mDisplays.get(displayId);
+ if (display == null) {
+ display = mGlobal.getCompatibleDisplay(displayId,
+ getCompatibilityInfoForDisplayLocked(displayId));
+ if (display != null) {
+ mDisplays.put(displayId, display);
+ }
+ } else if (!assumeValid && !display.isValid()) {
+ display = null;
}
+ return display;
+ }
+ private CompatibilityInfoHolder getCompatibilityInfoForDisplayLocked(int displayId) {
CompatibilityInfoHolder cih = null;
if (displayId == Display.DEFAULT_DISPLAY) {
- cih = applicationContext.getCompatibilityInfo();
+ cih = mContext.getCompatibilityInfo();
}
- return getCompatibleDisplay(displayId, cih);
- }
-
- /**
- * Gets information about a logical display.
- *
- * The display metrics may be adjusted to provide compatibility
- * for legacy applications.
- *
- * @param displayId The logical display id.
- * @param cih The compatibility info, or null if none is required.
- * @return The display object.
- *
- * @hide
- */
- public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
- return new Display(displayId, cih);
- }
-
- /**
- * Gets information about a logical display without applying any compatibility metrics.
- *
- * @param displayId The logical display id.
- * @return The display object.
- *
- * @hide
- */
- public Display getRealDisplay(int displayId) {
- return getCompatibleDisplay(displayId, null);
+ return cih;
}
/**
@@ -160,16 +121,7 @@ public final class DisplayManager {
* @see #unregisterDisplayListener
*/
public void registerDisplayListener(DisplayListener listener, Handler handler) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- synchronized (mDisplayLock) {
- int index = findDisplayListenerLocked(listener);
- if (index < 0) {
- mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
- }
- }
+ mGlobal.registerDisplayListener(listener, handler);
}
/**
@@ -180,28 +132,7 @@ public final class DisplayManager {
* @see #registerDisplayListener
*/
public void unregisterDisplayListener(DisplayListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- synchronized (mDisplayLock) {
- int index = findDisplayListenerLocked(listener);
- if (index >= 0) {
- DisplayListenerDelegate d = mDisplayListeners.get(index);
- d.removeCallbacksAndMessages(null);
- mDisplayListeners.remove(index);
- }
- }
- }
-
- private int findDisplayListenerLocked(DisplayListener listener) {
- final int numListeners = mDisplayListeners.size();
- for (int i = 0; i < numListeners; i++) {
- if (mDisplayListeners.get(i).mListener == listener) {
- return i;
- }
- }
- return -1;
+ mGlobal.unregisterDisplayListener(listener);
}
/**
@@ -210,7 +141,8 @@ public final class DisplayManager {
public interface DisplayListener {
/**
* Called whenever a logical display has been added to the system.
- * Use {@link DisplayManager#getDisplay} to get more information about the display.
+ * Use {@link DisplayManager#getDisplay} to get more information about
+ * the display.
*
* @param displayId The id of the logical display that was added.
*/
@@ -230,28 +162,4 @@ public final class DisplayManager {
*/
void onDisplayChanged(int displayId);
}
-
- private static final class DisplayListenerDelegate extends Handler {
- public final DisplayListener mListener;
-
- public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
- super(handler != null ? handler.getLooper() : Looper.myLooper());
- mListener = listener;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_DISPLAY_ADDED:
- mListener.onDisplayAdded(msg.arg1);
- break;
- case MSG_DISPLAY_REMOVED:
- mListener.onDisplayRemoved(msg.arg1);
- break;
- case MSG_DISPLAY_CHANGED:
- mListener.onDisplayChanged(msg.arg1);
- break;
- }
- }
- }
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
new file mode 100644
index 0000000..69c0319
--- /dev/null
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.CompatibilityInfoHolder;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Manager communication with the display manager service on behalf of
+ * an application process. You're probably looking for {@link DisplayManager}.
+ *
+ * @hide
+ */
+public final class DisplayManagerGlobal {
+ private static final String TAG = "DisplayManager";
+ private static final boolean DEBUG = false;
+
+ public static final int EVENT_DISPLAY_ADDED = 1;
+ public static final int EVENT_DISPLAY_CHANGED = 2;
+ public static final int EVENT_DISPLAY_REMOVED = 3;
+
+ private static DisplayManagerGlobal sInstance;
+
+ private final Object mLock = new Object();
+
+ private final IDisplayManager mDm;
+
+ private DisplayManagerCallback mCallback;
+ private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
+ new ArrayList<DisplayListenerDelegate>();
+
+ private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
+ private int[] mDisplayIdCache;
+
+ private DisplayManagerGlobal(IDisplayManager dm) {
+ mDm = dm;
+ }
+
+ /**
+ * Gets an instance of the display manager global singleton.
+ *
+ * @return The display manager instance, may be null early in system startup
+ * before the display manager has been fully initialized.
+ */
+ public static DisplayManagerGlobal getInstance() {
+ synchronized (DisplayManagerGlobal.class) {
+ if (sInstance == null) {
+ IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
+ if (b != null) {
+ sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Get information about a particular logical display.
+ *
+ * @param displayId The logical display id.
+ * @return Information about the specified display, or null if it does not exist.
+ * This object belongs to an internal cache and should be treated as if it were immutable.
+ */
+ public DisplayInfo getDisplayInfo(int displayId) {
+ try {
+ synchronized (mLock) {
+ DisplayInfo info = mDisplayInfoCache.get(displayId);
+ if (info != null) {
+ return info;
+ }
+
+ info = mDm.getDisplayInfo(displayId);
+ if (info == null) {
+ return null;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
+ }
+
+ mDisplayInfoCache.put(displayId, info);
+ registerCallbackIfNeededLocked();
+ return info;
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Could not get display information from display manager.", ex);
+ return null;
+ }
+ }
+
+ /**
+ * Gets all currently valid logical display ids.
+ *
+ * @return An array containing all display ids.
+ */
+ public int[] getDisplayIds() {
+ try {
+ synchronized (mLock) {
+ if (mDisplayIdCache == null) {
+ mDisplayIdCache = mDm.getDisplayIds();
+ registerCallbackIfNeededLocked();
+ }
+ return mDisplayIdCache;
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Could not get display ids from display manager.", ex);
+ return new int[] { Display.DEFAULT_DISPLAY };
+ }
+ }
+
+ /**
+ * Gets information about a logical display.
+ *
+ * The display metrics may be adjusted to provide compatibility
+ * for legacy applications.
+ *
+ * @param displayId The logical display id.
+ * @param cih The compatibility info, or null if none is required.
+ * @return The display object, or null if there is no display with the given id.
+ */
+ public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
+ DisplayInfo displayInfo = getDisplayInfo(displayId);
+ if (displayInfo == null) {
+ return null;
+ }
+ return new Display(this, displayId, displayInfo, cih);
+ }
+
+ /**
+ * Gets information about a logical display without applying any compatibility metrics.
+ *
+ * @param displayId The logical display id.
+ * @return The display object, or null if there is no display with the given id.
+ */
+ public Display getRealDisplay(int displayId) {
+ return getCompatibleDisplay(displayId, null);
+ }
+
+ public void registerDisplayListener(DisplayListener listener, Handler handler) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mLock) {
+ int index = findDisplayListenerLocked(listener);
+ if (index < 0) {
+ mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
+ registerCallbackIfNeededLocked();
+ }
+ }
+ }
+
+ public void unregisterDisplayListener(DisplayListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+
+ synchronized (mLock) {
+ int index = findDisplayListenerLocked(listener);
+ if (index >= 0) {
+ DisplayListenerDelegate d = mDisplayListeners.get(index);
+ d.clearEvents();
+ mDisplayListeners.remove(index);
+ }
+ }
+ }
+
+ private int findDisplayListenerLocked(DisplayListener listener) {
+ final int numListeners = mDisplayListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ if (mDisplayListeners.get(i).mListener == listener) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void registerCallbackIfNeededLocked() {
+ if (mCallback == null) {
+ mCallback = new DisplayManagerCallback();
+ try {
+ mDm.registerCallback(mCallback);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to register callback with display manager service.", ex);
+ mCallback = null;
+ }
+ }
+ }
+
+ private void handleDisplayEvent(int displayId, int event) {
+ synchronized (mLock) {
+ mDisplayInfoCache.remove(displayId);
+
+ if (event == EVENT_DISPLAY_ADDED || event == EVENT_DISPLAY_REMOVED) {
+ mDisplayIdCache = null;
+ }
+
+ final int numListeners = mDisplayListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ mDisplayListeners.get(i).sendDisplayEvent(displayId, event);
+ }
+ }
+ }
+
+ private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
+ @Override
+ public void onDisplayEvent(int displayId, int event) {
+ if (DEBUG) {
+ Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
+ }
+ handleDisplayEvent(displayId, event);
+ }
+ }
+
+ private static final class DisplayListenerDelegate extends Handler {
+ public final DisplayListener mListener;
+
+ public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
+ super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
+ mListener = listener;
+ }
+
+ public void sendDisplayEvent(int displayId, int event) {
+ Message msg = obtainMessage(event, displayId, 0);
+ sendMessage(msg);
+ }
+
+ public void clearEvents() {
+ removeCallbacksAndMessages(null);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_DISPLAY_ADDED:
+ mListener.onDisplayAdded(msg.arg1);
+ break;
+ case EVENT_DISPLAY_CHANGED:
+ mListener.onDisplayChanged(msg.arg1);
+ break;
+ case EVENT_DISPLAY_REMOVED:
+ mListener.onDisplayRemoved(msg.arg1);
+ break;
+ }
+ }
+ }
+}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index fd8c35f..d802aa1 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -16,9 +16,13 @@
package android.hardware.display;
+import android.hardware.display.IDisplayManagerCallback;
import android.view.DisplayInfo;
/** @hide */
interface IDisplayManager {
- boolean getDisplayInfo(int displayId, out DisplayInfo outInfo);
+ DisplayInfo getDisplayInfo(int displayId);
+ int[] getDisplayIds();
+
+ void registerCallback(in IDisplayManagerCallback callback);
}
diff --git a/core/java/android/hardware/display/IDisplayManagerCallback.aidl b/core/java/android/hardware/display/IDisplayManagerCallback.aidl
new file mode 100644
index 0000000..c50e3fb
--- /dev/null
+++ b/core/java/android/hardware/display/IDisplayManagerCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+/** @hide */
+interface IDisplayManagerCallback {
+ oneway void onDisplayEvent(int displayId, int event);
+}
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index 99bd647..4b60f07 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -96,6 +96,11 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
}
@Override
+ public void captivePortalCheckComplete() {
+ // not implemented
+ }
+
+ @Override
public boolean setRadio(boolean turnOn) {
// Base tracker doesn't handle radios
return true;
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
new file mode 100644
index 0000000..aa392d0
--- /dev/null
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.android.internal.R;
+
+/**
+ * This class allows captive portal detection
+ * @hide
+ */
+public class CaptivePortalTracker {
+ private static final boolean DBG = true;
+ private static final String TAG = "CaptivePortalTracker";
+
+ private static final String DEFAULT_SERVER = "clients3.google.com";
+ private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+
+ private static final int SOCKET_TIMEOUT_MS = 10000;
+
+ private String mServer;
+ private String mUrl;
+ private boolean mNotificationShown = false;
+ private boolean mIsCaptivePortalCheckEnabled = false;
+ private InternalHandler mHandler;
+ private IConnectivityManager mConnService;
+ private Context mContext;
+ private NetworkInfo mNetworkInfo;
+ private boolean mIsCaptivePortal = false;
+
+ private static final int DETECT_PORTAL = 0;
+ private static final int HANDLE_CONNECT = 1;
+
+ /**
+ * Activity Action: Switch to the captive portal network
+ * <p>Input: Nothing.
+ * <p>Output: Nothing.
+ */
+ public static final String ACTION_SWITCH_TO_CAPTIVE_PORTAL
+ = "android.net.SWITCH_TO_CAPTIVE_PORTAL";
+
+ private CaptivePortalTracker(Context context, NetworkInfo info, IConnectivityManager cs) {
+ mContext = context;
+ mNetworkInfo = info;
+ mConnService = cs;
+
+ HandlerThread handlerThread = new HandlerThread("CaptivePortalThread");
+ handlerThread.start();
+ mHandler = new InternalHandler(handlerThread.getLooper());
+ mHandler.obtainMessage(DETECT_PORTAL).sendToTarget();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_SWITCH_TO_CAPTIVE_PORTAL);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+
+ mContext.registerReceiver(mReceiver, filter);
+
+ mServer = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.CAPTIVE_PORTAL_SERVER);
+ if (mServer == null) mServer = DEFAULT_SERVER;
+
+ mIsCaptivePortalCheckEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ACTION_SWITCH_TO_CAPTIVE_PORTAL)) {
+ notifyPortalCheckComplete();
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ NetworkInfo info = intent.getParcelableExtra(
+ ConnectivityManager.EXTRA_NETWORK_INFO);
+ mHandler.obtainMessage(HANDLE_CONNECT, info).sendToTarget();
+ }
+ }
+ };
+
+ public static CaptivePortalTracker detect(Context context, NetworkInfo info,
+ IConnectivityManager cs) {
+ CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, info, cs);
+ return captivePortal;
+ }
+
+ private class InternalHandler extends Handler {
+ public InternalHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case DETECT_PORTAL:
+ InetAddress server = lookupHost(mServer);
+ if (server != null) {
+ requestRouteToHost(server);
+ if (isCaptivePortal(server)) {
+ if (DBG) log("Captive portal " + mNetworkInfo);
+ setNotificationVisible(true);
+ mIsCaptivePortal = true;
+ break;
+ }
+ }
+ notifyPortalCheckComplete();
+ quit();
+ break;
+ case HANDLE_CONNECT:
+ NetworkInfo info = (NetworkInfo) msg.obj;
+ if (info.getType() != mNetworkInfo.getType()) break;
+
+ if (info.getState() == NetworkInfo.State.CONNECTED ||
+ info.getState() == NetworkInfo.State.DISCONNECTED) {
+ setNotificationVisible(false);
+ }
+
+ /* Connected to a captive portal */
+ if (info.getState() == NetworkInfo.State.CONNECTED &&
+ mIsCaptivePortal) {
+ launchBrowser();
+ quit();
+ }
+ break;
+ default:
+ loge("Unhandled message " + msg);
+ break;
+ }
+ }
+
+ private void quit() {
+ mIsCaptivePortal = false;
+ getLooper().quit();
+ mContext.unregisterReceiver(mReceiver);
+ }
+ }
+
+ private void launchBrowser() {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl));
+ intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+
+ private void notifyPortalCheckComplete() {
+ try {
+ mConnService.captivePortalCheckComplete(mNetworkInfo);
+ } catch(RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void requestRouteToHost(InetAddress server) {
+ try {
+ mConnService.requestRouteToHostAddress(mNetworkInfo.getType(),
+ server.getAddress());
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Do a URL fetch on a known server to see if we get the data we expect
+ */
+ private boolean isCaptivePortal(InetAddress server) {
+ HttpURLConnection urlConnection = null;
+ if (!mIsCaptivePortalCheckEnabled) return false;
+
+ mUrl = "http://" + server.getHostAddress() + "/generate_204";
+ try {
+ URL url = new URL(mUrl);
+ urlConnection = (HttpURLConnection) url.openConnection();
+ urlConnection.setInstanceFollowRedirects(false);
+ urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
+ urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+ urlConnection.setUseCaches(false);
+ urlConnection.getInputStream();
+ // we got a valid response, but not from the real google
+ return urlConnection.getResponseCode() != 204;
+ } catch (IOException e) {
+ if (DBG) log("Probably not a portal: exception " + e);
+ return false;
+ } finally {
+ if (urlConnection != null) {
+ urlConnection.disconnect();
+ }
+ }
+ }
+
+ private InetAddress lookupHost(String hostname) {
+ InetAddress inetAddress[];
+ try {
+ inetAddress = InetAddress.getAllByName(hostname);
+ } catch (UnknownHostException e) {
+ return null;
+ }
+
+ for (InetAddress a : inetAddress) {
+ if (a instanceof Inet4Address) return a;
+ }
+ return null;
+ }
+
+ private void setNotificationVisible(boolean visible) {
+ // if it should be hidden and it is already hidden, then noop
+ if (!visible && !mNotificationShown) {
+ return;
+ }
+
+ Resources r = Resources.getSystem();
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if (visible) {
+ CharSequence title = r.getString(R.string.wifi_available_sign_in, 0);
+ CharSequence details = r.getString(R.string.wifi_available_sign_in_detailed,
+ mNetworkInfo.getExtraInfo());
+
+ Notification notification = new Notification();
+ notification.when = 0;
+ notification.icon = com.android.internal.R.drawable.stat_notify_wifi_in_range;
+ notification.flags = Notification.FLAG_AUTO_CANCEL;
+ notification.contentIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(CaptivePortalTracker.ACTION_SWITCH_TO_CAPTIVE_PORTAL), 0);
+
+ notification.tickerText = title;
+ notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
+
+ notificationManager.notify(NOTIFICATION_ID, 1, notification);
+ } else {
+ notificationManager.cancel(NOTIFICATION_ID, 1);
+ }
+ mNotificationShown = visible;
+ }
+
+ private static void log(String s) {
+ Log.d(TAG, s);
+ }
+
+ private static void loge(String s) {
+ Log.e(TAG, s);
+ }
+
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 60bf4d6..a570473 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -921,4 +921,15 @@ public class ConnectivityManager {
return false;
}
}
+
+ /**
+ * {@hide}
+ */
+ public void captivePortalCheckComplete(NetworkInfo info) {
+ try {
+ mService.captivePortalCheckComplete(info);
+ } catch (RemoteException e) {
+ }
+ }
+
}
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index cc3e34f..874e80a 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -92,10 +92,12 @@ public class DhcpStateMachine extends StateMachine {
/* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
* success/failure */
public static final int CMD_POST_DHCP_ACTION = BASE + 5;
+ /* Notification from DHCP state machine before quitting */
+ public static final int CMD_ON_QUIT = BASE + 6;
/* Command from controller to indicate DHCP discovery/renewal can continue
* after pre DHCP action is complete */
- public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 6;
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 7;
/* Message.arg1 arguments to CMD_POST_DHCP notification */
public static final int DHCP_SUCCESS = 1;
@@ -172,6 +174,10 @@ public class DhcpStateMachine extends StateMachine {
quit();
}
+ protected void onQuitting() {
+ mController.sendMessage(CMD_ON_QUIT);
+ }
+
class DefaultState extends State {
@Override
public void exit() {
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index ccd96ff..39440c2 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -119,6 +119,10 @@ public class DummyDataStateTracker implements NetworkStateTracker {
return true;
}
+ public void captivePortalCheckComplete() {
+ // not implemented
+ }
+
/**
* Record the detailed state of a network, and if it is a
* change from the previous state, send a notification to
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index c690430..c52aa9e 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -274,6 +274,11 @@ public class EthernetDataTracker implements NetworkStateTracker {
return mLinkUp;
}
+ @Override
+ public void captivePortalCheckComplete() {
+ // not implemented
+ }
+
/**
* Turn the wireless radio off for a network.
* @param turnOn {@code true} to turn the radio on, {@code false}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 3614045..056fa03 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -124,4 +124,6 @@ interface IConnectivityManager
LegacyVpnInfo getLegacyVpnInfo();
boolean updateLockdownVpn();
+
+ void captivePortalCheckComplete(in NetworkInfo info);
}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index d59fa6a..b35d61c 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -381,6 +381,11 @@ public class MobileDataStateTracker implements NetworkStateTracker {
return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED);
}
+ @Override
+ public void captivePortalCheckComplete() {
+ // not implemented
+ }
+
/**
* Record the detailed state of a network, and if it is a
* change from the previous state, send a notification to
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 0bc6b58..0b23cb7 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -79,7 +79,9 @@ public class NetworkInfo implements Parcelable {
/** Access to this network is blocked. */
BLOCKED,
/** Link has poor connectivity. */
- VERIFYING_POOR_LINK
+ VERIFYING_POOR_LINK,
+ /** Checking if network is a captive portal */
+ CAPTIVE_PORTAL_CHECK,
}
/**
@@ -97,6 +99,7 @@ public class NetworkInfo implements Parcelable {
stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
+ stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index eae89f1..0a0c1e0 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -123,6 +123,11 @@ public interface NetworkStateTracker {
public boolean reconnect();
/**
+ * Ready to switch on to the network after captive portal check
+ */
+ public void captivePortalCheckComplete();
+
+ /**
* Turn the wireless radio off for a network.
* @param turnOn {@code true} to turn the radio on, {@code false}
*/
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index fb5263d..65d3f2b 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -329,7 +329,7 @@ public class VpnService extends Service {
throw new IllegalArgumentException("Bad address");
}
- mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
+ mAddresses.append(' ' + address.getHostAddress() + '/' + prefixLength);
return this;
}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 4e2b5c0..0f9be9c 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -412,6 +412,50 @@ public class Handler {
}
/**
+ * Runs the specified task synchronously.
+ *
+ * If the current thread is the same as the handler thread, then the runnable
+ * runs immediately without being enqueued. Otherwise, posts the runnable
+ * to the handler and waits for it to complete before returning.
+ *
+ * This method is dangerous! Improper use can result in deadlocks.
+ * Never call this method while any locks are held or use it in a
+ * possibly re-entrant manner.
+ *
+ * This method is occasionally useful in situations where a background thread
+ * must synchronously await completion of a task that must run on the
+ * handler's thread. However, this problem is often a symptom of bad design.
+ * Consider improving the design (if possible) before resorting to this method.
+ *
+ * One example of where you might want to use this method is when you just
+ * set up a Handler thread and need to perform some initialization steps on
+ * it before continuing execution.
+ *
+ * @param r The Runnable that will be executed synchronously.
+ *
+ * @return Returns true if the Runnable was successfully executed.
+ * Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ *
+ * @hide This method is prone to abuse and should probably not be in the API.
+ * If we ever do make it part of the API, we might want to rename it to something
+ * less funny like runUnsafe().
+ */
+ public final boolean runWithScissors(final Runnable r) {
+ if (r == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
+
+ if (Looper.myLooper() == mLooper) {
+ r.run();
+ return true;
+ }
+
+ BlockingRunnable br = new BlockingRunnable(r);
+ return br.postAndWait(this);
+ }
+
+ /**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(Runnable r)
@@ -678,4 +722,41 @@ public class Handler {
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
+
+ private static final class BlockingRunnable implements Runnable {
+ private final Runnable mTask;
+ private boolean mDone;
+
+ public BlockingRunnable(Runnable task) {
+ mTask = task;
+ }
+
+ @Override
+ public void run() {
+ try {
+ mTask.run();
+ } finally {
+ synchronized (this) {
+ mDone = true;
+ notifyAll();
+ }
+ }
+ }
+
+ public boolean postAndWait(Handler handler) {
+ if (!handler.post(this)) {
+ return false;
+ }
+
+ synchronized (this) {
+ while (!mDone) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+ return true;
+ }
+ }
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 851b8df..d5fca4d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -584,6 +584,8 @@ public class Process {
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
argsForZygote.add("--mount-external-multiuser");
+ } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ argsForZygote.add("--mount-external-multiuser-all");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1f6f0dd..b4841b1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3279,13 +3279,6 @@ public final class Settings {
/**
- * ms delay before rechecking a connect SSID for walled garden with a http download.
- * @hide
- */
- public static final String WIFI_WATCHDOG_WALLED_GARDEN_INTERVAL_MS =
- "wifi_watchdog_walled_garden_interval_ms";
-
- /**
* Number of ARP pings per check.
* @hide
*/
@@ -3322,23 +3315,6 @@ public final class Settings {
"wifi_suspend_optimizations_enabled";
/**
- * Setting to turn off walled garden test on Wi-Fi. Feature is enabled by default and
- * the setting needs to be set to 0 to disable it.
- * @hide
- */
- public static final String WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED =
- "wifi_watchdog_walled_garden_test_enabled";
-
- /**
- * The URL used for walled garden check upon a new conection. WifiWatchdogService
- * fetches the URL and checks to see if {@link #WIFI_WATCHDOG_WALLED_GARDEN_PATTERN}
- * is not part of the title string to notify the user on the presence of a walled garden.
- * @hide
- */
- public static final String WIFI_WATCHDOG_WALLED_GARDEN_URL =
- "wifi_watchdog_walled_garden_url";
-
- /**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
* A value of N means that we will make N+1 connection attempts in all.
@@ -3362,6 +3338,21 @@ public final class Settings {
public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
/**
+ * Setting to turn off captive portal detection. Feature is enabled by default and
+ * the setting needs to be set to 0 to disable it.
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_DETECTION_ENABLED =
+ "captive_portal_detection_enabled";
+
+ /**
+ * The server used for captive portal detection upon a new conection. A 204 response
+ * code from the server is used for validation.
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server";
+
+ /**
* Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile
* data connectivity to be established after a disconnect from Wi-Fi.
*/
@@ -4360,6 +4351,25 @@ public final class Settings {
public static final String SMS_SHORT_CODES_PREFIX = "sms_short_codes_";
/**
+ * Overlay display devices setting.
+ * The associated value is a specially formatted string that describes the
+ * size and density of simulated secondary display devices.
+ * <p>
+ * Format: {width}x{height}/{dpi};...
+ * </p><p>
+ * Example:
+ * <ul>
+ * <li><code>1280x720/213</code>: make one overlay that is 1280x720 at 213dpi.</li>
+ * <li><code>1920x1080/320;1280x720/213</code>: make two overlays, the first
+ * at 1080p and the second at 720p.</li>
+ * <li>If the value is empty, then no overlay display devices are created.</li>
+ * </ul></p>
+ *
+ * @hide
+ */
+ public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index 47e2129..186cb49 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -69,7 +69,8 @@ class BlockingAudioTrack {
// Need to be seen by stop() which can be called from another thread. mAudioTrack will be
// set to null only after waitAndRelease().
- private volatile AudioTrack mAudioTrack;
+ private Object mAudioTrackLock = new Object();
+ private AudioTrack mAudioTrack;
private volatile boolean mStopped;
BlockingAudioTrack(int streamType, int sampleRate,
@@ -93,7 +94,9 @@ class BlockingAudioTrack {
public boolean init() {
AudioTrack track = createStreamingAudioTrack();
- mAudioTrack = track;
+ synchronized (mAudioTrackLock) {
+ mAudioTrack = track;
+ }
if (track == null) {
return false;
@@ -103,24 +106,34 @@ class BlockingAudioTrack {
}
public void stop() {
- AudioTrack track = mAudioTrack;
- if (track != null) {
- track.stop();
+ synchronized (mAudioTrackLock) {
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ }
+ mStopped = true;
}
- mStopped = true;
}
public int write(byte[] data) {
- if (mAudioTrack == null || mStopped) {
+ AudioTrack track = null;
+ synchronized (mAudioTrackLock) {
+ track = mAudioTrack;
+ }
+
+ if (track == null || mStopped) {
return -1;
}
- final int bytesWritten = writeToAudioTrack(mAudioTrack, data);
+ final int bytesWritten = writeToAudioTrack(track, data);
+
mBytesWritten += bytesWritten;
return bytesWritten;
}
public void waitAndRelease() {
- AudioTrack track = mAudioTrack;
+ AudioTrack track = null;
+ synchronized (mAudioTrackLock) {
+ track = mAudioTrack;
+ }
if (track == null) {
if (DBG) Log.d(TAG, "Audio track null [duplicate call to waitAndRelease ?]");
return;
@@ -152,8 +165,10 @@ class BlockingAudioTrack {
// all data from the audioTrack has been sent to the mixer, so
// it's safe to release at this point.
if (DBG) Log.d(TAG, "Releasing audio track [" + track.hashCode() + "]");
+ synchronized(mAudioTrackLock) {
+ mAudioTrack = null;
+ }
track.release();
- mAudioTrack = null;
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 392d1f2..6848606 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -17,6 +17,7 @@
package android.view;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -166,8 +167,7 @@ public final class Choreographer {
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
- Display d = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
- mFrameIntervalNanos = (long)(1000000000 / d.getRefreshRate());
+ mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
@@ -175,6 +175,12 @@ public final class Choreographer {
}
}
+ private static float getRefreshRate() {
+ DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
+ Display.DEFAULT_DISPLAY);
+ return di.refreshRate;
+ }
+
/**
* Gets the choreographer for the calling thread. Must be called from
* a thread that already has a {@link android.os.Looper} associated with it.
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 6f8ca13..ec635a2 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -19,7 +19,7 @@ package android.view;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -49,10 +49,14 @@ import android.util.Log;
*/
public final class Display {
private static final String TAG = "Display";
+ private static final boolean DEBUG = false;
+ private final DisplayManagerGlobal mGlobal;
private final int mDisplayId;
private final CompatibilityInfoHolder mCompatibilityInfo;
- private final DisplayInfo mDisplayInfo = new DisplayInfo();
+
+ private DisplayInfo mDisplayInfo; // never null
+ private boolean mIsValid;
// Temporary display metrics structure used for compatibility mode.
private final DisplayMetrics mTempMetrics = new DisplayMetrics();
@@ -80,9 +84,14 @@ public final class Display {
*
* @hide
*/
- public Display(int displayId, CompatibilityInfoHolder compatibilityInfo) {
+ public Display(DisplayManagerGlobal global,
+ int displayId, DisplayInfo displayInfo /*not null*/,
+ CompatibilityInfoHolder compatibilityInfo) {
+ mGlobal = global;
mDisplayId = displayId;
+ mDisplayInfo = displayInfo;
mCompatibilityInfo = compatibilityInfo;
+ mIsValid = true;
}
/**
@@ -97,15 +106,37 @@ public final class Display {
}
/**
+ * Returns true if this display is still valid, false if the display has been removed.
+ *
+ * If the display is invalid, then the methods of this class will
+ * continue to report the most recently observed display information.
+ * However, it is unwise (and rather fruitless) to continue using a
+ * {@link Display} object after the display's demise.
+ *
+ * It's possible for a display that was previously invalid to become
+ * valid again if a display with the same id is reconnected.
+ *
+ * @return True if the display is still valid.
+ */
+ public boolean isValid() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mIsValid;
+ }
+ }
+
+ /**
* Gets a full copy of the display information.
*
* @param outDisplayInfo The object to receive the copy of the display information.
+ * @return True if the display is still valid.
* @hide
*/
- public void getDisplayInfo(DisplayInfo outDisplayInfo) {
+ public boolean getDisplayInfo(DisplayInfo outDisplayInfo) {
synchronized (this) {
updateDisplayInfoLocked();
outDisplayInfo.copyFrom(mDisplayInfo);
+ return mIsValid;
}
}
@@ -366,9 +397,25 @@ public final class Display {
}
private void updateDisplayInfoLocked() {
- // TODO: only refresh the display information when needed
- if (!DisplayManager.getInstance().getDisplayInfo(mDisplayId, mDisplayInfo)) {
- Log.e(TAG, "Could not get information about logical display " + mDisplayId);
+ // Note: The display manager caches display info objects on our behalf.
+ DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
+ if (newInfo == null) {
+ // Preserve the old mDisplayInfo after the display is removed.
+ if (mIsValid) {
+ mIsValid = false;
+ if (DEBUG) {
+ Log.d(TAG, "Logical display " + mDisplayId + " was removed.");
+ }
+ }
+ } else {
+ // Use the new display info. (It might be the same object if nothing changed.)
+ mDisplayInfo = newInfo;
+ if (!mIsValid) {
+ mIsValid = true;
+ if (DEBUG) {
+ Log.d(TAG, "Logical display " + mDisplayId + " was recreated.");
+ }
+ }
}
}
@@ -390,7 +437,7 @@ public final class Display {
updateDisplayInfoLocked();
mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
return "Display id " + mDisplayId + ": " + mDisplayInfo
- + ", " + mTempMetrics;
+ + ", " + mTempMetrics + ", isValid=" + mIsValid;
}
}
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 6c2e540..0b138c2 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -66,7 +66,7 @@ public abstract class DisplayEventReceiver {
@Override
protected void finalize() throws Throwable {
try {
- dispose();
+ dispose(true);
} finally {
super.finalize();
}
@@ -76,9 +76,17 @@ public abstract class DisplayEventReceiver {
* Disposes the receiver.
*/
public void dispose() {
+ dispose(false);
+ }
+
+ private void dispose(boolean finalized) {
if (mCloseGuard != null) {
+ if (finalized) {
+ mCloseGuard.warnIfOpen();
+ }
mCloseGuard.close();
}
+
if (mReceiverPtr != 0) {
nativeDispose(mReceiverPtr);
mReceiverPtr = 0;
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index e38f245..593e8c4 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -138,6 +138,10 @@ public final class DisplayInfo implements Parcelable {
public DisplayInfo() {
}
+ public DisplayInfo(DisplayInfo other) {
+ copyFrom(other);
+ }
+
private DisplayInfo(Parcel source) {
readFromParcel(source);
}
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 0114a41..23337f0 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -226,17 +226,12 @@ public class GestureDetector {
*/
private boolean mIsDoubleTapping;
- private float mLastMotionY;
- private float mLastMotionX;
+ private float mLastFocusX;
+ private float mLastFocusY;
+ private float mDownFocusX;
+ private float mDownFocusY;
private boolean mIsLongpressEnabled;
-
- /**
- * True if we are at a target API level of >= Froyo or the developer can
- * explicitly set it. If true, input events with > 1 pointer will be ignored
- * so we can work side by side with multitouch gesture detectors.
- */
- private boolean mIgnoreMultitouch;
/**
* Determines speed during touch scrolling
@@ -349,8 +344,16 @@ public class GestureDetector {
* @throws NullPointerException if {@code listener} is null.
*/
public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
- this(context, listener, handler, context != null &&
- context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO);
+ if (handler != null) {
+ mHandler = new GestureHandler(handler);
+ } else {
+ mHandler = new GestureHandler();
+ }
+ mListener = listener;
+ if (listener instanceof OnDoubleTapListener) {
+ setOnDoubleTapListener((OnDoubleTapListener) listener);
+ }
+ init(context);
}
/**
@@ -362,31 +365,19 @@ public class GestureDetector {
* @param listener the listener invoked for all the callbacks, this must
* not be null.
* @param handler the handler to use
- * @param ignoreMultitouch whether events involving more than one pointer should
- * be ignored.
*
* @throws NullPointerException if {@code listener} is null.
*/
public GestureDetector(Context context, OnGestureListener listener, Handler handler,
- boolean ignoreMultitouch) {
- if (handler != null) {
- mHandler = new GestureHandler(handler);
- } else {
- mHandler = new GestureHandler();
- }
- mListener = listener;
- if (listener instanceof OnDoubleTapListener) {
- setOnDoubleTapListener((OnDoubleTapListener) listener);
- }
- init(context, ignoreMultitouch);
+ boolean unused) {
+ this(context, listener, handler);
}
- private void init(Context context, boolean ignoreMultitouch) {
+ private void init(Context context) {
if (mListener == null) {
throw new NullPointerException("OnGestureListener must not be null");
}
mIsLongpressEnabled = true;
- mIgnoreMultitouch = ignoreMultitouch;
// Fallback to support pre-donuts releases
int touchSlop, doubleTapSlop, doubleTapTouchSlop;
@@ -456,34 +447,40 @@ public class GestureDetector {
}
final int action = ev.getAction();
- final float y = ev.getY();
- final float x = ev.getX();
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
+ final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
+ final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
+
+ // Determine focal point
+ float sumX = 0, sumY = 0;
+ final int count = ev.getPointerCount();
+ for (int i = 0; i < count; i++) {
+ if (skipIndex == i) continue;
+ sumX += ev.getX(i);
+ sumY += ev.getY(i);
+ }
+ final int div = pointerUp ? count - 1 : count;
+ final float focusX = sumX / div;
+ final float focusY = sumY / div;
+
boolean handled = false;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
- if (mIgnoreMultitouch) {
- // Multitouch event - abort.
- cancel();
- }
+ mDownFocusX = mLastFocusX = focusX;
+ mDownFocusY = mLastFocusY = focusY;
+ // Cancel long press and taps
+ cancelTaps();
break;
case MotionEvent.ACTION_POINTER_UP:
- // Ending a multitouch gesture and going back to 1 finger
- if (mIgnoreMultitouch && ev.getPointerCount() == 2) {
- int index = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
- mLastMotionX = ev.getX(index);
- mLastMotionY = ev.getY(index);
- mVelocityTracker.recycle();
- mVelocityTracker = VelocityTracker.obtain();
- }
+ mDownFocusX = mLastFocusX = focusX;
+ mDownFocusY = mLastFocusY = focusY;
break;
case MotionEvent.ACTION_DOWN:
@@ -504,8 +501,8 @@ public class GestureDetector {
}
}
- mLastMotionX = x;
- mLastMotionY = y;
+ mDownFocusX = mLastFocusX = focusX;
+ mDownFocusY = mLastFocusY = focusY;
if (mCurrentDownEvent != null) {
mCurrentDownEvent.recycle();
}
@@ -525,22 +522,22 @@ public class GestureDetector {
break;
case MotionEvent.ACTION_MOVE:
- if (mInLongPress || (mIgnoreMultitouch && ev.getPointerCount() > 1)) {
+ if (mInLongPress) {
break;
}
- final float scrollX = mLastMotionX - x;
- final float scrollY = mLastMotionY - y;
+ final float scrollX = mLastFocusX - focusX;
+ final float scrollY = mLastFocusY - focusY;
if (mIsDoubleTapping) {
// Give the move events of the double-tap
handled |= mDoubleTapListener.onDoubleTapEvent(ev);
} else if (mAlwaysInTapRegion) {
- final int deltaX = (int) (x - mCurrentDownEvent.getX());
- final int deltaY = (int) (y - mCurrentDownEvent.getY());
+ final int deltaX = (int) (focusX - mDownFocusX);
+ final int deltaY = (int) (focusY - mDownFocusY);
int distance = (deltaX * deltaX) + (deltaY * deltaY);
if (distance > mTouchSlopSquare) {
handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
- mLastMotionX = x;
- mLastMotionY = y;
+ mLastFocusX = focusX;
+ mLastFocusY = focusY;
mAlwaysInTapRegion = false;
mHandler.removeMessages(TAP);
mHandler.removeMessages(SHOW_PRESS);
@@ -551,8 +548,8 @@ public class GestureDetector {
}
} else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
- mLastMotionX = x;
- mLastMotionY = y;
+ mLastFocusX = focusX;
+ mLastFocusY = focusY;
}
break;
@@ -571,9 +568,10 @@ public class GestureDetector {
// A fling must travel the minimum tap distance
final VelocityTracker velocityTracker = mVelocityTracker;
+ final int pointerId = ev.getPointerId(0);
velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
- final float velocityY = velocityTracker.getYVelocity();
- final float velocityX = velocityTracker.getXVelocity();
+ final float velocityY = velocityTracker.getYVelocity(pointerId);
+ final float velocityX = velocityTracker.getXVelocity(pointerId);
if ((Math.abs(velocityY) > mMinimumFlingVelocity)
|| (Math.abs(velocityX) > mMinimumFlingVelocity)){
@@ -622,6 +620,18 @@ public class GestureDetector {
}
}
+ private void cancelTaps() {
+ mHandler.removeMessages(SHOW_PRESS);
+ mHandler.removeMessages(LONG_PRESS);
+ mHandler.removeMessages(TAP);
+ mIsDoubleTapping = false;
+ mAlwaysInTapRegion = false;
+ mAlwaysInBiggerTapRegion = false;
+ if (mInLongPress) {
+ mInLongPress = false;
+ }
+ }
+
private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
MotionEvent secondDown) {
if (!mAlwaysInBiggerTapRegion) {
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 9c56782..117c101 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -73,7 +73,7 @@ public abstract class InputEventReceiver {
@Override
protected void finalize() throws Throwable {
try {
- dispose();
+ dispose(true);
} finally {
super.finalize();
}
@@ -83,9 +83,17 @@ public abstract class InputEventReceiver {
* Disposes the receiver.
*/
public void dispose() {
+ dispose(false);
+ }
+
+ private void dispose(boolean finalized) {
if (mCloseGuard != null) {
+ if (finalized) {
+ mCloseGuard.warnIfOpen();
+ }
mCloseGuard.close();
}
+
if (mReceiverPtr != 0) {
nativeDispose(mReceiverPtr);
mReceiverPtr = 0;
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 73f94bc..dc36088 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -17,14 +17,13 @@
package android.view;
import android.content.Context;
-import android.util.DisplayMetrics;
import android.util.FloatMath;
-import android.util.Log;
/**
- * Detects transformation gestures involving more than one pointer ("multitouch")
- * using the supplied {@link MotionEvent}s. The {@link OnScaleGestureListener}
- * callback will notify users when a particular gesture event has occurred.
+ * Detects scaling transformation gestures using the supplied {@link MotionEvent}s.
+ * The {@link OnScaleGestureListener} callback will notify users when a particular
+ * gesture event has occurred.
+ *
* This class should only be used with {@link MotionEvent}s reported via touch.
*
* To use this class:
@@ -121,43 +120,21 @@ public class ScaleGestureDetector {
}
}
- /**
- * This value is the threshold ratio between our previous combined pressure
- * and the current combined pressure. We will only fire an onScale event if
- * the computed ratio between the current and previous event pressures is
- * greater than this value. When pressure decreases rapidly between events
- * the position values can often be imprecise, as it usually indicates
- * that the user is in the process of lifting a pointer off of the device.
- * Its value was tuned experimentally.
- */
- private static final float PRESSURE_THRESHOLD = 0.67f;
-
private final Context mContext;
private final OnScaleGestureListener mListener;
- private boolean mGestureInProgress;
-
- private MotionEvent mPrevEvent;
- private MotionEvent mCurrEvent;
private float mFocusX;
private float mFocusY;
- private float mPrevFingerDiffX;
- private float mPrevFingerDiffY;
- private float mCurrFingerDiffX;
- private float mCurrFingerDiffY;
- private float mCurrLen;
- private float mPrevLen;
- private float mScaleFactor;
- private float mCurrPressure;
- private float mPrevPressure;
- private long mTimeDelta;
-
- private boolean mInvalidGesture;
-
- // Pointer IDs currently responsible for the two fingers controlling the gesture
- private int mActiveId0;
- private int mActiveId1;
- private boolean mActive0MostRecent;
+
+ private float mCurrSpan;
+ private float mPrevSpan;
+ private float mCurrSpanX;
+ private float mCurrSpanY;
+ private float mPrevSpanX;
+ private float mPrevSpanY;
+ private long mCurrTime;
+ private long mPrevTime;
+ private boolean mInProgress;
/**
* Consistency verifier for debugging purposes.
@@ -171,6 +148,18 @@ public class ScaleGestureDetector {
mListener = listener;
}
+ /**
+ * Accepts MotionEvents and dispatches events to a {@link OnScaleGestureListener}
+ * when appropriate.
+ *
+ * <p>Applications should pass a complete and consistent event stream to this method.
+ * A complete and consistent event stream involves all MotionEvents from the initial
+ * ACTION_DOWN to the final ACTION_UP or ACTION_CANCEL.</p>
+ *
+ * @param event The event to process
+ * @return true if the event was processed and the detector wants to receive the
+ * rest of the MotionEvents in this event stream.
+ */
public boolean onTouchEvent(MotionEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
@@ -178,265 +167,110 @@ public class ScaleGestureDetector {
final int action = event.getActionMasked();
- if (action == MotionEvent.ACTION_DOWN) {
- reset(); // Start fresh
- }
-
- boolean handled = true;
- if (mInvalidGesture) {
- handled = false;
- } else if (!mGestureInProgress) {
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- mActiveId0 = event.getPointerId(0);
- mActive0MostRecent = true;
- }
- break;
-
- case MotionEvent.ACTION_UP:
- reset();
- break;
-
- case MotionEvent.ACTION_POINTER_DOWN: {
- // We have a new multi-finger gesture
- if (mPrevEvent != null) mPrevEvent.recycle();
- mPrevEvent = MotionEvent.obtain(event);
- mTimeDelta = 0;
-
- int index1 = event.getActionIndex();
- int index0 = event.findPointerIndex(mActiveId0);
- mActiveId1 = event.getPointerId(index1);
- if (index0 < 0 || index0 == index1) {
- // Probably someone sending us a broken event stream.
- index0 = findNewActiveIndex(event, mActiveId1, -1);
- mActiveId0 = event.getPointerId(index0);
- }
- mActive0MostRecent = false;
-
- setContext(event);
-
- mGestureInProgress = mListener.onScaleBegin(this);
- break;
- }
+ final boolean streamComplete = action == MotionEvent.ACTION_UP ||
+ action == MotionEvent.ACTION_CANCEL;
+ if (action == MotionEvent.ACTION_DOWN || streamComplete) {
+ // Reset any scale in progress with the listener.
+ // If it's an ACTION_DOWN we're beginning a new event stream.
+ // This means the app probably didn't give us all the events. Shame on it.
+ if (mInProgress) {
+ mListener.onScaleEnd(this);
+ mInProgress = false;
}
- } else {
- // Transform gesture in progress - attempt to handle it
- switch (action) {
- case MotionEvent.ACTION_POINTER_DOWN: {
- // End the old gesture and begin a new one with the most recent two fingers.
- mListener.onScaleEnd(this);
- final int oldActive0 = mActiveId0;
- final int oldActive1 = mActiveId1;
- reset();
-
- mPrevEvent = MotionEvent.obtain(event);
- mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1;
- mActiveId1 = event.getPointerId(event.getActionIndex());
- mActive0MostRecent = false;
-
- int index0 = event.findPointerIndex(mActiveId0);
- if (index0 < 0 || mActiveId0 == mActiveId1) {
- // Probably someone sending us a broken event stream.
- Log.e(TAG, "Got " + MotionEvent.actionToString(action) +
- " with bad state while a gesture was in progress. " +
- "Did you forget to pass an event to " +
- "ScaleGestureDetector#onTouchEvent?");
- index0 = findNewActiveIndex(event, mActiveId1, -1);
- mActiveId0 = event.getPointerId(index0);
- }
-
- setContext(event);
-
- mGestureInProgress = mListener.onScaleBegin(this);
- }
- break;
-
- case MotionEvent.ACTION_POINTER_UP: {
- final int pointerCount = event.getPointerCount();
- final int actionIndex = event.getActionIndex();
- final int actionId = event.getPointerId(actionIndex);
-
- boolean gestureEnded = false;
- if (pointerCount > 2) {
- if (actionId == mActiveId0) {
- final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
- if (newIndex >= 0) {
- mListener.onScaleEnd(this);
- mActiveId0 = event.getPointerId(newIndex);
- mActive0MostRecent = true;
- mPrevEvent = MotionEvent.obtain(event);
- setContext(event);
- mGestureInProgress = mListener.onScaleBegin(this);
- } else {
- gestureEnded = true;
- }
- } else if (actionId == mActiveId1) {
- final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
- if (newIndex >= 0) {
- mListener.onScaleEnd(this);
- mActiveId1 = event.getPointerId(newIndex);
- mActive0MostRecent = false;
- mPrevEvent = MotionEvent.obtain(event);
- setContext(event);
- mGestureInProgress = mListener.onScaleBegin(this);
- } else {
- gestureEnded = true;
- }
- }
- mPrevEvent.recycle();
- mPrevEvent = MotionEvent.obtain(event);
- setContext(event);
- } else {
- gestureEnded = true;
- }
-
- if (gestureEnded) {
- // Gesture ended
- setContext(event);
-
- // Set focus point to the remaining finger
- final int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0;
- final int index = event.findPointerIndex(activeId);
- mFocusX = event.getX(index);
- mFocusY = event.getY(index);
-
- mListener.onScaleEnd(this);
- reset();
- mActiveId0 = activeId;
- mActive0MostRecent = true;
- }
- }
- break;
-
- case MotionEvent.ACTION_CANCEL:
- mListener.onScaleEnd(this);
- reset();
- break;
-
- case MotionEvent.ACTION_UP:
- reset();
- break;
-
- case MotionEvent.ACTION_MOVE: {
- setContext(event);
-
- // Only accept the event if our relative pressure is within
- // a certain limit - this can help filter shaky data as a
- // finger is lifted.
- if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
- final boolean updatePrevious = mListener.onScale(this);
-
- if (updatePrevious) {
- mPrevEvent.recycle();
- mPrevEvent = MotionEvent.obtain(event);
- }
- }
- }
- break;
+
+ if (streamComplete) {
+ return true;
}
}
- if (!handled && mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
+ final boolean configChanged =
+ action == MotionEvent.ACTION_POINTER_UP ||
+ action == MotionEvent.ACTION_POINTER_DOWN;
+ final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
+ final int skipIndex = pointerUp ? event.getActionIndex() : -1;
+
+ // Determine focal point
+ float sumX = 0, sumY = 0;
+ final int count = event.getPointerCount();
+ for (int i = 0; i < count; i++) {
+ if (skipIndex == i) continue;
+ sumX += event.getX(i);
+ sumY += event.getY(i);
}
- return handled;
- }
-
- private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int removedPointerIndex) {
- final int pointerCount = ev.getPointerCount();
-
- // It's ok if this isn't found and returns -1, it simply won't match.
- final int otherActiveIndex = ev.findPointerIndex(otherActiveId);
-
- // Pick a new id and update tracking state.
- for (int i = 0; i < pointerCount; i++) {
- if (i != removedPointerIndex && i != otherActiveIndex) {
- return i;
- }
+ final int div = pointerUp ? count - 1 : count;
+ final float focusX = sumX / div;
+ final float focusY = sumY / div;
+
+ // Determine average deviation from focal point
+ float devSumX = 0, devSumY = 0;
+ for (int i = 0; i < count; i++) {
+ if (skipIndex == i) continue;
+ devSumX += Math.abs(event.getX(i) - focusX);
+ devSumY += Math.abs(event.getY(i) - focusY);
}
- return -1;
- }
-
- private void setContext(MotionEvent curr) {
- if (mCurrEvent != null) {
- mCurrEvent.recycle();
+ final float devX = devSumX / div;
+ final float devY = devSumY / div;
+
+ // Span is the average distance between touch points through the focal point;
+ // i.e. the diameter of the circle with a radius of the average deviation from
+ // the focal point.
+ final float spanX = devX * 2;
+ final float spanY = devY * 2;
+ final float span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
+
+ // Dispatch begin/end events as needed.
+ // If the configuration changes, notify the app to reset its current state by beginning
+ // a fresh scale event stream.
+ if (mInProgress && (span == 0 || configChanged)) {
+ mListener.onScaleEnd(this);
+ mInProgress = false;
+ }
+ if (configChanged) {
+ mPrevSpanX = mCurrSpanX = spanX;
+ mPrevSpanY = mCurrSpanY = spanY;
+ mPrevSpan = mCurrSpan = span;
+ }
+ if (!mInProgress && span != 0) {
+ mFocusX = focusX;
+ mFocusY = focusY;
+ mInProgress = mListener.onScaleBegin(this);
}
- mCurrEvent = MotionEvent.obtain(curr);
-
- mCurrLen = -1;
- mPrevLen = -1;
- mScaleFactor = -1;
-
- final MotionEvent prev = mPrevEvent;
- final int prevIndex0 = prev.findPointerIndex(mActiveId0);
- final int prevIndex1 = prev.findPointerIndex(mActiveId1);
- final int currIndex0 = curr.findPointerIndex(mActiveId0);
- final int currIndex1 = curr.findPointerIndex(mActiveId1);
+ // Handle motion; focal point and span/scale factor are changing.
+ if (action == MotionEvent.ACTION_MOVE) {
+ mCurrSpanX = spanX;
+ mCurrSpanY = spanY;
+ mCurrSpan = span;
+ mFocusX = focusX;
+ mFocusY = focusY;
+
+ boolean updatePrev = true;
+ if (mInProgress) {
+ updatePrev = mListener.onScale(this);
+ }
- if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) {
- mInvalidGesture = true;
- Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable());
- if (mGestureInProgress) {
- mListener.onScaleEnd(this);
+ if (updatePrev) {
+ mPrevSpanX = mCurrSpanX;
+ mPrevSpanY = mCurrSpanY;
+ mPrevSpan = mCurrSpan;
}
- return;
}
- final float px0 = prev.getX(prevIndex0);
- final float py0 = prev.getY(prevIndex0);
- final float px1 = prev.getX(prevIndex1);
- final float py1 = prev.getY(prevIndex1);
- final float cx0 = curr.getX(currIndex0);
- final float cy0 = curr.getY(currIndex0);
- final float cx1 = curr.getX(currIndex1);
- final float cy1 = curr.getY(currIndex1);
-
- final float pvx = px1 - px0;
- final float pvy = py1 - py0;
- final float cvx = cx1 - cx0;
- final float cvy = cy1 - cy0;
- mPrevFingerDiffX = pvx;
- mPrevFingerDiffY = pvy;
- mCurrFingerDiffX = cvx;
- mCurrFingerDiffY = cvy;
-
- mFocusX = cx0 + cvx * 0.5f;
- mFocusY = cy0 + cvy * 0.5f;
- mTimeDelta = curr.getEventTime() - prev.getEventTime();
- mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1);
- mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1);
- }
-
- private void reset() {
- if (mPrevEvent != null) {
- mPrevEvent.recycle();
- mPrevEvent = null;
- }
- if (mCurrEvent != null) {
- mCurrEvent.recycle();
- mCurrEvent = null;
- }
- mGestureInProgress = false;
- mActiveId0 = -1;
- mActiveId1 = -1;
- mInvalidGesture = false;
+ return true;
}
/**
- * Returns {@code true} if a two-finger scale gesture is in progress.
- * @return {@code true} if a scale gesture is in progress, {@code false} otherwise.
+ * Returns {@code true} if a scale gesture is in progress.
*/
public boolean isInProgress() {
- return mGestureInProgress;
+ return mInProgress;
}
/**
* Get the X coordinate of the current gesture's focal point.
- * If a gesture is in progress, the focal point is directly between
- * the two pointers forming the gesture.
- * If a gesture is ending, the focal point is the location of the
- * remaining pointer on the screen.
+ * If a gesture is in progress, the focal point is between
+ * each of the pointers forming the gesture.
+ *
* If {@link #isInProgress()} would return false, the result of this
* function is undefined.
*
@@ -448,10 +282,9 @@ public class ScaleGestureDetector {
/**
* Get the Y coordinate of the current gesture's focal point.
- * If a gesture is in progress, the focal point is directly between
- * the two pointers forming the gesture.
- * If a gesture is ending, the focal point is the location of the
- * remaining pointer on the screen.
+ * If a gesture is in progress, the focal point is between
+ * each of the pointers forming the gesture.
+ *
* If {@link #isInProgress()} would return false, the result of this
* function is undefined.
*
@@ -462,73 +295,63 @@ public class ScaleGestureDetector {
}
/**
- * Return the current distance between the two pointers forming the
- * gesture in progress.
+ * Return the average distance between each of the pointers forming the
+ * gesture in progress through the focal point.
*
* @return Distance between pointers in pixels.
*/
public float getCurrentSpan() {
- if (mCurrLen == -1) {
- final float cvx = mCurrFingerDiffX;
- final float cvy = mCurrFingerDiffY;
- mCurrLen = FloatMath.sqrt(cvx*cvx + cvy*cvy);
- }
- return mCurrLen;
+ return mCurrSpan;
}
/**
- * Return the current x distance between the two pointers forming the
- * gesture in progress.
+ * Return the average X distance between each of the pointers forming the
+ * gesture in progress through the focal point.
*
* @return Distance between pointers in pixels.
*/
public float getCurrentSpanX() {
- return mCurrFingerDiffX;
+ return mCurrSpanX;
}
/**
- * Return the current y distance between the two pointers forming the
- * gesture in progress.
+ * Return the average Y distance between each of the pointers forming the
+ * gesture in progress through the focal point.
*
* @return Distance between pointers in pixels.
*/
public float getCurrentSpanY() {
- return mCurrFingerDiffY;
+ return mCurrSpanY;
}
/**
- * Return the previous distance between the two pointers forming the
- * gesture in progress.
+ * Return the previous average distance between each of the pointers forming the
+ * gesture in progress through the focal point.
*
* @return Previous distance between pointers in pixels.
*/
public float getPreviousSpan() {
- if (mPrevLen == -1) {
- final float pvx = mPrevFingerDiffX;
- final float pvy = mPrevFingerDiffY;
- mPrevLen = FloatMath.sqrt(pvx*pvx + pvy*pvy);
- }
- return mPrevLen;
+ return mPrevSpan;
}
/**
- * Return the previous x distance between the two pointers forming the
- * gesture in progress.
+ * Return the previous average X distance between each of the pointers forming the
+ * gesture in progress through the focal point.
*
* @return Previous distance between pointers in pixels.
*/
public float getPreviousSpanX() {
- return mPrevFingerDiffX;
+ return mPrevSpanX;
}
/**
- * Return the previous y distance between the two pointers forming the
- * gesture in progress.
+ * Return the previous average Y distance between each of the pointers forming the
+ * gesture in progress through the focal point.
*
* @return Previous distance between pointers in pixels.
*/
public float getPreviousSpanY() {
- return mPrevFingerDiffY;
+ return mPrevSpanY;
}
/**
@@ -539,10 +362,7 @@ public class ScaleGestureDetector {
* @return The current scaling factor.
*/
public float getScaleFactor() {
- if (mScaleFactor == -1) {
- mScaleFactor = getCurrentSpan() / getPreviousSpan();
- }
- return mScaleFactor;
+ return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
}
/**
@@ -552,7 +372,7 @@ public class ScaleGestureDetector {
* @return Time difference since the last scaling event in milliseconds.
*/
public long getTimeDelta() {
- return mTimeDelta;
+ return mCurrTime - mPrevTime;
}
/**
@@ -561,6 +381,6 @@ public class ScaleGestureDetector {
* @return Current event time in milliseconds.
*/
public long getEventTime() {
- return mCurrEvent.getEventTime();
+ return mCurrTime;
}
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index a6d1a3f..cf1767d 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -16,8 +16,16 @@
package android.view;
+import dalvik.system.CloseGuard;
+
import android.content.res.CompatibilityInfo.Translator;
-import android.graphics.*;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.SurfaceTexture;
+import android.os.IBinder;
import android.os.Parcelable;
import android.os.Parcel;
import android.os.SystemProperties;
@@ -27,206 +35,187 @@ import android.util.Log;
* Handle onto a raw buffer that is being managed by the screen compositor.
*/
public class Surface implements Parcelable {
- private static final String LOG_TAG = "Surface";
- private static final boolean DEBUG_RELEASE = false;
-
- /* orientations for setOrientation() */
- public static final int ROTATION_0 = 0;
- public static final int ROTATION_90 = 1;
- public static final int ROTATION_180 = 2;
- public static final int ROTATION_270 = 3;
+ private static final String TAG = "Surface";
- private static final boolean headless = "1".equals(
+ private static final boolean HEADLESS = "1".equals(
SystemProperties.get("ro.config.headless", "0"));
- private static void checkHeadless() {
- if(headless) {
- throw new UnsupportedOperationException("Device is headless");
+ public static final Parcelable.Creator<Surface> CREATOR =
+ new Parcelable.Creator<Surface>() {
+ public Surface createFromParcel(Parcel source) {
+ try {
+ Surface s = new Surface();
+ s.readFromParcel(source);
+ return s;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating surface from parcel", e);
+ return null;
+ }
}
- }
- /**
- * Create Surface from a {@link SurfaceTexture}.
- *
- * Images drawn to the Surface will be made available to the {@link
- * SurfaceTexture}, which can attach them an OpenGL ES texture via {@link
- * SurfaceTexture#updateTexImage}.
- *
- * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
- * Surface.
- */
- public Surface(SurfaceTexture surfaceTexture) {
- checkHeadless();
-
- if (DEBUG_RELEASE) {
- mCreationStack = new Exception();
+ public Surface[] newArray(int size) {
+ return new Surface[size];
}
- mCanvas = new CompatibleCanvas();
- initFromSurfaceTexture(surfaceTexture);
- }
+ };
/**
- * Does this object hold a valid surface? Returns true if it holds
- * a physical surface, so lockCanvas() will succeed. Otherwise
- * returns false.
+ * Rotation constant: 0 degree rotation (natural orientation)
*/
- public native boolean isValid();
+ public static final int ROTATION_0 = 0;
- /** Release the local reference to the server-side surface.
- * Always call release() when you're done with a Surface. This will
- * make the surface invalid.
+ /**
+ * Rotation constant: 90 degree rotation.
*/
- public native void release();
+ public static final int ROTATION_90 = 1;
- /** draw into a surface */
- public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException {
- /*
- * the dirty rectangle may be expanded to the surface's size, if for
- * instance it has been resized or if the bits were lost, since the last
- * call.
- */
- return lockCanvasNative(dirty);
- }
-
- /** unlock the surface and asks a page flip */
- public native void unlockCanvasAndPost(Canvas canvas);
-
- /**
- * unlock the surface. the screen won't be updated until
- * post() or postAll() is called
+ /**
+ * Rotation constant: 180 degree rotation.
*/
- public native void unlockCanvas(Canvas canvas);
+ public static final int ROTATION_180 = 2;
- @Override
- public String toString() {
- return "Surface(name=" + mName + ", identity=" + getIdentity() + ")";
- }
-
- public int describeContents() {
- return 0;
- }
+ /**
+ * Rotation constant: 270 degree rotation.
+ */
+ public static final int ROTATION_270 = 3;
- public native void readFromParcel(Parcel source);
- public native void writeToParcel(Parcel dest, int flags);
+ /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
+ * these are different from the logical display ids used elsewhere in the framework */
/**
- * Exception thrown when a surface couldn't be created or resized
+ * Built-in physical display id: Main display.
+ * Use only with {@link #getBuiltInDisplay()}.
+ * @hide
*/
- public static class OutOfResourcesException extends Exception {
- public OutOfResourcesException() {
- }
- public OutOfResourcesException(String name) {
- super(name);
- }
- }
-
- /*
- * -----------------------------------------------------------------------
- * No user serviceable parts beyond this point
- * -----------------------------------------------------------------------
+ public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
+
+ /**
+ * Built-in physical display id: Attached HDMI display.
+ * Use only with {@link #getBuiltInDisplay()}.
+ * @hide
*/
+ public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
- /* flags used in constructor (keep in sync with ISurfaceComposer.h) */
+ /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
- /** Surface is created hidden @hide */
- public static final int HIDDEN = 0x00000004;
+ /**
+ * Surface creation flag: Surface is created hidden
+ * @hide */
+ public static final int HIDDEN = 0x00000004;
- /** The surface contains secure content, special measures will
- * be taken to disallow the surface's content to be copied from
- * another process. In particular, screenshots and VNC servers will
+ /**
+ * Surface creation flag: The surface contains secure content, special
+ * measures will be taken to disallow the surface's content to be copied
+ * from another process. In particular, screenshots and VNC servers will
* be disabled, but other measures can take place, for instance the
* surface might not be hardware accelerated.
- * @hide*/
- public static final int SECURE = 0x00000080;
-
- /** Creates a surface where color components are interpreted as
- * "non pre-multiplied" by their alpha channel. Of course this flag is
- * meaningless for surfaces without an alpha channel. By default
- * surfaces are pre-multiplied, which means that each color component is
- * already multiplied by its alpha value. In this case the blending
- * equation used is:
- *
+ * @hide
+ */
+ public static final int SECURE = 0x00000080;
+
+ /**
+ * Surface creation flag: Creates a surface where color components are interpreted
+ * as "non pre-multiplied" by their alpha channel. Of course this flag is
+ * meaningless for surfaces without an alpha channel. By default
+ * surfaces are pre-multiplied, which means that each color component is
+ * already multiplied by its alpha value. In this case the blending
+ * equation used is:
+ *
* DEST = SRC + DEST * (1-SRC_ALPHA)
- *
- * By contrast, non pre-multiplied surfaces use the following equation:
- *
+ *
+ * By contrast, non pre-multiplied surfaces use the following equation:
+ *
* DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)
- *
- * pre-multiplied surfaces must always be used if transparent pixels are
- * composited on top of each-other into the surface. A pre-multiplied
- * surface can never lower the value of the alpha component of a given
- * pixel.
- *
- * In some rare situations, a non pre-multiplied surface is preferable.
- *
- * @hide
- */
- public static final int NON_PREMULTIPLIED = 0x00000100;
-
+ *
+ * pre-multiplied surfaces must always be used if transparent pixels are
+ * composited on top of each-other into the surface. A pre-multiplied
+ * surface can never lower the value of the alpha component of a given
+ * pixel.
+ *
+ * In some rare situations, a non pre-multiplied surface is preferable.
+ * @hide
+ */
+ public static final int NON_PREMULTIPLIED = 0x00000100;
+
/**
- * Indicates that the surface must be considered opaque, even if its
- * pixel format is set to translucent. This can be useful if an
+ * Surface creation flag: Indicates that the surface must be considered opaque,
+ * even if its pixel format is set to translucent. This can be useful if an
* application needs full RGBA 8888 support for instance but will
* still draw every pixel opaque.
- *
* @hide
*/
- public static final int OPAQUE = 0x00000400;
-
+ public static final int OPAQUE = 0x00000400;
+
/**
- * Application requires a hardware-protected path to an
+ * Surface creation flag: Application requires a hardware-protected path to an
* external display sink. If a hardware-protected path is not available,
* then this surface will not be displayed on the external sink.
- *
* @hide
*/
- public static final int PROTECTED_APP = 0x00000800;
+ public static final int PROTECTED_APP = 0x00000800;
// 0x1000 is reserved for an independent DRM protected flag in framework
- /** Creates a normal surface. This is the default. @hide */
+ /**
+ * Surface creation flag: Creates a normal surface.
+ * This is the default.
+ * @hide
+ */
public static final int FX_SURFACE_NORMAL = 0x00000000;
-
- /** Creates a Blur surface. Everything behind this surface is blurred
- * by some amount. The quality and refresh speed of the blur effect
- * is not settable or guaranteed.
- * It is an error to lock a Blur surface, since it doesn't have
- * a backing store.
+
+ /**
+ * Surface creation flag: Creates a Blur surface.
+ * Everything behind this surface is blurred by some amount.
+ * The quality and refresh speed of the blur effect is not settable or guaranteed.
+ * It is an error to lock a Blur surface, since it doesn't have a backing store.
* @hide
* @deprecated
*/
@Deprecated
- public static final int FX_SURFACE_BLUR = 0x00010000;
-
- /** Creates a Dim surface. Everything behind this surface is dimmed
- * by the amount specified in {@link #setAlpha}.
- * It is an error to lock a Dim surface, since it doesn't have
- * a backing store.
+ public static final int FX_SURFACE_BLUR = 0x00010000;
+
+ /**
+ * Surface creation flag: Creates a Dim surface.
+ * Everything behind this surface is dimmed by the amount specified
+ * in {@link #setAlpha}. It is an error to lock a Dim surface, since it
+ * doesn't have a backing store.
* @hide
*/
- public static final int FX_SURFACE_DIM = 0x00020000;
+ public static final int FX_SURFACE_DIM = 0x00020000;
- /** @hide */
- public static final int FX_SURFACE_SCREENSHOT = 0x00030000;
+ /**
+ * @hide
+ */
+ public static final int FX_SURFACE_SCREENSHOT = 0x00030000;
- /** Mask used for FX values above @hide */
- public static final int FX_SURFACE_MASK = 0x000F0000;
+ /**
+ * Mask used for FX values above.
+ * @hide
+ */
+ public static final int FX_SURFACE_MASK = 0x000F0000;
/* flags used with setFlags() (keep in sync with ISurfaceComposer.h) */
- /** Hide the surface. Equivalent to calling hide(). @hide */
- public static final int SURFACE_HIDDEN = 0x01;
+ /**
+ * Surface flag: Hide the surface.
+ * Equivalent to calling hide().
+ * @hide
+ */
+ public static final int SURFACE_HIDDEN = 0x01;
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private String mName;
+
+ // Note: These fields are accessed by native code.
// The mSurfaceControl will only be present for Surfaces used by the window
// server or system processes. When this class is parceled we defer to the
// mSurfaceControl to do the parceling. Otherwise we parcel the
// mNativeSurface.
- private int mSurfaceControl;
- private int mSaveCount;
- private Canvas mCanvas;
- private int mNativeSurface;
- private int mSurfaceGenerationId;
- private String mName;
+ private int mNativeSurface; // Surface*
+ private int mNativeSurfaceControl; // SurfaceControl*
+ private int mGenerationId; // incremented each time mNativeSurface changes
+ private final Canvas mCanvas = new CompatibleCanvas();
+ private int mCanvasSaveCount; // Canvas save count at time of lockCanvas()
// The Translator for density compatibility mode. This is used for scaling
// the canvas to perform the appropriate density transformation.
@@ -236,141 +225,245 @@ public class Surface implements Parcelable {
// non compatibility mode.
private Matrix mCompatibleMatrix;
- private Exception mCreationStack;
+ private native void nativeCreate(SurfaceSession session, String name,
+ int w, int h, int format, int flags)
+ throws OutOfResourcesException;
+ private native void nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
+ throws OutOfResourcesException;
+ private native void nativeRelease();
+ private native void nativeDestroy();
+
+ private native boolean nativeIsValid();
+ private native int nativeGetIdentity();
+ private native boolean nativeIsConsumerRunningBehind();
+
+ private native Canvas nativeLockCanvas(Rect dirty);
+ private native void nativeUnlockCanvasAndPost(Canvas canvas);
+
+ private static native Bitmap nativeScreenshot(IBinder displayToken,
+ int width, int height, int minLayer, int maxLayer, boolean allLayers);
+
+ private static native void nativeOpenTransaction();
+ private static native void nativeCloseTransaction();
+
+ private native void nativeSetLayer(int zorder);
+ private native void nativeSetPosition(float x, float y);
+ private native void nativeSetSize(int w, int h);
+ private native void nativeSetTransparentRegionHint(Region region);
+ private native void nativeSetAlpha(float alpha);
+ private native void nativeSetMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
+ private native void nativeSetFlags(int flags, int mask);
+ private native void nativeSetWindowCrop(Rect crop);
+ private native void nativeSetLayerStack(int layerStack);
+
+ private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
+ private static native IBinder nativeCreateDisplay(String name);
+ private static native void nativeSetDisplaySurface(
+ IBinder displayToken, SurfaceTexture surfaceTexture);
+ private static native void nativeSetDisplayLayerStack(
+ IBinder displayToken, int layerStack);
+ private static native void nativeSetDisplayOrientation(
+ IBinder displayToken, int orientation);
+ private static native void nativeSetDisplayViewport(
+ IBinder displayToken, Rect viewport);
+ private static native void nativeSetDisplayFrame(
+ IBinder displayToken, Rect frame);
+ private static native boolean nativeGetDisplayInfo(
+ IBinder displayToken, PhysicalDisplayInfo outInfo);
+
+ private native void nativeCopyFrom(Surface other);
+ private native void nativeTransferFrom(Surface other);
+ private native void nativeReadFromParcel(Parcel source);
+ private native void nativeWriteToParcel(Parcel dest);
- /*
- * We use a class initializer to allow the native code to cache some
- * field offsets.
+ /**
+ * Create an empty surface, which will later be filled in by readFromParcel().
+ * @hide
*/
- native private static void nativeClassInit();
- static { nativeClassInit(); }
-
- /** create a surface with a name @hide */
- public Surface(SurfaceSession s,
- int pid, String name, int layerStack, int w, int h, int format, int flags)
- throws OutOfResourcesException {
+ public Surface() {
checkHeadless();
- if (DEBUG_RELEASE) {
- mCreationStack = new Exception();
+ mCloseGuard.open("release");
+ }
+
+ /**
+ * Create a surface with a name.
+ *
+ * The surface creation flags specify what kind of surface to create and
+ * certain options such as whether the surface can be assumed to be opaque
+ * and whether it should be initially hidden. Surfaces should always be
+ * created with the {@link #HIDDEN} flag set to ensure that they are not
+ * made visible prematurely before all of the surface's properties have been
+ * configured.
+ *
+ * Good practice is to first create the surface with the {@link #HIDDEN} flag
+ * specified, open a transaction, set the surface layer, layer stack, alpha,
+ * and position, call {@link #show} if appropriate, and close the transaction.
+ *
+ * @param session The surface session, must not be null.
+ * @param name The surface name, must not be null.
+ * @param w The surface initial width.
+ * @param h The surface initial height.
+ * @param flags The surface creation flags. Should always include {@link #HIDDEN}
+ * in the creation flags.
+ * @hide
+ */
+ public Surface(SurfaceSession session,
+ String name, int w, int h, int format, int flags)
+ throws OutOfResourcesException {
+ if (session == null) {
+ throw new IllegalArgumentException("session must not be null");
+ }
+ if (name == null) {
+ throw new IllegalArgumentException("name must not be null");
+ }
+
+ if ((flags & HIDDEN) == 0) {
+ Log.w(TAG, "Surfaces should always be created with the HIDDEN flag set "
+ + "to ensure that they are not made visible prematurely before "
+ + "all of the surface's properties have been configured. "
+ + "Set the other properties and make the surface visible within "
+ + "a transaction. New surface name: " + name,
+ new Throwable());
}
- mCanvas = new CompatibleCanvas();
- init(s, pid, name, layerStack, w, h, format, flags);
+
+ checkHeadless();
+
mName = name;
+ nativeCreate(session, name, w, h, format, flags);
+
+ mCloseGuard.open("release");
}
/**
- * Create an empty surface, which will later be filled in by
- * readFromParcel().
- * @hide
+ * Create Surface from a {@link SurfaceTexture}.
+ *
+ * Images drawn to the Surface will be made available to the {@link
+ * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
+ * SurfaceTexture#updateTexImage}.
+ *
+ * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
+ * Surface.
*/
- public Surface() {
+ public Surface(SurfaceTexture surfaceTexture) {
+ if (surfaceTexture == null) {
+ throw new IllegalArgumentException("surfaceTexture must not be null");
+ }
+
checkHeadless();
- if (DEBUG_RELEASE) {
- mCreationStack = new Exception();
+ mName = surfaceTexture.toString();
+ try {
+ nativeCreateFromSurfaceTexture(surfaceTexture);
+ } catch (OutOfResourcesException ex) {
+ // We can't throw OutOfResourcesException because it would be an API change.
+ throw new RuntimeException(ex);
}
- mCanvas = new CompatibleCanvas();
+
+ mCloseGuard.open("release");
}
- private Surface(Parcel source) throws OutOfResourcesException {
- init(source);
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ nativeRelease();
+ } finally {
+ super.finalize();
+ }
}
/**
- * Copy another surface to this one. This surface now holds a reference
- * to the same data as the original surface, and is -not- the owner.
- * This is for use by the window manager when returning a window surface
- * back from a client, converting it from the representation being managed
- * by the window manager to the representation the client uses to draw
- * in to it.
+ * Release the local reference to the server-side surface.
+ * Always call release() when you're done with a Surface.
+ * This will make the surface invalid.
+ */
+ public void release() {
+ nativeRelease();
+ mCloseGuard.close();
+ }
+
+ /**
+ * Free all server-side state associated with this surface and
+ * release this object's reference. This method can only be
+ * called from the process that created the service.
* @hide
*/
- public native void copyFrom(Surface o);
+ public void destroy() {
+ nativeDestroy();
+ mCloseGuard.close();
+ }
/**
- * Transfer the native state from 'o' to this surface, releasing it
- * from 'o'. This is for use in the client side for drawing into a
- * surface; not guaranteed to work on the window manager side.
- * This is for use by the client to move the underlying surface from
- * one Surface object to another, in particular in SurfaceFlinger.
- * @hide.
+ * Returns true if this object holds a valid surface.
+ *
+ * @return True if it holds a physical surface, so lockCanvas() will succeed.
+ * Otherwise returns false.
*/
- public native void transferFrom(Surface o);
+ public boolean isValid() {
+ return nativeIsValid();
+ }
- /** @hide */
+ /**
+ * Gets the generation number of this surface, incremented each time
+ * the native surface contained within this object changes.
+ *
+ * @return The current generation number.
+ * @hide
+ */
public int getGenerationId() {
- return mSurfaceGenerationId;
+ return mGenerationId;
}
-
/**
- * Whether the consumer of this Surface is running behind the producer;
- * that is, isConsumerRunningBehind() returns true if the consumer is more
- * than one buffer ahead of the producer.
+ * Returns true if the consumer of this Surface is running behind the producer.
+ *
+ * @return True if the consumer is more than one buffer ahead of the producer.
* @hide
*/
- public native boolean isConsumerRunningBehind();
+ public boolean isConsumerRunningBehind() {
+ return nativeIsConsumerRunningBehind();
+ }
/**
- * A Canvas class that can handle the compatibility mode. This does two
- * things differently.
- * <ul>
- * <li>Returns the width and height of the target metrics, rather than
- * native. For example, the canvas returns 320x480 even if an app is running
- * in WVGA high density.
- * <li>Scales the matrix in setMatrix by the application scale, except if
- * the matrix looks like obtained from getMatrix. This is a hack to handle
- * the case that an application uses getMatrix to keep the original matrix,
- * set matrix of its own, then set the original matrix back. There is no
- * perfect solution that works for all cases, and there are a lot of cases
- * that this model does not work, but we hope this works for many apps.
- * </ul>
+ * Gets a {@link Canvas} for drawing into this surface.
+ *
+ * After drawing into the provided {@link Canvas}, the caller should
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * @param dirty A rectangle that represents the dirty region that the caller wants
+ * to redraw. This function may choose to expand the dirty rectangle if for example
+ * the surface has been resized or if the previous contents of the surface were
+ * not available. The caller should redraw the entire dirty region as represented
+ * by the contents of the dirty rect upon return from this function.
+ * The caller may also pass <code>null</code> instead, in the case where the
+ * entire surface should be redrawn.
+ * @return A canvas for drawing into the surface.
*/
- private class CompatibleCanvas extends Canvas {
- // A temp matrix to remember what an application obtained via {@link getMatrix}
- private Matrix mOrigMatrix = null;
-
- @Override
- public int getWidth() {
- int w = super.getWidth();
- if (mCompatibilityTranslator != null) {
- w = (int)(w * mCompatibilityTranslator.applicationInvertedScale + .5f);
- }
- return w;
- }
-
- @Override
- public int getHeight() {
- int h = super.getHeight();
- if (mCompatibilityTranslator != null) {
- h = (int)(h * mCompatibilityTranslator.applicationInvertedScale + .5f);
- }
- return h;
- }
+ public Canvas lockCanvas(Rect dirty)
+ throws OutOfResourcesException, IllegalArgumentException {
+ return nativeLockCanvas(dirty);
+ }
- @Override
- public void setMatrix(Matrix matrix) {
- if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
- // don't scale the matrix if it's not compatibility mode, or
- // the matrix was obtained from getMatrix.
- super.setMatrix(matrix);
- } else {
- Matrix m = new Matrix(mCompatibleMatrix);
- m.preConcat(matrix);
- super.setMatrix(m);
- }
- }
+ /**
+ * Posts the new contents of the {@link Canvas} to the surface and
+ * releases the {@link Canvas}.
+ *
+ * @param canvas The canvas previously obtained from {@link #lockCanvas}.
+ */
+ public void unlockCanvasAndPost(Canvas canvas) {
+ nativeUnlockCanvasAndPost(canvas);
+ }
- @Override
- public void getMatrix(Matrix m) {
- super.getMatrix(m);
- if (mOrigMatrix == null) {
- mOrigMatrix = new Matrix();
- }
- mOrigMatrix.set(m);
- }
+ /**
+ * @deprecated This API has been removed and is not supported. Do not use.
+ */
+ @Deprecated
+ public void unlockCanvas(Canvas canvas) {
+ throw new UnsupportedOperationException();
}
/**
@@ -384,20 +477,6 @@ public class Surface implements Parcelable {
mCompatibleMatrix.setScale(appScale, appScale);
}
}
-
- /** Free all server-side state associated with this surface and
- * release this object's reference. @hide */
- public native void destroy();
-
- private native Canvas lockCanvasNative(Rect dirty) throws OutOfResourcesException;
-
- /**
- * set the orientation of the given display.
- * @param display
- * @param orientation
- * @hide
- */
- public static native void setOrientation(int display, int orientation);
/**
* Like {@link #screenshot(int, int, int, int)} but includes all
@@ -405,8 +484,12 @@ public class Surface implements Parcelable {
*
* @hide
*/
- public static native Bitmap screenshot(int width, int height);
-
+ public static Bitmap screenshot(int width, int height) {
+ // TODO: should take the display as a parameter
+ IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN);
+ return nativeScreenshot(displayToken, width, height, 0, 0, true);
+ }
+
/**
* Copy the current screen contents into a bitmap and return it.
*
@@ -418,91 +501,318 @@ public class Surface implements Parcelable {
* include in the screenshot.
* @param maxLayer The highest (top-most Z order) surface layer to
* include in the screenshot.
- * @return Returns a Bitmap containing the screen contents.
+ * @return Returns a Bitmap containing the screen contents, or null
+ * if an error occurs.
*
* @hide
*/
- public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);
+ public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
+ // TODO: should take the display as a parameter
+ IBinder displayToken = getBuiltInDisplay(BUILT_IN_DISPLAY_ID_MAIN);
+ return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false);
+ }
-
/*
* set surface parameters.
* needs to be inside open/closeTransaction block
*/
-
+
/** start a transaction @hide */
- public static native void openTransaction();
+ public static void openTransaction() {
+ nativeOpenTransaction();
+ }
+
/** end a transaction @hide */
- public static native void closeTransaction();
+ public static void closeTransaction() {
+ nativeCloseTransaction();
+ }
+
/** @hide */
- public native void setLayer(int zorder);
+ public void setLayer(int zorder) {
+ nativeSetLayer(zorder);
+ }
+
/** @hide */
- public void setPosition(int x, int y) { setPosition((float)x, (float)y); }
+ public void setPosition(int x, int y) {
+ nativeSetPosition((float)x, (float)y);
+ }
+
/** @hide */
- public native void setPosition(float x, float y);
+ public void setPosition(float x, float y) {
+ nativeSetPosition(x, y);
+ }
+
/** @hide */
- public native void setSize(int w, int h);
+ public void setSize(int w, int h) {
+ nativeSetSize(w, h);
+ }
+
/** @hide */
- public native void hide();
+ public void hide() {
+ nativeSetFlags(SURFACE_HIDDEN, SURFACE_HIDDEN);
+ }
+
/** @hide */
- public native void show();
+ public void show() {
+ nativeSetFlags(0, SURFACE_HIDDEN);
+ }
+
/** @hide */
- public native void setTransparentRegionHint(Region region);
+ public void setTransparentRegionHint(Region region) {
+ nativeSetTransparentRegionHint(region);
+ }
+
/** @hide */
- public native void setAlpha(float alpha);
+ public void setAlpha(float alpha) {
+ nativeSetAlpha(alpha);
+ }
+
/** @hide */
- public native void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
+ public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ nativeSetMatrix(dsdx, dtdx, dsdy, dtdy);
+ }
+
/** @hide */
- public native void setFlags(int flags, int mask);
+ public void setFlags(int flags, int mask) {
+ nativeSetFlags(flags, mask);
+ }
+
/** @hide */
- public native void setWindowCrop(Rect crop);
+ public void setWindowCrop(Rect crop) {
+ nativeSetWindowCrop(crop);
+ }
+
/** @hide */
- public native void setLayerStack(int layerStack);
+ public void setLayerStack(int layerStack) {
+ nativeSetLayerStack(layerStack);
+ }
+ /** @hide */
+ public static IBinder getBuiltInDisplay(int builtInDisplayId) {
+ return nativeGetBuiltInDisplay(builtInDisplayId);
+ }
-
- public static final Parcelable.Creator<Surface> CREATOR
- = new Parcelable.Creator<Surface>()
- {
- public Surface createFromParcel(Parcel source) {
- try {
- return new Surface(source);
- } catch (Exception e) {
- Log.e(LOG_TAG, "Exception creating surface from parcel", e);
- }
- return null;
+ /** @hide */
+ public static IBinder createDisplay(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name must not be null");
}
+ return nativeCreateDisplay(name);
+ }
- public Surface[] newArray(int size) {
- return new Surface[size];
+ /** @hide */
+ public static void setDisplaySurface(IBinder displayToken, SurfaceTexture surfaceTexture) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
}
- };
+ nativeSetDisplaySurface(displayToken, surfaceTexture);
+ }
+
+ /** @hide */
+ public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ nativeSetDisplayLayerStack(displayToken, layerStack);
+ }
+
+ /** @hide */
+ public static void setDisplayOrientation(IBinder displayToken, int orientation) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ nativeSetDisplayOrientation(displayToken, orientation);
+ }
+
+ /** @hide */
+ public static void setDisplayViewport(IBinder displayToken, Rect viewport) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ if (viewport == null) {
+ throw new IllegalArgumentException("viewport must not be null");
+ }
+ nativeSetDisplayViewport(displayToken, viewport);
+ }
+
+ /** @hide */
+ public static void setDisplayFrame(IBinder displayToken, Rect frame) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ if (frame == null) {
+ throw new IllegalArgumentException("frame must not be null");
+ }
+ nativeSetDisplayFrame(displayToken, frame);
+ }
+
+ /** @hide */
+ public static boolean getDisplayInfo(IBinder displayToken, PhysicalDisplayInfo outInfo) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ if (outInfo == null) {
+ throw new IllegalArgumentException("outInfo must not be null");
+ }
+ return nativeGetDisplayInfo(displayToken, outInfo);
+ }
+
+ /**
+ * Copy another surface to this one. This surface now holds a reference
+ * to the same data as the original surface, and is -not- the owner.
+ * This is for use by the window manager when returning a window surface
+ * back from a client, converting it from the representation being managed
+ * by the window manager to the representation the client uses to draw
+ * in to it.
+ * @hide
+ */
+ public void copyFrom(Surface other) {
+ if (other == null) {
+ throw new IllegalArgumentException("other must not be null");
+ }
+ if (other != this) {
+ nativeCopyFrom(other);
+ }
+ }
+
+ /**
+ * Transfer the native state from 'other' to this surface, releasing it
+ * from 'other'. This is for use in the client side for drawing into a
+ * surface; not guaranteed to work on the window manager side.
+ * This is for use by the client to move the underlying surface from
+ * one Surface object to another, in particular in SurfaceFlinger.
+ * @hide.
+ */
+ public void transferFrom(Surface other) {
+ if (other == null) {
+ throw new IllegalArgumentException("other must not be null");
+ }
+ if (other != this) {
+ nativeTransferFrom(other);
+ }
+ }
@Override
- protected void finalize() throws Throwable {
- try {
- super.finalize();
- } finally {
- if (mNativeSurface != 0 || mSurfaceControl != 0) {
- if (DEBUG_RELEASE) {
- Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() ("
- + mNativeSurface + ", " + mSurfaceControl + ")", mCreationStack);
- } else {
- Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() ("
- + mNativeSurface + ", " + mSurfaceControl + ")");
- }
- }
- release();
+ public int describeContents() {
+ return 0;
+ }
+
+ public void readFromParcel(Parcel source) {
+ if (source == null) {
+ throw new IllegalArgumentException("source must not be null");
}
+
+ mName = source.readString();
+ nativeReadFromParcel(source);
}
-
- private native void init(SurfaceSession s,
- int pid, String name, int layerStack, int w, int h, int format, int flags)
- throws OutOfResourcesException;
- private native void init(Parcel source) throws OutOfResourcesException;
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (dest == null) {
+ throw new IllegalArgumentException("dest must not be null");
+ }
- private native void initFromSurfaceTexture(SurfaceTexture surfaceTexture);
+ dest.writeString(mName);
+ nativeWriteToParcel(dest);
+ if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+ release();
+ }
+ }
- private native int getIdentity();
+ @Override
+ public String toString() {
+ return "Surface(name=" + mName + ", identity=" + nativeGetIdentity() + ")";
+ }
+
+ private static void checkHeadless() {
+ if (HEADLESS) {
+ throw new UnsupportedOperationException("Device is headless");
+ }
+ }
+
+ /**
+ * Exception thrown when a surface couldn't be created or resized.
+ */
+ public static class OutOfResourcesException extends Exception {
+ public OutOfResourcesException() {
+ }
+
+ public OutOfResourcesException(String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * Describes the properties of a physical display.
+ * @hide
+ */
+ public static final class PhysicalDisplayInfo {
+ // TODO: redesign this
+ public int width;
+ public int height;
+ public float refreshRate;
+ public float density;
+ public float xDpi;
+ public float yDpi;
+ }
+
+ /**
+ * A Canvas class that can handle the compatibility mode.
+ * This does two things differently.
+ * <ul>
+ * <li>Returns the width and height of the target metrics, rather than
+ * native. For example, the canvas returns 320x480 even if an app is running
+ * in WVGA high density.
+ * <li>Scales the matrix in setMatrix by the application scale, except if
+ * the matrix looks like obtained from getMatrix. This is a hack to handle
+ * the case that an application uses getMatrix to keep the original matrix,
+ * set matrix of its own, then set the original matrix back. There is no
+ * perfect solution that works for all cases, and there are a lot of cases
+ * that this model does not work, but we hope this works for many apps.
+ * </ul>
+ */
+ private final class CompatibleCanvas extends Canvas {
+ // A temp matrix to remember what an application obtained via {@link getMatrix}
+ private Matrix mOrigMatrix = null;
+
+ @Override
+ public int getWidth() {
+ int w = super.getWidth();
+ if (mCompatibilityTranslator != null) {
+ w = (int)(w * mCompatibilityTranslator.applicationInvertedScale + .5f);
+ }
+ return w;
+ }
+
+ @Override
+ public int getHeight() {
+ int h = super.getHeight();
+ if (mCompatibilityTranslator != null) {
+ h = (int)(h * mCompatibilityTranslator.applicationInvertedScale + .5f);
+ }
+ return h;
+ }
+
+ @Override
+ public void setMatrix(Matrix matrix) {
+ if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
+ // don't scale the matrix if it's not compatibility mode, or
+ // the matrix was obtained from getMatrix.
+ super.setMatrix(matrix);
+ } else {
+ Matrix m = new Matrix(mCompatibleMatrix);
+ m.preConcat(matrix);
+ super.setMatrix(m);
+ }
+ }
+
+ @Override
+ public void getMatrix(Matrix m) {
+ super.getMatrix(m);
+ if (mOrigMatrix == null) {
+ mOrigMatrix = new Matrix();
+ }
+ mOrigMatrix.set(m);
+ }
+ }
}
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 2a04675..0dfd94a 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -16,34 +16,44 @@
package android.view;
-
/**
* An instance of this class represents a connection to the surface
- * flinger, in which you can create one or more Surface instances that will
+ * flinger, from which you can create one or more Surface instances that will
* be composited to the screen.
* {@hide}
*/
-public class SurfaceSession {
+public final class SurfaceSession {
+ // Note: This field is accessed by native code.
+ private int mNativeClient; // SurfaceComposerClient*
+
+ private static native int nativeCreate();
+ private static native void nativeDestroy(int ptr);
+ private static native void nativeKill(int ptr);
+
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
- init();
+ mNativeClient = nativeCreate();
}
- /** Forcibly detach native resources associated with this object.
- * Unlike destroy(), after this call any surfaces that were created
- * from the session will no longer work. The session itself is destroyed.
- */
- public native void kill();
-
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
- destroy();
+ try {
+ if (mNativeClient != 0) {
+ nativeDestroy(mNativeClient);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Forcibly detach native resources associated with this object.
+ * Unlike destroy(), after this call any surfaces that were created
+ * from the session will no longer work.
+ */
+ public void kill() {
+ nativeKill(mNativeClient);
}
-
- private native void init();
- private native void destroy();
-
- private int mClient;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b1f5e9e..745e1b8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,6 +40,7 @@ import android.graphics.Shader;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -4925,6 +4926,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Returns the delegate for implementing accessibility support via
+ * composition. For more details see {@link AccessibilityDelegate}.
+ *
+ * @return The delegate, or null if none set.
+ *
+ * @hide
+ */
+ public AccessibilityDelegate getAccessibilityDelegate() {
+ return mAccessibilityDelegate;
+ }
+
+ /**
* Sets a delegate for implementing accessibility support via compositon as
* opposed to inheritance. The delegate's primary use is for implementing
* backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
@@ -7347,7 +7360,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
outRect.bottom -= insets.bottom;
return;
}
- Display d = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+ // The view is not attached to a display so we don't have a context.
+ // Make a best guess about the display size.
+ Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
d.getRectSize(outRect);
}
@@ -17610,23 +17625,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// use use a height of 1, and then wack the matrix each time we
// actually use it.
shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
-
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+
this.host = host;
}
public void setFadeColor(int color) {
- if (color != 0 && color != mLastColor) {
+ if (color != mLastColor) {
mLastColor = color;
- color |= 0xFF000000;
- shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
- color & 0x00FFFFFF, Shader.TileMode.CLAMP);
-
- paint.setShader(shader);
- // Restore the default transfer mode (src_over)
- paint.setXfermode(null);
+ if (color != 0) {
+ shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
+ color & 0x00FFFFFF, Shader.TileMode.CLAMP);
+ paint.setShader(shader);
+ // Restore the default transfer mode (src_over)
+ paint.setXfermode(null);
+ } else {
+ shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
+ paint.setShader(shader);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 725d9b5..ffd495e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -214,6 +214,9 @@ public final class ViewRootImpl implements ViewParent,
boolean mTraversalScheduled;
int mTraversalBarrier;
boolean mWillDrawSoon;
+ /** Set to true while in performTraversals for detecting when die(true) is called from internal
+ * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
+ boolean mIsInTraversal;
boolean mFitSystemWindowsRequested;
boolean mLayoutRequested;
boolean mFirst;
@@ -1104,6 +1107,7 @@ public final class ViewRootImpl implements ViewParent,
if (host == null || !mAdded)
return;
+ mIsInTraversal = true;
mWillDrawSoon = true;
boolean windowSizeMayChange = false;
boolean newSurface = false;
@@ -1842,6 +1846,8 @@ public final class ViewRootImpl implements ViewParent,
mPendingTransitions.clear();
}
}
+
+ mIsInTraversal = false;
}
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
@@ -3956,7 +3962,9 @@ public final class ViewRootImpl implements ViewParent,
}
public void die(boolean immediate) {
- if (immediate) {
+ // Make sure we do execute immediately if we are in the middle of a traversal or the damage
+ // done by dispatchDetachedFromWindow will cause havoc on return.
+ if (immediate && !mIsInTraversal) {
doDie();
} else {
if (!mIsDrawing) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 123d9e7..f30952c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -179,7 +179,8 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS"),
@ViewDebug.IntToString(from = TYPE_HIDDEN_NAV_CONSUMER, to = "TYPE_HIDDEN_NAV_CONSUMER"),
@ViewDebug.IntToString(from = TYPE_DREAM, to = "TYPE_DREAM"),
- @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL")
+ @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"),
+ @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY")
})
public int type;
@@ -435,6 +436,12 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
/**
+ * Window type: Display overlay window. Used to simulate secondary display devices.
+ * @hide
+ */
+ public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index bf061df..aa9179f 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -52,8 +52,9 @@ public final class WindowManagerImpl implements WindowManager {
private final Window mParentWindow;
public WindowManagerImpl(Context context, int displayId) {
+ DisplayManager dm = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mContext = context;
- mDisplay = DisplayManager.getInstance().getDisplay(displayId, mContext);
+ mDisplay = dm.getDisplay(displayId);
mParentWindow = null;
}
diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java
index 7dfb5bb..fd73fda 100644
--- a/core/java/android/webkit/AccessibilityInjector.java
+++ b/core/java/android/webkit/AccessibilityInjector.java
@@ -279,6 +279,7 @@ class AccessibilityInjector {
}
if (!shouldInjectJavaScript(url)) {
+ mAccessibilityScriptInjected = false;
toggleFallbackAccessibilityInjector(true);
return;
}
@@ -292,6 +293,23 @@ class AccessibilityInjector {
}
/**
+ * Adjusts the accessibility injection state to reflect changes in the
+ * JavaScript enabled state.
+ *
+ * @param enabled Whether JavaScript is enabled.
+ */
+ public void updateJavaScriptEnabled(boolean enabled) {
+ if (enabled) {
+ addAccessibilityApisIfNecessary();
+ } else {
+ removeAccessibilityApisIfNecessary();
+ }
+
+ // We have to reload the page after adding or removing APIs.
+ mWebView.reload();
+ }
+
+ /**
* Toggles the non-JavaScript method for handling accessibility.
*
* @param enabled {@code true} to enable the non-JavaScript method, or
diff --git a/core/java/android/webkit/BrowserDownloadListener.java b/core/java/android/webkit/BrowserDownloadListener.java
new file mode 100644
index 0000000..724cc62
--- /dev/null
+++ b/core/java/android/webkit/BrowserDownloadListener.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * An abstract download listener that allows passing extra information as
+ * part of onDownloadStart callback.
+ * @hide
+ */
+public abstract class BrowserDownloadListener implements DownloadListener {
+
+ /**
+ * Notify the host application that a file should be downloaded
+ * @param url The full url to the content that should be downloaded
+ * @param userAgent the user agent to be used for the download.
+ * @param contentDisposition Content-disposition http header, if
+ * present.
+ * @param mimetype The mimetype of the content reported by the server
+ * @param referer The referer associated with this url
+ * @param contentLength The file size reported by the server
+ */
+ public abstract void onDownloadStart(String url, String userAgent,
+ String contentDisposition, String mimetype, String referer,
+ long contentLength);
+
+
+ /**
+ * Notify the host application that a file should be downloaded
+ * @param url The full url to the content that should be downloaded
+ * @param userAgent the user agent to be used for the download.
+ * @param contentDisposition Content-disposition http header, if
+ * present.
+ * @param mimetype The mimetype of the content reported by the server
+ * @param contentLength The file size reported by the server
+ */
+ @Override
+ public void onDownloadStart(String url, String userAgent,
+ String contentDisposition, String mimetype, long contentLength) {
+
+ onDownloadStart(url, userAgent, contentDisposition, mimetype, null,
+ contentLength);
+ }
+}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index fe812af..1b23b18 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1137,7 +1137,7 @@ class BrowserFrame extends Handler {
* DownloadListener.
*/
private void downloadStart(String url, String userAgent,
- String contentDisposition, String mimeType, long contentLength) {
+ String contentDisposition, String mimeType, String referer, long contentLength) {
// This will only work if the url ends with the filename
if (mimeType.isEmpty()) {
try {
@@ -1157,7 +1157,7 @@ class BrowserFrame extends Handler {
mKeyStoreHandler = new KeyStoreHandler(mimeType);
} else {
mCallbackProxy.onDownloadStart(url, userAgent,
- contentDisposition, mimeType, contentLength);
+ contentDisposition, mimeType, referer, contentLength);
}
}
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 6b87ded..b47cba8 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -452,10 +452,16 @@ class CallbackProxy extends Handler {
String contentDisposition =
msg.getData().getString("contentDisposition");
String mimetype = msg.getData().getString("mimetype");
+ String referer = msg.getData().getString("referer");
Long contentLength = msg.getData().getLong("contentLength");
- mDownloadListener.onDownloadStart(url, userAgent,
- contentDisposition, mimetype, contentLength);
+ if (mDownloadListener instanceof BrowserDownloadListener) {
+ ((BrowserDownloadListener) mDownloadListener).onDownloadStart(url,
+ userAgent, contentDisposition, mimetype, referer, contentLength);
+ } else {
+ mDownloadListener.onDownloadStart(url, userAgent,
+ contentDisposition, mimetype, contentLength);
+ }
}
break;
@@ -1179,7 +1185,8 @@ class CallbackProxy extends Handler {
* return false.
*/
public boolean onDownloadStart(String url, String userAgent,
- String contentDisposition, String mimetype, long contentLength) {
+ String contentDisposition, String mimetype, String referer,
+ long contentLength) {
// Do an unsynchronized quick check to avoid posting if no callback has
// been set.
if (mDownloadListener == null) {
@@ -1192,6 +1199,7 @@ class CallbackProxy extends Handler {
bundle.putString("url", url);
bundle.putString("userAgent", userAgent);
bundle.putString("mimetype", mimetype);
+ bundle.putString("referer", referer);
bundle.putLong("contentLength", contentLength);
bundle.putString("contentDisposition", contentDisposition);
sendMessage(msg);
diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java
index d1f8b4b..1bbe7bb 100644
--- a/core/java/android/webkit/WebSettingsClassic.java
+++ b/core/java/android/webkit/WebSettingsClassic.java
@@ -1122,6 +1122,7 @@ public class WebSettingsClassic extends WebSettings {
if (mJavaScriptEnabled != flag) {
mJavaScriptEnabled = flag;
postSync();
+ mWebView.updateJavaScriptEnabled(flag);
}
}
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 9df4852..591b87f 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -687,6 +687,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// It's used to dismiss the dialog in destroy if not done before.
private AlertDialog mListBoxDialog = null;
+ // Reference to the save password dialog so it can be dimissed in
+ // destroy if not done before.
+ private AlertDialog mSavePasswordDialog = null;
+
static final String LOGTAG = "webview";
private ZoomManager mZoomManager;
@@ -1370,7 +1374,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
if (action == MotionEvent.ACTION_POINTER_DOWN) {
cancelTouch();
action = MotionEvent.ACTION_DOWN;
- } else if (action == MotionEvent.ACTION_POINTER_UP && ev.getPointerCount() >= 2) {
+ } else if (action == MotionEvent.ACTION_POINTER_UP) {
// set mLastTouchX/Y to the remaining points for multi-touch.
mLastTouchX = Math.round(x);
mLastTouchY = Math.round(y);
@@ -1633,6 +1637,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
mZoomManager.updateMultiTouchSupport(context);
}
+ void updateJavaScriptEnabled(boolean enabled) {
+ if (isAccessibilityInjectionEnabled()) {
+ getAccessibilityInjector().updateJavaScriptEnabled(enabled);
+ }
+ }
+
private void init() {
OnTrimMemoryListener.init(mContext);
mWebView.setWillNotDraw(false);
@@ -1830,7 +1840,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
neverRemember.getData().putString("password", password);
neverRemember.obj = resumeMsg;
- new AlertDialog.Builder(mContext)
+ mSavePasswordDialog = new AlertDialog.Builder(mContext)
.setTitle(com.android.internal.R.string.save_password_label)
.setMessage(com.android.internal.R.string.save_password_message)
.setPositiveButton(com.android.internal.R.string.save_password_notnow,
@@ -1841,6 +1851,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
resumeMsg.sendToTarget();
mResumeMsg = null;
}
+ mSavePasswordDialog = null;
}
})
.setNeutralButton(com.android.internal.R.string.save_password_remember,
@@ -1851,6 +1862,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
remember.sendToTarget();
mResumeMsg = null;
}
+ mSavePasswordDialog = null;
}
})
.setNegativeButton(com.android.internal.R.string.save_password_never,
@@ -1861,6 +1873,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
neverRemember.sendToTarget();
mResumeMsg = null;
}
+ mSavePasswordDialog = null;
}
})
.setOnCancelListener(new OnCancelListener() {
@@ -1870,6 +1883,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
resumeMsg.sendToTarget();
mResumeMsg = null;
}
+ mSavePasswordDialog = null;
}
}).show();
// Return true so that WebViewCore will pause while the dialog is
@@ -2109,6 +2123,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
mListBoxDialog.dismiss();
mListBoxDialog = null;
}
+ if (mSavePasswordDialog != null) {
+ mSavePasswordDialog.dismiss();
+ mSavePasswordDialog = null;
+ }
if (mWebViewCore != null) {
// Tell WebViewCore to destroy itself
synchronized (this) {
@@ -6981,6 +6999,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
+ // Check if we are destroyed
+ if (mWebViewCore == null) return false;
// FIXME: If a subwindow is showing find, and the user touches the
// background window, it can steal focus.
if (mFindIsUp) return false;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 423135f..920d44f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2158,7 +2158,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mAccessibilityDelegate == null) {
mAccessibilityDelegate = new ListItemAccessibilityDelegate();
}
- child.setAccessibilityDelegate(mAccessibilityDelegate);
+ if (child.getAccessibilityDelegate() == null) {
+ child.setAccessibilityDelegate(mAccessibilityDelegate);
+ }
}
return child;
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index fc35f05..f76ab2b 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -477,7 +477,8 @@ public class MediaController extends FrameLayout {
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP
- || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+ || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE
+ || keyCode == KeyEvent.KEYCODE_CAMERA) {
// don't show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 053ade7..e8bf9d9 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -305,12 +305,14 @@ public class Toast {
private static class TN extends ITransientNotification.Stub {
final Runnable mShow = new Runnable() {
+ @Override
public void run() {
handleShow();
}
};
final Runnable mHide = new Runnable() {
+ @Override
public void run() {
handleHide();
// Don't do this in handleHide() because it is also invoked by handleShow()
@@ -329,7 +331,7 @@ public class Toast {
View mView;
View mNextView;
-
+
WindowManager mWM;
TN() {
@@ -350,6 +352,7 @@ public class Toast {
/**
* schedule handleShow into the right thread
*/
+ @Override
public void show() {
if (localLOGV) Log.v(TAG, "SHOW: " + this);
mHandler.post(mShow);
@@ -358,6 +361,7 @@ public class Toast {
/**
* schedule handleHide into the right thread
*/
+ @Override
public void hide() {
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.post(mHide);
@@ -370,7 +374,8 @@ public class Toast {
// remove the old view if necessary
handleHide();
mView = mNextView;
- mWM = (WindowManager)mView.getContext().getSystemService(Context.WINDOW_SERVICE);
+ mWM = (WindowManager)mView.getContext().getApplicationContext()
+ .getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
final Configuration config = mView.getContext().getResources().getConfiguration();
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index 6a68240..eee914e 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -329,8 +329,21 @@ public class ViewAnimator extends FrameLayout {
}
/**
+ * Returns whether the current View should be animated the first time the ViewAnimator
+ * is displayed.
+ *
+ * @return true if the current View will be animated the first time it is displayed,
+ * false otherwise.
+ *
+ * @see #setAnimateFirstView(boolean)
+ */
+ public boolean getAnimateFirstView() {
+ return mAnimateFirstTime;
+ }
+
+ /**
* Indicates whether the current View should be animated the first time
- * the ViewAnimation is displayed.
+ * the ViewAnimator is displayed.
*
* @param animate True to animate the current View the first time it is displayed,
* false otherwise.
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 650681a..3477a90 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -49,6 +49,7 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
sPackageFilt.addDataScheme("package");
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
+ sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
}
@@ -136,6 +137,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
return false;
}
+
+ public void onHandleUserStop(Intent intent, int userHandle) {
+ }
public void onUidRemoved(int uid) {
}
@@ -307,6 +311,10 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
intent.getIntExtra(Intent.EXTRA_UID, 0), true);
} else if (Intent.ACTION_UID_REMOVED.equals(action)) {
onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0));
+ } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
+ if (intent.hasExtra(Intent.EXTRA_USER_HANDLE)) {
+ onHandleUserStop(intent, intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ }
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
mAppearingPackages = pkgList;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index d6f1807..d24513a 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -529,6 +529,8 @@ class ZygoteConnection {
niceName = arg.substring(arg.indexOf('=') + 1);
} else if (arg.equals("--mount-external-multiuser")) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
+ } else if (arg.equals("--mount-external-multiuser-all")) {
+ mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
} else {
break;
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f950d3d..9d45479 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -46,6 +46,7 @@ LOCAL_SRC_FILES:= \
android_emoji_EmojiFactory.cpp \
android_view_DisplayEventReceiver.cpp \
android_view_Surface.cpp \
+ android_view_SurfaceSession.cpp \
android_view_TextureView.cpp \
android_view_InputChannel.cpp \
android_view_InputDevice.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0c88297..55563a8 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -121,6 +121,7 @@ extern int register_android_view_GLES20DisplayList(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
extern int register_android_view_HardwareRenderer(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
+extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
extern int register_android_database_CursorWindow(JNIEnv* env);
extern int register_android_database_SQLiteConnection(JNIEnv* env);
@@ -1094,6 +1095,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_view_GLES20Canvas),
REG_JNI(register_android_view_HardwareRenderer),
REG_JNI(register_android_view_Surface),
+ REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_TextureView),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 3c27caf..1bba5b4 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -298,8 +298,18 @@ static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
}
bool success = false;
- SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
- if (NULL != strm) {
+ if (NULL != bitmap) {
+ SkAutoLockPixels alp(*bitmap);
+
+ if (NULL == bitmap->getPixels()) {
+ return false;
+ }
+
+ SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+ if (NULL == strm) {
+ return false;
+ }
+
SkImageEncoder* encoder = SkImageEncoder::Create(fm);
if (NULL != encoder) {
success = encoder->encodeStream(strm, *bitmap, quality);
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 074afa3..21162f4 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -436,7 +436,7 @@ struct NativeCode : public ANativeActivity {
void setSurface(jobject _surface) {
if (_surface != NULL) {
- nativeWindow = android_Surface_getNativeWindow(env, _surface);
+ nativeWindow = android_view_Surface_getNativeWindow(env, _surface);
} else {
nativeWindow = NULL;
}
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index c271aeb..b1664c6 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -549,7 +549,7 @@ not_valid_surface:
goto exit;
}
- window = android::android_Surface_getNativeWindow(_env, win);
+ window = android::android_view_Surface_getNativeWindow(_env, win);
if (window == NULL)
goto not_valid_surface;
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bada329..4d5e680 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -18,15 +18,19 @@
#include <stdio.h>
+#include "android_os_Parcel.h"
#include "android_util_Binder.h"
#include "android/graphics/GraphicsJNI.h"
+#include "android/graphics/Region.h"
#include <binder/IMemory.h>
+#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceTexture.h>
+#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -41,127 +45,135 @@
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_view_SurfaceSession.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
#include <utils/misc.h>
+#include <ScopedUtfChars.h>
+
// ----------------------------------------------------------------------------
namespace android {
-enum {
- // should match Parcelable.java
- PARCELABLE_WRITE_RETURN_VALUE = 0x0001
-};
-
-// ----------------------------------------------------------------------------
-
static const char* const OutOfResourcesException =
"android/view/Surface$OutOfResourcesException";
-const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession";
-const char* const kSurfaceClassPathName = "android/view/Surface";
+static struct {
+ jclass clazz;
+ jfieldID mNativeSurface;
+ jfieldID mNativeSurfaceControl;
+ jfieldID mGenerationId;
+ jfieldID mCanvas;
+ jfieldID mCanvasSaveCount;
+} gSurfaceClassInfo;
+
+static struct {
+ jfieldID left;
+ jfieldID top;
+ jfieldID right;
+ jfieldID bottom;
+} gRectClassInfo;
+
+static struct {
+ jfieldID mNativeCanvas;
+ jfieldID mSurfaceFormat;
+} gCanvasClassInfo;
+
+static struct {
+ jfieldID width;
+ jfieldID height;
+ jfieldID refreshRate;
+ jfieldID density;
+ jfieldID xDpi;
+ jfieldID yDpi;
+} gPhysicalDisplayInfoClassInfo;
-struct sso_t {
- jfieldID client;
-};
-static sso_t sso;
-
-struct so_t {
- jfieldID surfaceControl;
- jfieldID surfaceGenerationId;
- jfieldID surface;
- jfieldID saveCount;
- jfieldID canvas;
-};
-static so_t so;
-struct ro_t {
- jfieldID l;
- jfieldID t;
- jfieldID r;
- jfieldID b;
-};
-static ro_t ro;
+class ScreenshotPixelRef : public SkPixelRef {
+public:
+ ScreenshotPixelRef(SkColorTable* ctable) {
+ fCTable = ctable;
+ SkSafeRef(ctable);
+ setImmutable();
+ }
-struct po_t {
- jfieldID x;
- jfieldID y;
-};
-static po_t po;
+ virtual ~ScreenshotPixelRef() {
+ SkSafeUnref(fCTable);
+ }
-struct co_t {
- jfieldID surfaceFormat;
-};
-static co_t co;
+ status_t update(const sp<IBinder>& display, int width, int height,
+ int minLayer, int maxLayer, bool allLayers) {
+ status_t res = (width > 0 && height > 0)
+ ? (allLayers
+ ? mScreenshot.update(display, width, height)
+ : mScreenshot.update(display, width, height, minLayer, maxLayer))
+ : mScreenshot.update(display);
+ if (res != NO_ERROR) {
+ return res;
+ }
-struct no_t {
- jfieldID native_canvas;
- jfieldID native_region;
- jfieldID native_parcel;
-};
-static no_t no;
+ return NO_ERROR;
+ }
+ uint32_t getWidth() const {
+ return mScreenshot.getWidth();
+ }
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
+ uint32_t getHeight() const {
+ return mScreenshot.getHeight();
+ }
-static void SurfaceSession_init(JNIEnv* env, jobject clazz)
-{
- sp<SurfaceComposerClient> client = new SurfaceComposerClient;
- client->incStrong(clazz);
- env->SetIntField(clazz, sso.client, (int)client.get());
-}
+ uint32_t getStride() const {
+ return mScreenshot.getStride();
+ }
-static void SurfaceSession_destroy(JNIEnv* env, jobject clazz)
-{
- SurfaceComposerClient* client =
- (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
- if (client != 0) {
- client->decStrong(clazz);
- env->SetIntField(clazz, sso.client, 0);
+ uint32_t getFormat() const {
+ return mScreenshot.getFormat();
}
-}
-static void SurfaceSession_kill(JNIEnv* env, jobject clazz)
-{
- SurfaceComposerClient* client =
- (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
- if (client != 0) {
- client->dispose();
- client->decStrong(clazz);
- env->SetIntField(clazz, sso.client, 0);
+protected:
+ // overrides from SkPixelRef
+ virtual void* onLockPixels(SkColorTable** ct) {
+ *ct = fCTable;
+ return (void*)mScreenshot.getPixels();
}
-}
+
+ virtual void onUnlockPixels() {
+ }
+
+private:
+ ScreenshotClient mScreenshot;
+ SkColorTable* fCTable;
+
+ typedef SkPixelRef INHERITED;
+};
+
// ----------------------------------------------------------------------------
-static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject clazz)
-{
- SurfaceControl* const p =
- (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
- return sp<SurfaceControl>(p);
+static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject surfaceObj) {
+ return reinterpret_cast<SurfaceControl*>(
+ env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
}
-static void setSurfaceControl(JNIEnv* env, jobject clazz,
- const sp<SurfaceControl>& surface)
-{
- SurfaceControl* const p =
- (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+static void setSurfaceControl(JNIEnv* env, jobject surfaceObj,
+ const sp<SurfaceControl>& surface) {
+ SurfaceControl* const p = reinterpret_cast<SurfaceControl*>(
+ env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
if (surface.get()) {
- surface->incStrong(clazz);
+ surface->incStrong(surfaceObj);
}
if (p) {
- p->decStrong(clazz);
+ p->decStrong(surfaceObj);
}
- env->SetIntField(clazz, so.surfaceControl, (int)surface.get());
+ env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl,
+ reinterpret_cast<jint>(surface.get()));
}
-static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
-{
- sp<Surface> result(Surface_getSurface(env, clazz));
- if (result == 0) {
+static sp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {
+ sp<Surface> result(android_view_Surface_getSurface(env, surfaceObj));
+ if (result == NULL) {
/*
* if this method is called from the WindowManager's process, it means
* the client is is not remote, and therefore is allowed to have
@@ -170,94 +182,81 @@ static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
* process.
*/
- SurfaceControl* const control =
- (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ SurfaceControl* const control = reinterpret_cast<SurfaceControl*>(
+ env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
if (control) {
result = control->getSurface();
- if (result != 0) {
- result->incStrong(clazz);
- env->SetIntField(clazz, so.surface, (int)result.get());
+ if (result != NULL) {
+ result->incStrong(surfaceObj);
+ env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
+ reinterpret_cast<jint>(result.get()));
}
}
}
return result;
}
-sp<ANativeWindow> android_Surface_getNativeWindow(
- JNIEnv* env, jobject clazz) {
- return getSurface(env, clazz);
+sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
+ return getSurface(env, surfaceObj);
}
-bool android_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
- jclass surfaceClass = env->FindClass(kSurfaceClassPathName);
- return env->IsInstanceOf(obj, surfaceClass);
+bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
+ return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
}
-sp<Surface> Surface_getSurface(JNIEnv* env, jobject clazz) {
- sp<Surface> surface((Surface*)env->GetIntField(clazz, so.surface));
- return surface;
+sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
+ return reinterpret_cast<Surface*>(
+ env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
}
-void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
-{
- Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
+static void setSurface(JNIEnv* env, jobject surfaceObj, const sp<Surface>& surface) {
+ Surface* const p = reinterpret_cast<Surface*>(
+ env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface));
if (surface.get()) {
- surface->incStrong(clazz);
+ surface->incStrong(surfaceObj);
}
if (p) {
- p->decStrong(clazz);
+ p->decStrong(surfaceObj);
}
- env->SetIntField(clazz, so.surface, (int)surface.get());
+ env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface,
+ reinterpret_cast<jint>(surface.get()));
+
// This test is conservative and it would be better to compare the ISurfaces
if (p && p != surface.get()) {
- jint generationId = env->GetIntField(clazz, so.surfaceGenerationId);
+ jint generationId = env->GetIntField(surfaceObj,
+ gSurfaceClassInfo.mGenerationId);
generationId++;
- env->SetIntField(clazz, so.surfaceGenerationId, generationId);
+ env->SetIntField(surfaceObj,
+ gSurfaceClassInfo.mGenerationId, generationId);
}
}
// ----------------------------------------------------------------------------
-static void Surface_init(
- JNIEnv* env, jobject clazz,
- jobject session,
- jint, jstring jname, jint layerStack, jint w, jint h, jint format, jint flags)
-{
- if (session == NULL) {
- doThrowNPE(env);
- return;
- }
-
- SurfaceComposerClient* client =
- (SurfaceComposerClient*)env->GetIntField(session, sso.client);
+static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
+ jstring nameStr, jint w, jint h, jint format, jint flags) {
+ ScopedUtfChars name(env, nameStr);
+ sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
- sp<SurfaceControl> surface;
- if (jname == NULL) {
- surface = client->createSurface(layerStack, w, h, format, flags);
- } else {
- const jchar* str = env->GetStringCritical(jname, 0);
- const String8 name(str, env->GetStringLength(jname));
- env->ReleaseStringCritical(jname, str);
- surface = client->createSurface(name, layerStack, w, h, format, flags);
- }
-
- if (surface == 0) {
+ sp<SurfaceControl> surface = client->createSurface(
+ String8(name.c_str()), w, h, format, flags);
+ if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return;
}
- setSurfaceControl(env, clazz, surface);
-}
-static void Surface_initFromSurfaceTexture(
- JNIEnv* env, jobject clazz, jobject jst)
-{
- sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, jst));
+ setSurfaceControl(env, surfaceObj, surface);
+}
+static void nativeCreateFromSurfaceTexture(JNIEnv* env, jobject surfaceObj,
+ jobject surfaceTextureObj) {
+ sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
if (st == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"SurfaceTexture has already been released");
return;
}
+
sp<ISurfaceTexture> bq = st->getBufferQueue();
sp<Surface> surface(new Surface(bq));
@@ -265,72 +264,62 @@ static void Surface_initFromSurfaceTexture(
jniThrowException(env, OutOfResourcesException, NULL);
return;
}
- setSurfaceControl(env, clazz, NULL);
- setSurface(env, clazz, surface);
-}
-static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
-{
- Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);
- if (parcel == NULL) {
- doThrowNPE(env);
- return;
- }
-
- sp<Surface> sur(Surface::readFromParcel(*parcel));
- setSurface(env, clazz, sur);
+ setSurface(env, surfaceObj, surface);
}
-static jint Surface_getIdentity(JNIEnv* env, jobject clazz)
-{
- const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
- if (control != 0) return (jint) control->getIdentity();
- const sp<Surface>& surface(getSurface(env, clazz));
- if (surface != 0) return (jint) surface->getIdentity();
- return -1;
+static void nativeRelease(JNIEnv* env, jobject surfaceObj) {
+ setSurfaceControl(env, surfaceObj, NULL);
+ setSurface(env, surfaceObj, NULL);
}
-static void Surface_destroy(JNIEnv* env, jobject clazz, uintptr_t *ostack)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (SurfaceControl::isValid(surface)) {
- surface->clear();
+static void nativeDestroy(JNIEnv* env, jobject surfaceObj) {
+ sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
+ if (SurfaceControl::isValid(surfaceControl)) {
+ surfaceControl->clear();
}
- setSurfaceControl(env, clazz, 0);
- setSurface(env, clazz, 0);
+ setSurfaceControl(env, surfaceObj, NULL);
+ setSurface(env, surfaceObj, NULL);
}
-static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack)
-{
- setSurfaceControl(env, clazz, 0);
- setSurface(env, clazz, 0);
-}
-
-static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
-{
- const sp<SurfaceControl>& surfaceControl(getSurfaceControl(env, clazz));
- if (surfaceControl != 0) {
+static jboolean nativeIsValid(JNIEnv* env, jobject surfaceObj) {
+ sp<SurfaceControl> surfaceControl(getSurfaceControl(env, surfaceObj));
+ if (surfaceControl != NULL) {
return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
}
- const sp<Surface>& surface(getSurface(env, clazz));
+
+ sp<Surface> surface(getSurface(env, surfaceObj));
return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean Surface_isConsumerRunningBehind(JNIEnv* env, jobject clazz)
-{
- int value = 0;
- const sp<Surface>& surface(getSurface(env, clazz));
+static jint nativeGetIdentity(JNIEnv* env, jobject surfaceObj) {
+ sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
+ if (control != NULL) {
+ return jint(control->getIdentity());
+ }
+
+ sp<Surface> surface(getSurface(env, surfaceObj));
+ if (surface != NULL) {
+ return jint(surface->getIdentity());
+ }
+
+ return -1;
+}
+
+static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jobject surfaceObj) {
+ sp<Surface> surface(getSurface(env, surfaceObj));
if (!Surface::isValid(surface)) {
doThrowIAE(env);
- return 0;
+ return JNI_FALSE;
}
- ANativeWindow* anw = static_cast<ANativeWindow *>(surface.get());
+
+ int value = 0;
+ ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
- return (jboolean)value;
+ return value;
}
-static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
-{
+static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
/* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
we can map to SkBitmap::kARGB_8888_Config, and optionally call
bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
@@ -345,44 +334,44 @@ static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
}
}
-static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
-{
- const sp<Surface>& surface(getSurface(env, clazz));
+static jobject nativeLockCanvas(JNIEnv* env, jobject surfaceObj, jobject dirtyRectObj) {
+ sp<Surface> surface(getSurface(env, surfaceObj));
if (!Surface::isValid(surface)) {
doThrowIAE(env);
- return 0;
+ return NULL;
}
// get dirty region
Region dirtyRegion;
- if (dirtyRect) {
+ if (dirtyRectObj) {
Rect dirty;
- dirty.left = env->GetIntField(dirtyRect, ro.l);
- dirty.top = env->GetIntField(dirtyRect, ro.t);
- dirty.right = env->GetIntField(dirtyRect, ro.r);
- dirty.bottom= env->GetIntField(dirtyRect, ro.b);
+ dirty.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
+ dirty.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
+ dirty.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
+ dirty.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
if (!dirty.isEmpty()) {
dirtyRegion.set(dirty);
}
} else {
- dirtyRegion.set(Rect(0x3FFF,0x3FFF));
+ dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
}
Surface::SurfaceInfo info;
status_t err = surface->lock(&info, &dirtyRegion);
if (err < 0) {
const char* const exception = (err == NO_MEMORY) ?
- OutOfResourcesException :
- "java/lang/IllegalArgumentException";
+ OutOfResourcesException :
+ "java/lang/IllegalArgumentException";
jniThrowException(env, exception, NULL);
- return 0;
+ return NULL;
}
// Associate a SkCanvas object to this surface
- jobject canvas = env->GetObjectField(clazz, so.canvas);
- env->SetIntField(canvas, co.surfaceFormat, info.format);
+ jobject canvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
+ env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, info.format);
- SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
+ SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
+ env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
SkBitmap bitmap;
ssize_t bpr = info.s * bytesPerPixel(info.format);
bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
@@ -413,38 +402,38 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
nativeCanvas->clipRegion(clipReg);
int saveCount = nativeCanvas->save();
- env->SetIntField(clazz, so.saveCount, saveCount);
+ env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, saveCount);
- if (dirtyRect) {
+ if (dirtyRectObj) {
const Rect& bounds(dirtyRegion.getBounds());
- env->SetIntField(dirtyRect, ro.l, bounds.left);
- env->SetIntField(dirtyRect, ro.t, bounds.top);
- env->SetIntField(dirtyRect, ro.r, bounds.right);
- env->SetIntField(dirtyRect, ro.b, bounds.bottom);
+ env->SetIntField(dirtyRectObj, gRectClassInfo.left, bounds.left);
+ env->SetIntField(dirtyRectObj, gRectClassInfo.top, bounds.top);
+ env->SetIntField(dirtyRectObj, gRectClassInfo.right, bounds.right);
+ env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, bounds.bottom);
}
- return canvas;
+ return canvasObj;
}
-static void Surface_unlockCanvasAndPost(
- JNIEnv* env, jobject clazz, jobject argCanvas)
-{
- jobject canvas = env->GetObjectField(clazz, so.canvas);
- if (env->IsSameObject(canvas, argCanvas) == JNI_FALSE) {
+static void nativeUnlockCanvasAndPost(JNIEnv* env, jobject surfaceObj, jobject canvasObj) {
+ jobject ownCanvasObj = env->GetObjectField(surfaceObj, gSurfaceClassInfo.mCanvas);
+ if (!env->IsSameObject(ownCanvasObj, canvasObj)) {
doThrowIAE(env);
return;
}
- const sp<Surface>& surface(getSurface(env, clazz));
- if (!Surface::isValid(surface))
+ sp<Surface> surface(getSurface(env, surfaceObj));
+ if (!Surface::isValid(surface)) {
return;
+ }
// detach the canvas from the surface
- SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
- int saveCount = env->GetIntField(clazz, so.saveCount);
+ SkCanvas* nativeCanvas = reinterpret_cast<SkCanvas*>(
+ env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
+ int saveCount = env->GetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount);
nativeCanvas->restoreToCount(saveCount);
nativeCanvas->setBitmapDevice(SkBitmap());
- env->SetIntField(clazz, so.saveCount, 0);
+ env->SetIntField(surfaceObj, gSurfaceClassInfo.mCanvasSaveCount, 0);
// unlock surface
status_t err = surface->unlockAndPost();
@@ -453,98 +442,18 @@ static void Surface_unlockCanvasAndPost(
}
}
-static void Surface_unlockCanvas(
- JNIEnv* env, jobject clazz, jobject argCanvas)
-{
- // XXX: this API has been removed
- doThrowIAE(env);
-}
-
-static void Surface_openTransaction(
- JNIEnv* env, jobject clazz)
-{
- SurfaceComposerClient::openGlobalTransaction();
-}
-
-static void Surface_closeTransaction(
- JNIEnv* env, jobject clazz)
-{
- SurfaceComposerClient::closeGlobalTransaction();
-}
-
-static void Surface_setOrientation(
- JNIEnv* env, jobject clazz, jint display, jint orientation)
-{
- int err = SurfaceComposerClient::setOrientation(display, orientation, 0);
- if (err < 0) {
- doThrowIAE(env);
+static jobject nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
+ jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
+ sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
+ if (displayToken == NULL) {
+ return NULL;
}
-}
-class ScreenshotPixelRef : public SkPixelRef {
-public:
- ScreenshotPixelRef(SkColorTable* ctable) {
- fCTable = ctable;
- SkSafeRef(ctable);
- setImmutable();
- }
- virtual ~ScreenshotPixelRef() {
- SkSafeUnref(fCTable);
- }
-
- status_t update(int width, int height, int minLayer, int maxLayer, bool allLayers) {
- status_t res = (width > 0 && height > 0)
- ? (allLayers
- ? mScreenshot.update(width, height)
- : mScreenshot.update(width, height, minLayer, maxLayer))
- : mScreenshot.update();
- if (res != NO_ERROR) {
- return res;
- }
-
- return NO_ERROR;
- }
-
- uint32_t getWidth() const {
- return mScreenshot.getWidth();
- }
-
- uint32_t getHeight() const {
- return mScreenshot.getHeight();
- }
-
- uint32_t getStride() const {
- return mScreenshot.getStride();
- }
-
- uint32_t getFormat() const {
- return mScreenshot.getFormat();
- }
-
-protected:
- // overrides from SkPixelRef
- virtual void* onLockPixels(SkColorTable** ct) {
- *ct = fCTable;
- return (void*)mScreenshot.getPixels();
- }
-
- virtual void onUnlockPixels() {
- }
-
-private:
- ScreenshotClient mScreenshot;
- SkColorTable* fCTable;
-
- typedef SkPixelRef INHERITED;
-};
-
-static jobject doScreenshot(JNIEnv* env, jobject clazz, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers)
-{
ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
- if (pixels->update(width, height, minLayer, maxLayer, allLayers) != NO_ERROR) {
+ if (pixels->update(displayToken, width, height,
+ minLayer, maxLayer, allLayers) != NO_ERROR) {
delete pixels;
- return 0;
+ return NULL;
}
uint32_t w = pixels->getWidth();
@@ -571,94 +480,68 @@ static jobject doScreenshot(JNIEnv* env, jobject clazz, jint width, jint height,
return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
}
-static jobject Surface_screenshotAll(JNIEnv* env, jobject clazz, jint width, jint height)
-{
- return doScreenshot(env, clazz, width, height, 0, 0, true);
+static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
+ SurfaceComposerClient::openGlobalTransaction();
}
-static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height,
- jint minLayer, jint maxLayer)
-{
- return doScreenshot(env, clazz, width, height, minLayer, maxLayer, false);
+static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
+ SurfaceComposerClient::closeGlobalTransaction();
}
-static void Surface_setLayer(
- JNIEnv* env, jobject clazz, jint zorder)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
+static void nativeSetLayer(JNIEnv* env, jobject surfaceObj, jint zorder) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
status_t err = surface->setLayer(zorder);
- if (err<0 && err!=NO_INIT) {
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setPosition(
- JNIEnv* env, jobject clazz, jfloat x, jfloat y)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
+static void nativeSetPosition(JNIEnv* env, jobject surfaceObj, jfloat x, jfloat y) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
status_t err = surface->setPosition(x, y);
- if (err<0 && err!=NO_INIT) {
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setSize(
- JNIEnv* env, jobject clazz, jint w, jint h)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
+static void nativeSetSize(JNIEnv* env, jobject surfaceObj, jint w, jint h) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
status_t err = surface->setSize(w, h);
- if (err<0 && err!=NO_INIT) {
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_hide(
- JNIEnv* env, jobject clazz)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
- status_t err = surface->hide();
- if (err<0 && err!=NO_INIT) {
- doThrowIAE(env);
- }
-}
+static void nativeSetFlags(JNIEnv* env, jobject surfaceObj, jint flags, jint mask) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
-static void Surface_show(
- JNIEnv* env, jobject clazz)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
- status_t err = surface->show();
- if (err<0 && err!=NO_INIT) {
+ status_t err = surface->setFlags(flags, mask);
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setFlags(
- JNIEnv* env, jobject clazz, jint flags, jint mask)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
- status_t err = surface->setFlags(flags, mask);
- if (err<0 && err!=NO_INIT) {
+static void nativeSetTransparentRegionHint(JNIEnv* env, jobject surfaceObj, jobject regionObj) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
+ SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+ if (!region) {
doThrowIAE(env);
+ return;
}
-}
-
-static void Surface_setTransparentRegion(
- JNIEnv* env, jobject clazz, jobject argRegion)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
- SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
- const SkIRect& b(nativeRegion->getBounds());
+ const SkIRect& b(region->getBounds());
Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
- if (nativeRegion->isComplex()) {
- SkRegion::Iterator it(*nativeRegion);
+ if (region->isComplex()) {
+ SkRegion::Iterator it(*region);
while (!it.done()) {
const SkIRect& r(it.rect());
reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
@@ -667,130 +550,197 @@ static void Surface_setTransparentRegion(
}
status_t err = surface->setTransparentRegionHint(reg);
- if (err<0 && err!=NO_INIT) {
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setAlpha(
- JNIEnv* env, jobject clazz, jfloat alpha)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
+static void nativeSetAlpha(JNIEnv* env, jobject surfaceObj, jfloat alpha) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
status_t err = surface->setAlpha(alpha);
- if (err<0 && err!=NO_INIT) {
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setMatrix(
- JNIEnv* env, jobject clazz,
- jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
- if (surface == 0) return;
+static void nativeSetMatrix(JNIEnv* env, jobject surfaceObj,
+ jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
- if (err<0 && err!=NO_INIT) {
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setWindowCrop(JNIEnv* env, jobject thiz, jobject crop)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, thiz));
- if (surface == 0) return;
-
- Rect nativeCrop;
- if (crop) {
- nativeCrop.left = env->GetIntField(crop, ro.l);
- nativeCrop.top = env->GetIntField(crop, ro.t);
- nativeCrop.right = env->GetIntField(crop, ro.r);
- nativeCrop.bottom= env->GetIntField(crop, ro.b);
+static void nativeSetWindowCrop(JNIEnv* env, jobject surfaceObj, jobject cropObj) {
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
+
+ Rect crop;
+ if (cropObj) {
+ crop.left = env->GetIntField(cropObj, gRectClassInfo.left);
+ crop.top = env->GetIntField(cropObj, gRectClassInfo.top);
+ crop.right = env->GetIntField(cropObj, gRectClassInfo.right);
+ crop.bottom = env->GetIntField(cropObj, gRectClassInfo.bottom);
} else {
- nativeCrop.left = nativeCrop.top = nativeCrop.right =
- nativeCrop.bottom = 0;
+ crop.left = crop.top = crop.right = crop.bottom = 0;
}
- status_t err = surface->setCrop(nativeCrop);
- if (err<0 && err!=NO_INIT) {
+ status_t err = surface->setCrop(crop);
+ if (err < 0 && err != NO_INIT) {
doThrowIAE(env);
}
}
-static void Surface_setLayerStack(JNIEnv* env, jobject thiz, jint layerStack)
-{
- const sp<SurfaceControl>& surface(getSurfaceControl(env, thiz));
- if (surface == 0) return;
+static void nativeSetLayerStack(JNIEnv* env, jobject surfaceObj, jint layerStack) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ if (surface == NULL) return;
- // TODO(mathias): Everything.
+ status_t err = surface->setLayerStack(layerStack);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
}
-// ----------------------------------------------------------------------------
+static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
+ sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
+ return javaObjectForIBinder(env, token);
+}
-static void Surface_copyFrom(
- JNIEnv* env, jobject clazz, jobject other)
-{
- if (clazz == other)
+static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj) {
+ ScopedUtfChars name(env, nameObj);
+ // TODO: pass the name to SF.
+ sp<IBinder> token(SurfaceComposerClient::createDisplay());
+ return javaObjectForIBinder(env, token);
+}
+
+static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jobject surfaceTextureObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ if (!surfaceTextureObj) {
+ SurfaceComposerClient::setDisplaySurface(token, NULL);
return;
+ }
- if (other == NULL) {
- doThrowNPE(env);
+ sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
+ if (st == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "SurfaceTexture has already been released");
return;
}
+ sp<ISurfaceTexture> bq = st->getBufferQueue();
+ SurfaceComposerClient::setDisplaySurface(token, bq);
+}
+
+static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jint layerStack) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
+}
+
+static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jint orientation) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ SurfaceComposerClient::setDisplayOrientation(token, orientation);
+}
+
+static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jobject rectObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ Rect rect;
+ rect.left = env->GetIntField(rectObj, gRectClassInfo.left);
+ rect.top = env->GetIntField(rectObj, gRectClassInfo.top);
+ rect.right = env->GetIntField(rectObj, gRectClassInfo.right);
+ rect.bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
+ SurfaceComposerClient::setDisplayViewport(token, rect);
+}
+
+static void nativeSetDisplayFrame(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jobject rectObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return;
+
+ Rect rect;
+ rect.left = env->GetIntField(rectObj, gRectClassInfo.left);
+ rect.top = env->GetIntField(rectObj, gRectClassInfo.top);
+ rect.right = env->GetIntField(rectObj, gRectClassInfo.right);
+ rect.bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
+ SurfaceComposerClient::setDisplayFrame(token, rect);
+}
+
+static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jobject infoObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return JNI_FALSE;
+
+ DisplayInfo info;
+ if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
+ return JNI_FALSE;
+ }
+
+ env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
+ env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
+ return JNI_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+static void nativeCopyFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
/*
* This is used by the WindowManagerService just after constructing
* a Surface and is necessary for returning the Surface reference to
* the caller. At this point, we should only have a SurfaceControl.
*/
- const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
- const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
- if (!SurfaceControl::isSameSurface(surface, rhs)) {
+ sp<SurfaceControl> surface(getSurfaceControl(env, surfaceObj));
+ sp<SurfaceControl> other(getSurfaceControl(env, otherObj));
+ if (!SurfaceControl::isSameSurface(surface, other)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
- setSurfaceControl(env, clazz, rhs);
+ setSurfaceControl(env, surfaceObj, other);
}
}
-static void Surface_transferFrom(
- JNIEnv* env, jobject clazz, jobject other)
-{
- if (clazz == other)
- return;
-
- if (other == NULL) {
- doThrowNPE(env);
- return;
- }
-
- sp<SurfaceControl> control(getSurfaceControl(env, other));
- sp<Surface> surface(Surface_getSurface(env, other));
- setSurfaceControl(env, clazz, control);
- setSurface(env, clazz, surface);
- setSurfaceControl(env, other, 0);
- setSurface(env, other, 0);
+static void nativeTransferFrom(JNIEnv* env, jobject surfaceObj, jobject otherObj) {
+ sp<SurfaceControl> control(getSurfaceControl(env, otherObj));
+ sp<Surface> surface(android_view_Surface_getSurface(env, otherObj));
+ setSurfaceControl(env, surfaceObj, control);
+ setSurface(env, surfaceObj, surface);
+ setSurfaceControl(env, otherObj, NULL);
+ setSurface(env, otherObj, NULL);
}
-static void Surface_readFromParcel(
- JNIEnv* env, jobject clazz, jobject argParcel)
-{
- Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);
+static void nativeReadFromParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return;
}
- sp<Surface> sur(Surface::readFromParcel(*parcel));
- setSurface(env, clazz, sur);
+ sp<Surface> surface(Surface::readFromParcel(*parcel));
+ setSurfaceControl(env, surfaceObj, NULL);
+ setSurface(env, surfaceObj, surface);
}
-static void Surface_writeToParcel(
- JNIEnv* env, jobject clazz, jobject argParcel, jint flags)
-{
- Parcel* parcel = (Parcel*)env->GetIntField(
- argParcel, no.native_parcel);
-
+static void nativeWriteToParcel(JNIEnv* env, jobject surfaceObj, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return;
@@ -802,110 +752,125 @@ static void Surface_writeToParcel(
// available we let it parcel itself. Finally, if the Surface is also
// NULL we fall back to using the SurfaceControl path which sends an
// empty surface; this matches legacy behavior.
- const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
+ sp<SurfaceControl> control(getSurfaceControl(env, surfaceObj));
if (control != NULL) {
SurfaceControl::writeSurfaceToParcel(control, parcel);
} else {
- sp<Surface> surface(Surface_getSurface(env, clazz));
+ sp<Surface> surface(android_view_Surface_getSurface(env, surfaceObj));
if (surface != NULL) {
Surface::writeToParcel(surface, parcel);
} else {
SurfaceControl::writeSurfaceToParcel(NULL, parcel);
}
}
- if (flags & PARCELABLE_WRITE_RETURN_VALUE) {
- setSurfaceControl(env, clazz, NULL);
- setSurface(env, clazz, NULL);
- }
}
// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-static void nativeClassInit(JNIEnv* env, jclass clazz);
-
-static JNINativeMethod gSurfaceSessionMethods[] = {
- {"init", "()V", (void*)SurfaceSession_init },
- {"destroy", "()V", (void*)SurfaceSession_destroy },
- {"kill", "()V", (void*)SurfaceSession_kill },
-};
static JNINativeMethod gSurfaceMethods[] = {
- {"nativeClassInit", "()V", (void*)nativeClassInit },
- {"init", "(Landroid/view/SurfaceSession;ILjava/lang/String;IIIII)V", (void*)Surface_init },
- {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
- {"initFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V", (void*)Surface_initFromSurfaceTexture },
- {"getIdentity", "()I", (void*)Surface_getIdentity },
- {"destroy", "()V", (void*)Surface_destroy },
- {"release", "()V", (void*)Surface_release },
- {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
- {"transferFrom", "(Landroid/view/Surface;)V", (void*)Surface_transferFrom },
- {"isValid", "()Z", (void*)Surface_isValid },
- {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
- {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost },
- {"unlockCanvas", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvas },
- {"openTransaction", "()V", (void*)Surface_openTransaction },
- {"closeTransaction", "()V", (void*)Surface_closeTransaction },
- {"setOrientation", "(II)V", (void*)Surface_setOrientation },
- {"screenshot", "(II)Landroid/graphics/Bitmap;", (void*)Surface_screenshotAll },
- {"screenshot", "(IIII)Landroid/graphics/Bitmap;", (void*)Surface_screenshot },
- {"setLayer", "(I)V", (void*)Surface_setLayer },
- {"setPosition", "(FF)V",(void*)Surface_setPosition },
- {"setSize", "(II)V",(void*)Surface_setSize },
- {"hide", "()V", (void*)Surface_hide },
- {"show", "()V", (void*)Surface_show },
- {"setFlags", "(II)V",(void*)Surface_setFlags },
- {"setTransparentRegionHint","(Landroid/graphics/Region;)V", (void*)Surface_setTransparentRegion },
- {"setAlpha", "(F)V", (void*)Surface_setAlpha },
- {"setMatrix", "(FFFF)V", (void*)Surface_setMatrix },
- {"readFromParcel", "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel },
- {"writeToParcel", "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
- {"isConsumerRunningBehind", "()Z", (void*)Surface_isConsumerRunningBehind },
- {"setWindowCrop", "(Landroid/graphics/Rect;)V", (void*)Surface_setWindowCrop },
- {"setLayerStack", "(I)V", (void*)Surface_setLayerStack },
+ {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)V",
+ (void*)nativeCreate },
+ {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V",
+ (void*)nativeCreateFromSurfaceTexture },
+ {"nativeRelease", "()V",
+ (void*)nativeRelease },
+ {"nativeDestroy", "()V",
+ (void*)nativeDestroy },
+ {"nativeIsValid", "()Z",
+ (void*)nativeIsValid },
+ {"nativeGetIdentity", "()I",
+ (void*)nativeGetIdentity },
+ {"nativeIsConsumerRunningBehind", "()Z",
+ (void*)nativeIsConsumerRunningBehind },
+ {"nativeLockCanvas", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;",
+ (void*)nativeLockCanvas },
+ {"nativeUnlockCanvasAndPost", "(Landroid/graphics/Canvas;)V",
+ (void*)nativeUnlockCanvasAndPost },
+ {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
+ (void*)nativeScreenshot },
+ {"nativeOpenTransaction", "()V",
+ (void*)nativeOpenTransaction },
+ {"nativeCloseTransaction", "()V",
+ (void*)nativeCloseTransaction },
+ {"nativeSetLayer", "(I)V",
+ (void*)nativeSetLayer },
+ {"nativeSetPosition", "(FF)V",
+ (void*)nativeSetPosition },
+ {"nativeSetSize", "(II)V",
+ (void*)nativeSetSize },
+ {"nativeSetTransparentRegionHint", "(Landroid/graphics/Region;)V",
+ (void*)nativeSetTransparentRegionHint },
+ {"nativeSetAlpha", "(F)V",
+ (void*)nativeSetAlpha },
+ {"nativeSetMatrix", "(FFFF)V",
+ (void*)nativeSetMatrix },
+ {"nativeSetFlags", "(II)V",
+ (void*)nativeSetFlags },
+ {"nativeSetWindowCrop", "(Landroid/graphics/Rect;)V",
+ (void*)nativeSetWindowCrop },
+ {"nativeSetLayerStack", "(I)V",
+ (void*)nativeSetLayerStack },
+ {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
+ (void*)nativeGetBuiltInDisplay },
+ {"nativeCreateDisplay", "(Ljava/lang/String;)Landroid/os/IBinder;",
+ (void*)nativeCreateDisplay },
+ {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/graphics/SurfaceTexture;)V",
+ (void*)nativeSetDisplaySurface },
+ {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
+ (void*)nativeSetDisplayLayerStack },
+ {"nativeSetDisplayOrientation", "(Landroid/os/IBinder;I)V",
+ (void*)nativeSetDisplayOrientation },
+ {"nativeSetDisplayViewport", "(Landroid/os/IBinder;Landroid/graphics/Rect;)V",
+ (void*)nativeSetDisplayViewport },
+ {"nativeSetDisplayFrame", "(Landroid/os/IBinder;Landroid/graphics/Rect;)V",
+ (void*)nativeSetDisplayFrame },
+ {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/Surface$PhysicalDisplayInfo;)Z",
+ (void*)nativeGetDisplayInfo },
+ {"nativeCopyFrom", "(Landroid/view/Surface;)V",
+ (void*)nativeCopyFrom },
+ {"nativeTransferFrom", "(Landroid/view/Surface;)V",
+ (void*)nativeTransferFrom },
+ {"nativeReadFromParcel", "(Landroid/os/Parcel;)V",
+ (void*)nativeReadFromParcel },
+ {"nativeWriteToParcel", "(Landroid/os/Parcel;)V",
+ (void*)nativeWriteToParcel },
};
-void nativeClassInit(JNIEnv* env, jclass clazz)
-{
- so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
- so.surfaceGenerationId = env->GetFieldID(clazz, "mSurfaceGenerationId", "I");
- so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
- so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
- so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
-
- jclass surfaceSession = env->FindClass("android/view/SurfaceSession");
- sso.client = env->GetFieldID(surfaceSession, "mClient", "I");
-
- jclass canvas = env->FindClass("android/graphics/Canvas");
- no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I");
- co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I");
-
- jclass region = env->FindClass("android/graphics/Region");
- no.native_region = env->GetFieldID(region, "mNativeRegion", "I");
-
- jclass parcel = env->FindClass("android/os/Parcel");
- no.native_parcel = env->GetFieldID(parcel, "mNativePtr", "I");
-
- jclass rect = env->FindClass("android/graphics/Rect");
- ro.l = env->GetFieldID(rect, "left", "I");
- ro.t = env->GetFieldID(rect, "top", "I");
- ro.r = env->GetFieldID(rect, "right", "I");
- ro.b = env->GetFieldID(rect, "bottom", "I");
-
- jclass point = env->FindClass("android/graphics/Point");
- po.x = env->GetFieldID(point, "x", "I");
- po.y = env->GetFieldID(point, "y", "I");
-}
-
int register_android_view_Surface(JNIEnv* env)
{
- int err;
- err = AndroidRuntime::registerNativeMethods(env, kSurfaceSessionClassPathName,
- gSurfaceSessionMethods, NELEM(gSurfaceSessionMethods));
-
- err |= AndroidRuntime::registerNativeMethods(env, kSurfaceClassPathName,
+ int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
gSurfaceMethods, NELEM(gSurfaceMethods));
+
+ jclass clazz = env->FindClass("android/view/Surface");
+ gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
+ gSurfaceClassInfo.mNativeSurface =
+ env->GetFieldID(gSurfaceClassInfo.clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+ gSurfaceClassInfo.mNativeSurfaceControl =
+ env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeSurfaceControl", "I");
+ gSurfaceClassInfo.mGenerationId =
+ env->GetFieldID(gSurfaceClassInfo.clazz, "mGenerationId", "I");
+ gSurfaceClassInfo.mCanvas =
+ env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
+ gSurfaceClassInfo.mCanvasSaveCount =
+ env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
+
+ clazz = env->FindClass("android/graphics/Canvas");
+ gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
+ gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
+
+ clazz = env->FindClass("android/graphics/Rect");
+ gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
+ gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
+ gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
+ gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
+
+ clazz = env->FindClass("android/view/Surface$PhysicalDisplayInfo");
+ gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
+ gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
+ gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
+ gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
+ gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
+ gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
return err;
}
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
new file mode 100644
index 0000000..1494bc5
--- /dev/null
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceSession"
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_SurfaceSession.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include <gui/SurfaceComposerClient.h>
+
+namespace android {
+
+static struct {
+ jfieldID mNativeClient;
+} gSurfaceSessionClassInfo;
+
+
+sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
+ JNIEnv* env, jobject surfaceSessionObj) {
+ return reinterpret_cast<SurfaceComposerClient*>(
+ env->GetIntField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
+}
+
+
+static jint nativeCreate(JNIEnv* env, jclass clazz) {
+ SurfaceComposerClient* client = new SurfaceComposerClient();
+ client->incStrong(clazz);
+ return reinterpret_cast<jint>(client);
+}
+
+static void nativeDestroy(JNIEnv* env, jclass clazz, jint ptr) {
+ SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
+ client->decStrong(clazz);
+}
+
+static void nativeKill(JNIEnv* env, jclass clazz, jint ptr) {
+ SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
+ client->dispose();
+}
+
+
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeCreate", "()I",
+ (void*)nativeCreate },
+ { "nativeDestroy", "(I)V",
+ (void*)nativeDestroy },
+ { "nativeKill", "(I)V",
+ (void*)nativeKill }
+};
+
+int register_android_view_SurfaceSession(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "android/view/SurfaceSession",
+ gMethods, NELEM(gMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz = env->FindClass("android/view/SurfaceSession");
+ gSurfaceSessionClassInfo.mNativeClient = env->GetFieldID(clazz, "mNativeClient", "I");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 9c6c7de..f8904bd 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -326,7 +326,7 @@ not_valid_surface:
return 0;
}
- window = android_Surface_getNativeWindow(_env, native_window);
+ window = android_view_Surface_getNativeWindow(_env, native_window);
if (window == NULL)
goto not_valid_surface;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1c9b440..abb9c0f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -62,6 +62,7 @@
<protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
<protected-broadcast android:name="android.intent.action.USER_ADDED" />
<protected-broadcast android:name="android.intent.action.USER_REMOVED" />
+ <protected-broadcast android:name="android.intent.action.USER_STOPPED" />
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
@@ -724,6 +725,13 @@
android:description="@string/permdesc_mediaStorageWrite"
android:protectionLevel="signature|system" />
+ <!-- Allows an application to access all multi-user external storage @hide -->
+ <permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE"
+ android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
+ android:label="@string/permlab_sdcardAccessAll"
+ android:description="@string/permdesc_sdcardAccessAll"
+ android:protectionLevel="signature" />
+
<!-- ============================================ -->
<!-- Permissions for low-level system interaction -->
<!-- ============================================ -->
@@ -1662,7 +1670,6 @@
<!-- Package verifier needs to have this permission before the PackageManager will
trust it to verify packages.
- @hide
-->
<permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
android:label="@string/permlab_packageVerificationAgent"
diff --git a/core/res/res/anim/keyguard_security_animate_in.xml b/core/res/res/anim/keyguard_security_animate_in.xml
new file mode 100644
index 0000000..6e1e17a
--- /dev/null
+++ b/core/res/res/anim/keyguard_security_animate_in.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false">
+
+ <scale
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromXScale="0.0"
+ android:toXScale="1.0"
+ android:fromYScale="1.0"
+ android:toYScale="1.0"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillAfter="true"
+ android:duration="@integer/flip_duration"
+ android:startOffset="@integer/flip_duration" />
+
+</set>
+
diff --git a/core/res/res/anim/keyguard_security_animate_out.xml b/core/res/res/anim/keyguard_security_animate_out.xml
new file mode 100644
index 0000000..5d65cd0
--- /dev/null
+++ b/core/res/res/anim/keyguard_security_animate_out.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false">
+
+ <scale
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:fromXScale="1.0"
+ android:toXScale="0.0"
+ android:fromYScale="1.0"
+ android:toYScale="1.0"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillAfter="true"
+ android:duration="@integer/flip_duration" />
+
+</set>
+
diff --git a/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_left.9.png b/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_left.9.png
new file mode 100644
index 0000000..c30eb1c
--- /dev/null
+++ b/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_right.9.png b/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_right.9.png
new file mode 100644
index 0000000..e5d5771
--- /dev/null
+++ b/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_right.9.png
Binary files differ
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
new file mode 100644
index 0000000..b404155
--- /dev/null
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+ and the security view. -->
+<com.android.internal.policy.impl.keyguard.KeyguardHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_host_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
+ android:id="@+id/app_widget_container"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="gone">
+
+ <!-- TODO: Remove this once supported as a widget -->
+ <include layout="@layout/keyguard_status_view"/>
+ </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
+
+
+ <ViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center">
+
+ <include layout="@layout/keyguard_selector_view"/>
+ <include layout="@layout/keyguard_account_view"/>
+ <include layout="@layout/keyguard_pattern_view"/>
+ <include layout="@layout/keyguard_password_view"/>
+ <include layout="@layout/keyguard_sim_pin_view"/>
+ <include layout="@layout/keyguard_sim_puk_view"/>
+ <include layout="@layout/keyguard_face_unlock_view"/>
+
+ </ViewFlipper>
+
+</com.android.internal.policy.impl.keyguard.KeyguardHostView>
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
new file mode 100644
index 0000000..5dc2225
--- /dev/null
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+ and the security view. -->
+<com.android.internal.policy.impl.keyguard.KeyguardHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_host_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:clipChildren="false">
+
+ <ViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <include layout="@layout/keyguard_selector_view"/>
+ <include layout="@layout/keyguard_account_view"/>
+ <include layout="@layout/keyguard_pattern_view"/>
+ <include layout="@layout/keyguard_password_view"/>
+ <include layout="@layout/keyguard_sim_pin_view"/>
+ <include layout="@layout/keyguard_sim_puk_view"/>
+ <include layout="@layout/keyguard_face_unlock_view"/>
+
+ </ViewFlipper>
+
+</com.android.internal.policy.impl.keyguard.KeyguardHostView>
+
diff --git a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
new file mode 100644
index 0000000..e77f584
--- /dev/null
+++ b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+ and the security view. -->
+<com.android.internal.policy.impl.keyguard.KeyguardHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_host_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
+ android:id="@+id/app_widget_container"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="gone">
+
+ <!-- TODO: Remove this once supported as a widget -->
+ <include layout="@layout/keyguard_status_view"/>
+
+ </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
+
+ <FrameLayout
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center">
+
+ <ViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_width="@dimen/kg_security_view_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:gravity="center">
+
+ <include layout="@layout/keyguard_selector_view"/>
+ <include layout="@layout/keyguard_account_view"/>
+ <include layout="@layout/keyguard_pattern_view"/>
+ <include layout="@layout/keyguard_password_view"/>
+ <include layout="@layout/keyguard_sim_pin_view"/>
+ <include layout="@layout/keyguard_sim_puk_view"/>
+ <include layout="@layout/keyguard_face_unlock_view"/>
+
+ </ViewFlipper>
+
+ </FrameLayout>
+
+</com.android.internal.policy.impl.keyguard.KeyguardHostView>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
new file mode 100644
index 0000000..50636f1
--- /dev/null
+++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+ and the security view. -->
+<com.android.internal.policy.impl.keyguard.KeyguardHostView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_host_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:clipChildren="false">
+
+ <com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
+ android:id="@+id/app_widget_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:visibility="gone">
+
+ <!-- TODO: Remove this once supported as a widget -->
+ <include layout="@layout/keyguard_status_view"/>
+
+ </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
+
+ <ViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_width="@dimen/kg_security_view_width"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:layout_gravity="center">
+
+ <include layout="@layout/keyguard_selector_view"/>
+ <include layout="@layout/keyguard_account_view"/>
+ <include layout="@layout/keyguard_pattern_view"/>
+ <include layout="@layout/keyguard_password_view"/>
+ <include layout="@layout/keyguard_sim_pin_view"/>
+ <include layout="@layout/keyguard_sim_puk_view"/>
+ <include layout="@layout/keyguard_face_unlock_view"/>
+
+ </ViewFlipper>
+
+</com.android.internal.policy.impl.keyguard.KeyguardHostView>
+
diff --git a/core/res/res/layout/keyguard_account_view.xml b/core/res/res/layout/keyguard_account_view.xml
new file mode 100644
index 0000000..481f0c1
--- /dev/null
+++ b/core/res/res/layout/keyguard_account_view.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+<com.android.internal.policy.impl.keyguard.KeyguardAccountView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_account_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/keyguard_navigation"/>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <EditText
+ android:id="@+id/login"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="7dip"
+ android:layout_marginEnd="7dip"
+ android:layout_alignParentTop="true"
+ android:hint="@string/kg_login_username_hint"
+ android:inputType="textEmailAddress"
+ />
+
+ <EditText
+ android:id="@+id/password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/login"
+ android:layout_marginTop="15dip"
+ android:layout_marginStart="7dip"
+ android:layout_marginEnd="7dip"
+ android:inputType="textPassword"
+ android:hint="@string/kg_login_password_hint"
+ android:nextFocusRight="@+id/ok"
+ android:nextFocusDown="@+id/ok"
+ />
+
+ <!-- ok below password, aligned to right of screen -->
+ <Button
+ android:id="@+id/ok"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="7dip"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentBottom="true"
+ android:text="@string/kg_login_submit_button"
+ />
+
+ </RelativeLayout>
+
+</com.android.internal.policy.impl.keyguard.KeyguardAccountView>
diff --git a/core/res/res/layout/keyguard_face_unlock_view.xml b/core/res/res/layout/keyguard_face_unlock_view.xml
new file mode 100644
index 0000000..572c013
--- /dev/null
+++ b/core/res/res/layout/keyguard_face_unlock_view.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the screen that shows the 9 circle unlock widget and instructs
+ the user how to unlock their device, or make an emergency call. This
+ is the portrait layout. -->
+<com.android.internal.policy.impl.keyguard.KeyguardFaceUnlockView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_face_unlock_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- TODO -->
+
+</com.android.internal.policy.impl.keyguard.KeyguardFaceUnlockView>
diff --git a/core/res/res/layout/keyguard_navigation.xml b/core/res/res/layout/keyguard_navigation.xml
new file mode 100644
index 0000000..569f93d
--- /dev/null
+++ b/core/res/res/layout/keyguard_navigation.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="left">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/back"
+ android:layout_width="20dip"
+ android:layout_height="wrap_content"
+ android:textSize="28dp"
+ android:text="@string/kg_temp_back_string" />
+
+ <!-- message area for security screen -->
+ <TextView
+ android:id="@+id/message_area"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:layout_marginEnd="6dip"
+ android:layout_marginStart="6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ </LinearLayout>
+
+ <!-- This is currently only uses for pattern unlock -->
+ <Button android:id="@+id/forgot_password_button"
+ android:layout_gravity="right"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+ android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
+ android:drawablePadding="0dip"
+ android:visibility="gone"/>
+
+</LinearLayout>
diff --git a/core/res/res/layout/keyguard_password_view.xml b/core/res/res/layout/keyguard_password_view.xml
new file mode 100644
index 0000000..b9a70e5
--- /dev/null
+++ b/core/res/res/layout/keyguard_password_view.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2008, 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.
+*/
+-->
+<com.android.internal.policy.impl.keyguard.KeyguardPasswordView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_password_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal">
+
+ <include layout="@layout/keyguard_navigation"/>
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"/>
+
+ <!-- Password entry field -->
+ <!-- Note: the entire container is styled to look like the edit field,
+ since the backspace/IME switcher looks better inside -->
+ <LinearLayout
+ android:layout_gravity="center_vertical|fill_horizontal"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:background="@*android:drawable/lockscreen_password_field_dark"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip">
+
+ <EditText android:id="@+id/passwordEntry"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center_horizontal"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+ android:singleLine="true"
+ android:textStyle="normal"
+ android:inputType="textPassword"
+ android:textSize="36sp"
+ android:background="@null"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="#ffffffff"
+ android:imeOptions="flagForceAscii|actionDone"
+ />
+
+ <!-- This delete button is only visible for numeric PIN entry -->
+ <ImageButton android:id="@+id/delete_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@*android:drawable/ic_input_delete"
+ android:clickable="true"
+ android:padding="8dip"
+ android:layout_gravity="center_vertical"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
+
+ <ImageView android:id="@+id/switch_ime_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@*android:drawable/ic_lockscreen_ime"
+ android:clickable="true"
+ android:padding="8dip"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground"
+ android:visibility="gone"
+ />
+
+ </LinearLayout>
+
+ <!-- Numeric keyboard -->
+ <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+ android:layout_width="match_parent"
+ android:layout_marginStart="4dip"
+ android:layout_marginEnd="4dip"
+ android:paddingTop="4dip"
+ android:paddingBottom="4dip"
+ android:background="#40000000"
+ android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
+ android:visibility="gone"
+ android:clickable="true"
+ />
+
+</com.android.internal.policy.impl.keyguard.KeyguardPasswordView>
diff --git a/core/res/res/layout/keyguard_pattern_view.xml b/core/res/res/layout/keyguard_pattern_view.xml
new file mode 100644
index 0000000..9cba609
--- /dev/null
+++ b/core/res/res/layout/keyguard_pattern_view.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the screen that shows the 9 circle unlock widget and instructs
+ the user how to unlock their device, or make an emergency call. This
+ is the portrait layout. -->
+<com.android.internal.policy.impl.keyguard.KeyguardPatternView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_pattern_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <GridLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal">
+
+ <include layout="@layout/keyguard_navigation"/>
+
+ <Space android:layout_gravity="fill" />
+
+ <!-- We need MATCH_PARENT here only to force the size of the parent to be passed to
+ the pattern view for it to compute its size. This is an unusual case, caused by
+ LockPatternView's requirement to maintain a square aspect ratio based on the width
+ of the screen. -->
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPatternView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="8dip"
+ android:layout_marginBottom="4dip"
+ android:layout_marginStart="8dip"
+ android:layout_gravity="center_horizontal"
+ />
+
+ </GridLayout>
+
+</com.android.internal.policy.impl.keyguard.KeyguardPatternView>
diff --git a/core/res/res/layout/keyguard_selector_view.xml b/core/res/res/layout/keyguard_selector_view.xml
new file mode 100644
index 0000000..d516369
--- /dev/null
+++ b/core/res/res/layout/keyguard_selector_view.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+
+<!-- This is the selector widget that allows the user to select an action. -->
+<com.android.internal.policy.impl.keyguard.KeyguardSelectorView
+ xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_selector_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
+ android:id="@+id/app_widget_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:visibility="gone">
+ <!-- TODO: Remove this once supported as a widget -->
+ <include layout="@layout/keyguard_status_view"/>
+ </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:gravity="center">
+
+ <com.android.internal.widget.multiwaveview.GlowPadView
+ android:id="@+id/glow_pad_view"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+
+ prvandroid:targetDrawables="@*android:array/lockscreen_targets_with_camera"
+ prvandroid:targetDescriptions="@*android:array/lockscreen_target_descriptions_with_camera"
+ prvandroid:directionDescriptions="@*android:array/lockscreen_direction_descriptions"
+ prvandroid:handleDrawable="@*android:drawable/ic_lockscreen_handle"
+ prvandroid:outerRingDrawable="@*android:drawable/ic_lockscreen_outerring"
+ prvandroid:outerRadius="@*android:dimen/glowpadview_target_placement_radius"
+ prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
+ prvandroid:snapMargin="@*android:dimen/glowpadview_snap_margin"
+ prvandroid:feedbackCount="1"
+ prvandroid:vibrationDuration="20"
+ prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
+ prvandroid:pointDrawable="@*android:drawable/ic_lockscreen_glowdot"/>
+
+ <Button
+ android:id="@+id/emergency_call_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
+ android:text="@string/kg_emergency_call_label"
+ style="?android:attr/buttonBarButtonStyle"
+ android:drawablePadding="8dip"
+ android:layout_alignRight="@id/glow_pad_view"
+ android:layout_alignTop="@id/glow_pad_view"
+ />
+
+ </RelativeLayout>
+
+</com.android.internal.policy.impl.keyguard.KeyguardSelectorView>
+
diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml
new file mode 100644
index 0000000..122484a
--- /dev/null
+++ b/core/res/res/layout/keyguard_sim_pin_view.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+** 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.
+*/
+-->
+<!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
+<com.android.internal.policy.impl.keyguard.KeyguardSimPinView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_sim_pin_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal">
+
+ <include layout="@layout/keyguard_navigation"/>
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"/>
+
+ <!-- Password entry field -->
+ <!-- Note: the entire container is styled to look like the edit field,
+ since the backspace/IME switcher looks better inside -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginEnd="6dip"
+ android:layout_marginStart="6dip"
+ android:gravity="center_vertical"
+ android:background="@android:drawable/edit_text">
+
+ <!-- displays dots as user enters pin -->
+ <EditText android:id="@+id/sim_pin_entry"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:maxLines="1"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@*android:color/primary_text_holo_light"
+ android:textStyle="bold"
+ android:inputType="textPassword"
+ android:imeOptions="flagForceAscii|actionDone"
+ />
+
+ <ImageButton android:id="@+id/delete_button"
+ android:src="@android:drawable/ic_input_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="-3dip"
+ android:layout_marginBottom="-3dip"
+ />
+ </LinearLayout>
+
+ <!-- Numeric keyboard -->
+ <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+ android:layout_width="match_parent"
+ android:layout_marginStart="4dip"
+ android:layout_marginEnd="4dip"
+ android:paddingTop="4dip"
+ android:paddingBottom="4dip"
+ android:background="#80ffffff"
+ android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
+ android:clickable="true"
+ />
+
+</com.android.internal.policy.impl.keyguard.KeyguardSimPinView>
diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml
new file mode 100644
index 0000000..8bb76c1
--- /dev/null
+++ b/core/res/res/layout/keyguard_sim_puk_view.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2008, 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.
+*/
+-->
+<com.android.internal.policy.impl.keyguard.KeyguardSimPukView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_sim_puk_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center_horizontal">
+
+ <include layout="@layout/keyguard_navigation"/>
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"/>
+
+ <LinearLayout android:id="@+id/topDisplayGroup"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:paddingEnd="0dip"
+ android:layout_marginEnd="10dip"
+ android:layout_marginStart="10dip">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginEnd="6dip"
+ android:layout_marginStart="6dip"
+ android:gravity="center_vertical"
+ android:background="@*android:drawable/edit_text">
+
+ <!-- displays dots as user enters puk -->
+ <EditText android:id="@+id/sim_puk_entry"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:maxLines="1"
+ android:textStyle="bold"
+ android:inputType="textPassword"
+ android:textColor="#000"
+ android:hint="@string/kg_puk_enter_puk_hint"
+ />
+
+ <ImageButton android:id="@+id/puk_delete_button"
+ android:src="@*android:drawable/ic_input_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="-3dip"
+ android:layout_marginBottom="-3dip"
+ />
+
+ </LinearLayout>
+
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginEnd="6dip"
+ android:layout_marginStart="6dip"
+ android:gravity="center_vertical"
+ android:background="@*android:drawable/edit_text">
+
+ <!-- displays dots as user enters new pin -->
+ <EditText android:id="@+id/sim_pin_entry"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:maxLines="1"
+ android:textStyle="bold"
+ android:inputType="textPassword"
+ android:textColor="#000"
+ android:hint="@string/kg_puk_enter_pin_hint"
+ />
+
+ <ImageButton android:id="@+id/pin_delete_button"
+ android:src="@*android:drawable/ic_input_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="-3dip"
+ android:layout_marginBottom="-3dip"
+ />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <!-- Numeric keyboard -->
+ <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+ android:layout_width="match_parent"
+ android:layout_marginStart="4dip"
+ android:layout_marginEnd="4dip"
+ android:paddingTop="4dip"
+ android:paddingBottom="4dip"
+ android:background="#80ffffff"
+ android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
+ android:clickable="true"
+ />
+
+</com.android.internal.policy.impl.keyguard.KeyguardSimPukView>
diff --git a/core/res/res/layout/keyguard_status_view.xml b/core/res/res/layout/keyguard_status_view.xml
new file mode 100644
index 0000000..f8d05b7
--- /dev/null
+++ b/core/res/res/layout/keyguard_status_view.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal">
+
+ <com.android.internal.policy.impl.keyguard.KeyguardStatusView
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal">
+
+ <com.android.internal.widget.DigitalClock android:id="@+id/time"
+ android:layout_marginTop="@*android:dimen/keyguard_lockscreen_status_line_clockfont_top_margin"
+ android:layout_marginBottom="12dip"
+ android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin"
+ android:layout_gravity="end">
+
+ <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
+ top of the other. Hence the redundant layout... -->
+ <TextView android:id="@*android:id/timeDisplayBackground"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="none"
+ android:textSize="@*android:dimen/keyguard_lockscreen_clock_font_size"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginBottom="6dip"
+ android:textColor="@*android:color/lockscreen_clock_background"
+ />
+
+ <TextView android:id="@*android:id/timeDisplayForeground"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="none"
+ android:textSize="@*android:dimen/keyguard_lockscreen_clock_font_size"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginBottom="6dip"
+ android:textColor="@*android:color/lockscreen_clock_foreground"
+ android:layout_alignStart="@*android:id/timeDisplayBackground"
+ android:layout_alignTop="@*android:id/timeDisplayBackground"
+ />
+
+ </com.android.internal.widget.DigitalClock>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_gravity="end"
+ android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin">
+
+ <TextView
+ android:id="@*android:id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+ />
+
+ <TextView
+ android:id="@*android:id/alarm_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+ android:drawablePadding="4dip"
+ />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@*android:id/status1"
+ android:layout_gravity="end"
+ android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+ android:drawablePadding="4dip"
+ />
+
+ <TextView
+ android:id="@*android:id/carrier"
+ android:layout_gravity="end"
+ android:layout_marginEnd="@*android:dimen/keyguard_lockscreen_status_line_font_right_margin"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
+ android:textColor="?android:attr/textColorSecondary"
+ />
+
+ </com.android.internal.policy.impl.keyguard.KeyguardStatusView>
+</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame> \ No newline at end of file
diff --git a/core/res/res/layout/overlay_display_window.xml b/core/res/res/layout/overlay_display_window.xml
new file mode 100644
index 0000000..25c792a
--- /dev/null
+++ b/core/res/res/layout/overlay_display_window.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextureView android:id="@+id/overlay_display_window_texture"
+ android:layout_width="0px"
+ android:layout_height="0px" />
+ <TextView android:id="@+id/overlay_display_window_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal" />
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 560a6a8..7aa8bf0 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Raak om die netwerk te bestuur."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
<string name="reset" msgid="2448168080964209908">"Stel terug"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index fc6d4b8..3068fb9 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -225,7 +225,7 @@
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር ለመፍጠር ሙሉ ፍቃድ"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"በተለያዩ ተጠቃሚዎች ላይ ሊኖሩ የሚችሉ መስተጋብሮችን ሁሉ ይፈቅዳል።"</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"ተጠቃሚዎችን ያስተዳድሩ"</string>
- <string name="permdesc_manageUsers" msgid="8409306667645355638">"መተግበሪያዎች በመሣሪያዎች ላይ ያሉ ተጠቃሚዎችን እንዲያቀናብር ያስችለዋል፣ መጠየቅን፣ መፍጠርንና መሰረዝን ጨምሮ።"</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"መተግበሪያዎች በመሣሪያው ላይ ያሉ ተጠቃሚዎችን እንዲያቀናብር ያስችለዋል፣ መጠየቅን፣ መፍጠርንና መሰረዝን ጨምሮ።"</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"እየሄዱ ስላሉ የመተግበሪያዎች ዝርዝሮች አምጣ"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"መተግበሪያው በአሁኑ ጊዜ እየተካሄዱ ስላሉና በቅርብ ጊዜ ስለተካሄዱ ተግባሮች መረጃ ዝርዝር እንዲያወጣ ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች ስለ ሌሎች መተግበሪያዎች የግል መረጃ ሊያገኙ ይችላሉ።"</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"አሂድ ትግበራዎችን ድጋሚ ደርድር"</string>
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
<string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት ንካ።"</string>
<string name="vpn_text_long" msgid="6407351006249174473">"ለ<xliff:g id="SESSION">%s</xliff:g>የተገናኘ። አውታረመረቡን ለማደራጀት ንካ።"</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"ፋይል ምረጥ"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"ምንም ፋይል አልተመረጠም"</string>
<string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d3b8f04..df3d114 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. المس لإدارة الشبكة."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
<string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index d801628..55621b3 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN актывуецца прыкладаннем <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Дакраніцеся, каб кіраваць сеткай."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Падлучаны да сеанса \"<xliff:g id="SESSION">%s</xliff:g>\". Дакраніцеся, каб кiраваць сеткай."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
<string name="reset" msgid="2448168080964209908">"Скінуць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 7e7c4e6..4aea25f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Свързана със: <xliff:g id="SESSION">%s</xliff:g>. Докоснете, за да управлявате мрежата."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string>
<string name="reset" msgid="2448168080964209908">"Повторно задаване"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0781217..097e86c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Connectat a <xliff:g id="SESSION">%s</xliff:g>. Toca per gestionar la xarxa."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string>
<string name="reset" msgid="2448168080964209908">"Reinicia"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 50cd013..c7f3f88 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Dotykem můžete síť spravovat."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string>
<string name="reset" msgid="2448168080964209908">"Resetovat"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ea40879..d390c3f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
<string name="reset" msgid="2448168080964209908">"Nulstil"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a0280c8..1bd213e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
<string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks berühren"</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string>
<string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 82f0c62..75ceaed 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Συνδέθηκε με <xliff:g id="SESSION">%s</xliff:g>. Αγγίξτε για τη διαχείριση του δικτύου."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Δεν έχει επιλεγεί αρχείο"</string>
<string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4f7b087..4fe04fb 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Touch to manage the network."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string>
<string name="reset" msgid="2448168080964209908">"Reset"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 00d8617..170e2f1 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -224,8 +224,8 @@
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string>
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Licencia completa para interactuar con los usuarios"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite todas las interacciones posibles con los usuarios."</string>
- <string name="permlab_manageUsers" msgid="1676150911672282428">"Administrar usuarios"</string>
- <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite a las aplicaciones administrar a los usuarios del dispositivo, incluidas la creación y la eliminación de consultas."</string>
+ <string name="permlab_manageUsers" msgid="1676150911672282428">"administrar usuarios"</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite a las aplicaciones administrar los usuarios del dispositivo, lo que incluye buscarlos, crearlos y eliminarlos."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recuperar información sobre las aplicaciones en ejecución"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite que la aplicación recupere información detallada sobre tareas en ejecución y recientemente ejecutadas. Las aplicaciones malintencionadas pueden hallar información privada sobre otras aplicaciones."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"reorganizar aplicaciones en ejecución"</string>
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
<string name="reset" msgid="2448168080964209908">"Restablecer"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5e63311..02551e3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string>
<string name="reset" msgid="2448168080964209908">"Restablecer"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8280b61..c15fae7 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Võrgu haldamiseks puudutage."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
<string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 0dba1bd..c55eb07 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
<string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"به <xliff:g id="SESSION">%s</xliff:g> وصل شد. برای مدیریت شبکه لمس کنید."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string>
<string name="reset" msgid="2448168080964209908">"بازنشانی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index f6ab9f8..ee536a6 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
<string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa koskettamalla."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string>
<string name="reset" msgid="2448168080964209908">"Palauta"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d4d938b..63a19f4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string>
<string name="reset" msgid="2448168080964209908">"Réinitialiser"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b491e97..b2ab326 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -468,7 +468,7 @@
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"फ़ोन हार्डवेयर में पूर्ण पहुंच की अनुमति देते हुए निम्‍न-स्‍तर निर्माता परीक्षण के रूप में चलाएं. केवल तभी उपलब्‍ध जब कोई फ़ोन निर्माता परीक्षण मोड में चल रहा हो."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"वॉलपेपर सेट करें"</string>
<string name="permdesc_setWallpaper" msgid="7373447920977624745">"एप्‍लिकेशन को सिस्‍टम वॉलपेपर सेट करने देता है."</string>
- <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"अपने वॉलपेपर का आकार समायोजित करें"</string>
+ <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"अपने वॉलपेपर का आकार एडजस्ट करें"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"एप्‍लिकेशन को सिस्‍टम वॉलपेपर आकार संकेत सेट करने देता है."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"फ़ैक्‍ट्री डिफ़ॉल्‍ट पर सिस्‍टम रीसेट करें"</string>
<string name="permdesc_masterClear" msgid="3665380492633910226">"एप्लिकेशन को सभी डेटा, कॉन्फ़िगरेशन, और इंस्टॉल एप्लिकेशन मिटाकर, सिस्टम को पूरी तरह उसकी फ़ैक्टरी सेटिंग पर रीसेट करने देता है."</string>
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g> से कनेक्‍ट किया गया. नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string>
<string name="reset" msgid="2448168080964209908">"रीसेट करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index aef3bdf..2dd59e0 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite za upravljanje mrežom."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string>
<string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 90bd85e..69dae8a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
<string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string>
<string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 34e6a96..f8e8fc1 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Sentuh untuk mengelola jaringan."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Pilih file"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string>
<string name="reset" msgid="2448168080964209908">"Setel ulang"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index a693dc8..9a7c439 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Collegata a <xliff:g id="SESSION">%s</xliff:g>. Tocca per gestire la rete."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Scegli file"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nessun file è stato scelto"</string>
<string name="reset" msgid="2448168080964209908">"Reimposta"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a318907..2ae5206 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"מחובר אל <xliff:g id="SESSION">%s</xliff:g>. גע כדי לנהל את הרשת."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string>
<string name="reset" msgid="2448168080964209908">"איפוס"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b7a9c3b..e94ebe7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
<string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
<string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g>に接続しました。ネットワークを管理するにはタップしてください。"</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
<string name="reset" msgid="2448168080964209908">"リセット"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0193ca2..4609a80 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -794,7 +794,7 @@
<string name="autofill_department" msgid="5343279462564453309">"지역"</string>
<string name="autofill_prefecture" msgid="2028499485065800419">"현"</string>
<string name="autofill_parish" msgid="8202206105468820057">"군"</string>
- <string name="autofill_area" msgid="3547409050889952423">"구역"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"주소"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"에미리트"</string>
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"웹 북마크 및 기록 읽기"</string>
<string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"앱이 브라우저가 방문한 모든 URL의 기록과 모든 브라우저 북마크를 읽을 수 있도록 허용합니다. 참고: 이 권한은 타사 브라우저 또는 브라우저 기능을 가진 기타 애플리케이션에 적용되지 않습니다."</string>
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
<string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g>에 연결되어 있습니다. 네트워크를 관리하려면 터치하세요."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string>
<string name="reset" msgid="2448168080964209908">"초기화"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b778d03..ad2e4cd 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string>
<string name="reset" msgid="2448168080964209908">"Atstatyti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 4b78bd4..5a5c14b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -225,7 +225,7 @@
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pilna licence ar atļauju darboties visos lietotāju kontos"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Ļauj veikt jebkādas darbības visos lietotāju kontos."</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"Lietotāju pārvaldība"</string>
- <string name="permdesc_manageUsers" msgid="8409306667645355638">"Ļauj lietotnēm pārvaldīt ierīces lietotājus, tostarp izveidot un dzēst lietotājus vai veidot vaicājumus."</string>
+ <string name="permdesc_manageUsers" msgid="8409306667645355638">"Ļauj lietotnēm pārvaldīt ierīces lietotājus, tostarp izveidot un dzēst lietotājus un veidot vaicājumus."</string>
<string name="permlab_getDetailedTasks" msgid="6229468674753529501">"Informācijas izguve par izmantotajām lietotnēm"</string>
<string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Ļauj lietotnei izgūt informāciju par šobrīd un nesen veiktajiem uzdevumiem. Ļaunprātīgas lietotnes var atklāt privātu informāciju par citām lietotnēm."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"pārkārtot izmantotās lietotnes"</string>
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
<string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Ir izveidots savienojums ar <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string>
<string name="reset" msgid="2448168080964209908">"Atiestatīt"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 782c2a7..2ac167f 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Bersambung ke <xliff:g id="SESSION">%s</xliff:g>. Sentuh untuk mengurus rangkaian."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string>
<string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3a4212b..7012793 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Koblet til <xliff:g id="SESSION">%s</xliff:g>. Trykk for å administrere nettverket."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Velg fil"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string>
<string name="reset" msgid="2448168080964209908">"Tilbakestill"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 89e52a9..8178980 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Verbonden met <xliff:g id="SESSION">%s</xliff:g>. Tik om het netwerk te beheren."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Geen bestand geselecteerd"</string>
<string name="reset" msgid="2448168080964209908">"Opnieuw instellen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f0dcc2f..c907fe6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Nawiązano połączenie z: <xliff:g id="SESSION">%s</xliff:g>. Dotknij, aby zarządzać siecią."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nie wybrano pliku"</string>
<string name="reset" msgid="2448168080964209908">"Resetuj"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 18c25a3..7541db8 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string>
<string name="reset" msgid="2448168080964209908">"Repor"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 794af68..d8a5bba 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
<string name="reset" msgid="2448168080964209908">"Redefinir"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index a093bfb..9ffa164 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1799,6 +1799,14 @@
<skip />
<!-- no translation found for vpn_text_long (6407351006249174473) -->
<skip />
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Tscherner ina datoteca"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nagina datoteca tschernida"</string>
<string name="reset" msgid="2448168080964209908">"Reinizialisar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6f6272d..23c1491 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Atingeţi pentru a gestiona reţeaua."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fişiere"</string>
<string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a9c0701..98dc250 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Сеть VPN подключена: <xliff:g id="SESSION">%s</xliff:g>. Нажмите, чтобы открыть настройки."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string>
<string name="reset" msgid="2448168080964209908">"Сбросить"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 6240be3..37395a8 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po dotyku môžete sieť spravovať."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string>
<string name="reset" msgid="2448168080964209908">"Obnoviť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 1ede6b7..48fa35d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Vzpostavljena povezava s sejo <xliff:g id="SESSION">%s</xliff:g>. Dotaknite se, če želite upravljati omrežje."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string>
<string name="reset" msgid="2448168080964209908">"Ponastavi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4ddde21..259cb15 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Повезано са сесијом <xliff:g id="SESSION">%s</xliff:g>. Додирните да бисте управљали мрежом."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
<string name="reset" msgid="2448168080964209908">"Поново постави"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 493a0bb..10bdd18 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Ansluten till <xliff:g id="SESSION">%s</xliff:g>. Knacka lätt om du vill hantera nätverket."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Välj fil"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil har valts"</string>
<string name="reset" msgid="2448168080964209908">"Återställ"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 759000d..5f20617 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Imeunganishwa kwa <xliff:g id="SESSION">%s</xliff:g>. Gusa ili kudhibiti mtandao."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Chagua faili"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Hakuna faili iliyochaguliwa"</string>
<string name="reset" msgid="2448168080964209908">"Weka upya"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index efb1d6f..40d4eb6 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
<string name="vpn_text_long" msgid="6407351006249174473">"เชื่อมต่อกับ <xliff:g id="SESSION">%s</xliff:g> แตะเพื่อจัดการเครือข่าย"</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string>
<string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 261a0b9..036a30e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Pindutin upang pamahalaan ang network."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string>
<string name="reset" msgid="2448168080964209908">"I-reset"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index c60535f..2848eea 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
<string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlandı. Ağı yönetmek için dokunun."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string>
<string name="reset" msgid="2448168080964209908">"Sıfırla"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a8633e8..ee3f8da 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Під’єднано до сеансу <xliff:g id="SESSION">%s</xliff:g>. Торкніться, щоб керувати мережею."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string>
<string name="reset" msgid="2448168080964209908">"Віднов."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 012a47a..b5c17ae 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
<string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string>
<string name="reset" msgid="2448168080964209908">"Đặt lại"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index e982c75..0caef06 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
<string name="vpn_text_long" msgid="6407351006249174473">"已连接到“<xliff:g id="SESSION">%s</xliff:g>”。触摸可管理网络。"</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
<string name="reset" msgid="2448168080964209908">"重置"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 36eba9f..2935256 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
<string name="vpn_text_long" msgid="6407351006249174473">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕觸即可管理網路。"</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string>
<string name="reset" msgid="2448168080964209908">"重設"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 78b287c..8360097 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1167,6 +1167,14 @@
<string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
<string name="vpn_text_long" msgid="6407351006249174473">"Ixhumeke ku-.<xliff:g id="SESSION">%s</xliff:g> Thinta ukuze ulawule inethiwekhi."</string>
+ <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+ <skip />
+ <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
+ <skip />
<string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string>
<string name="reset" msgid="2448168080964209908">"Setha kabusha"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5d8d397..209fff0 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5706,4 +5706,22 @@
<attr name="minHeight" />
</declare-styleable>
+ <!-- PagedView specific attributes. These attributes are used to customize
+ a PagedView view in XML files. -->
+ <declare-styleable name="PagedView">
+ <!-- A spacing override for the icons within a page -->
+ <attr name="pageLayoutWidthGap" format="dimension" />
+ <attr name="pageLayoutHeightGap" format="dimension" />
+ <!-- The padding of the pages that are dynamically created per page -->
+ <attr name="pageLayoutPaddingTop" format="dimension" />
+ <attr name="pageLayoutPaddingBottom" format="dimension" />
+ <attr name="pageLayoutPaddingLeft" format="dimension" />
+ <attr name="pageLayoutPaddingRight" format="dimension" />
+ <!-- The space between adjacent pages of the PagedView. -->
+ <attr name="pageSpacing" format="dimension" />
+ <!-- The padding for the scroll indicator area -->
+ <attr name="scrollIndicatorPaddingLeft" format="dimension" />
+ <attr name="scrollIndicatorPaddingRight" format="dimension" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index f30943a..372a1ee 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -237,4 +237,20 @@
<dimen name="notification_title_text_size">18dp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
<dimen name="notification_subtext_size">12dp</dimen>
+
+ <!-- Keyguard dimensions -->
+ <!-- Width of security view in keyguard. -->
+ <dimen name="kg_security_view_width">500dp</dimen>
+
+ <!-- Height of security view in keyguard. -->
+ <dimen name="kg_security_view_height">0dp</dimen>
+
+ <!-- Width of widget view in keyguard. -->
+ <dimen name="kg_widget_view_width">0dp</dimen>
+
+ <!-- Height of widget view in keyguard. -->
+ <dimen name="kg_widget_view_height">0dp</dimen>
+
+ <!-- Padding surrounding each widget page -->
+ <dimen name="kg_widget_page_padding">10dp</dimen>
</resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
new file mode 100644
index 0000000..603fd7e
--- /dev/null
+++ b/core/res/res/values/integers.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+** 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>
+ <integer name="flip_duration">300</integer>
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d761980..6414df8 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -120,6 +120,8 @@
<java-symbol type="id" name="old_app_action" />
<java-symbol type="id" name="old_app_description" />
<java-symbol type="id" name="old_app_icon" />
+ <java-symbol type="id" name="overlay_display_window_texture" />
+ <java-symbol type="id" name="overlay_display_window_title" />
<java-symbol type="id" name="package_label" />
<java-symbol type="id" name="packages_list" />
<java-symbol type="id" name="pause" />
@@ -479,7 +481,9 @@
<java-symbol type="string" name="decline" />
<java-symbol type="string" name="default_text_encoding" />
<java-symbol type="string" name="description_target_unlock_tablet" />
- <java-symbol type="string" name="display_manager_built_in_display" />
+ <java-symbol type="string" name="display_manager_built_in_display_name" />
+ <java-symbol type="string" name="display_manager_overlay_display_name" />
+ <java-symbol type="string" name="display_manager_overlay_display_title" />
<java-symbol type="string" name="double_tap_toast" />
<java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" />
<java-symbol type="string" name="elapsed_time_short_format_mm_ss" />
@@ -1093,6 +1097,7 @@
<java-symbol type="layout" name="list_menu_item_radio" />
<java-symbol type="layout" name="locale_picker_item" />
<java-symbol type="layout" name="media_controller" />
+ <java-symbol type="layout" name="overlay_display_window" />
<java-symbol type="layout" name="preference" />
<java-symbol type="layout" name="preference_header_item" />
<java-symbol type="layout" name="preference_list_content" />
@@ -1203,6 +1208,8 @@
<java-symbol type="anim" name="dock_left_exit" />
<java-symbol type="anim" name="dock_right_enter" />
<java-symbol type="anim" name="dock_right_exit" />
+ <java-symbol type="anim" name="keyguard_security_animate_in" />
+ <java-symbol type="anim" name="keyguard_security_animate_out" />
<java-symbol type="array" name="config_keyboardTapVibePattern" />
<java-symbol type="array" name="config_longPressVibePattern" />
<java-symbol type="array" name="config_safeModeDisabledVibePattern" />
@@ -1230,6 +1237,7 @@
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
<java-symbol type="dimen" name="status_bar_height" />
+ <java-symbol type="dimen" name="kg_widget_page_padding" />
<java-symbol type="drawable" name="ic_jog_dial_sound_off" />
<java-symbol type="drawable" name="ic_jog_dial_sound_on" />
<java-symbol type="drawable" name="ic_jog_dial_unlock" />
@@ -1247,6 +1255,8 @@
<java-symbol type="drawable" name="jog_tab_target_yellow" />
<java-symbol type="drawable" name="menu_background" />
<java-symbol type="drawable" name="stat_sys_secure" />
+ <java-symbol type="drawable" name="kg_widget_overscroll_layer_left" />
+ <java-symbol type="drawable" name="kg_widget_overscroll_layer_right" />
<java-symbol type="id" name="action_mode_bar_stub" />
<java-symbol type="id" name="alarm_status" />
<java-symbol type="id" name="backspace" />
@@ -1299,6 +1309,28 @@
<java-symbol type="id" name="two" />
<java-symbol type="id" name="unlock_widget" />
<java-symbol type="id" name="zero" />
+ <java-symbol type="id" name="message_area" />
+ <java-symbol type="id" name="keyguard_selector_view" />
+ <java-symbol type="id" name="keyguard_pattern_view" />
+ <java-symbol type="id" name="keyguard_password_view" />
+ <java-symbol type="id" name="keyguard_face_unlock_view" />
+ <java-symbol type="id" name="keyguard_sim_pin_view" />
+ <java-symbol type="id" name="keyguard_sim_puk_view" />
+ <java-symbol type="id" name="keyguard_account_view" />
+ <java-symbol type="id" name="app_widget_container" />
+ <java-symbol type="id" name="view_flipper" />
+ <java-symbol type="id" name="emergency_call_button" />
+ <java-symbol type="id" name="keyguard_host_view" />
+ <java-symbol type="id" name="delete_button" />
+ <java-symbol type="id" name="lockPatternView" />
+ <java-symbol type="id" name="forgot_password_button" />
+ <java-symbol type="id" name="glow_pad_view" />
+ <java-symbol type="id" name="sim_pin_entry" />
+ <java-symbol type="id" name="delete_button" />
+ <java-symbol type="id" name="sim_puk_entry" />
+ <java-symbol type="id" name="sim_pin_entry" />
+ <java-symbol type="id" name="puk_delete_button" />
+ <java-symbol type="id" name="pin_delete_button" />
<java-symbol type="integer" name="config_carDockRotation" />
<java-symbol type="integer" name="config_defaultUiModeType" />
<java-symbol type="integer" name="config_deskDockRotation" />
@@ -1328,6 +1360,7 @@
<java-symbol type="layout" name="screen_simple_overlay_action_mode" />
<java-symbol type="layout" name="screen_title" />
<java-symbol type="layout" name="screen_title_icons" />
+ <java-symbol type="layout" name="keyguard_host_view" />
<java-symbol type="string" name="abbrev_wday_month_day_no_year" />
<java-symbol type="string" name="android_upgrading_title" />
<java-symbol type="string" name="bugreport_title" />
@@ -1381,6 +1414,33 @@
<java-symbol type="style" name="Animation.LockScreen" />
<java-symbol type="style" name="Theme.Dialog.RecentApplications" />
<java-symbol type="style" name="Theme.ExpandedMenu" />
+ <java-symbol type="string" name="kg_emergency_call_label" />
+ <java-symbol type="string" name="kg_forgot_pattern_button_text" />
+ <java-symbol type="string" name="kg_wrong_pattern" />
+ <java-symbol type="string" name="kg_wrong_password" />
+ <java-symbol type="string" name="kg_wrong_pin" />
+ <java-symbol type="string" name="kg_too_many_failed_attempts_countdown" />
+ <java-symbol type="string" name="kg_pattern_instructions" />
+ <java-symbol type="string" name="kg_sim_pin_instructions" />
+ <java-symbol type="string" name="kg_pin_instructions" />
+ <java-symbol type="string" name="kg_password_instructions" />
+ <java-symbol type="string" name="kg_puk_enter_puk_hint" />
+ <java-symbol type="string" name="kg_puk_enter_pin_hint" />
+ <java-symbol type="string" name="kg_sim_unlock_progress_dialog_message" />
+ <java-symbol type="string" name="kg_password_wrong_pin_code" />
+ <java-symbol type="string" name="kg_invalid_sim_pin_hint" />
+ <java-symbol type="string" name="kg_invalid_sim_puk_hint" />
+ <java-symbol type="string" name="kg_sim_puk_recovery_hint" />
+ <java-symbol type="string" name="kg_invalid_puk" />
+ <java-symbol type="string" name="kg_login_too_many_attempts" />
+ <java-symbol type="string" name="kg_login_instructions" />
+ <java-symbol type="string" name="kg_login_username_hint" />
+ <java-symbol type="string" name="kg_login_password_hint" />
+ <java-symbol type="string" name="kg_login_submit_button" />
+ <java-symbol type="string" name="kg_login_invalid_input" />
+ <java-symbol type="string" name="kg_login_account_recovery_hint" />
+ <java-symbol type="string" name="kg_login_checking_password" />
+
<!-- From services -->
<java-symbol type="anim" name="screen_rotate_0_enter" />
@@ -3692,5 +3752,5 @@
<public type="attr" name="listPreferredItemPaddingStart" />
<public type="attr" name="listPreferredItemPaddingEnd" />
<public type="attr" name="singleUser" />
-
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e77dde7..3178af0 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1616,6 +1616,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
<string name="permdesc_mediaStorageWrite" product="default">Allows the app to modify the contents of the internal media storage.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permlab_sdcardAccessAll">access external storage of all users</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_sdcardAccessAll">Allows the app to access external storage for all users.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_cache_filesystem">access the cache filesystem</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3651,6 +3656,42 @@
<!-- Display manager service -->
<!-- Name of the built-in display. [CHAR LIMIT=50] -->
- <string name="display_manager_built_in_display">Built-in Screen</string>
+ <string name="display_manager_built_in_display_name">Built-in Screen</string>
+
+ <!-- Name of the N'th overlay display for testing. [CHAR LIMIT=50] -->
+ <string name="display_manager_overlay_display_name">Overlay #<xliff:g id="id">%1$d</xliff:g></string>
+
+ <!-- Title text to show within the overlay. [CHAR LIMIT=50] -->
+ <string name="display_manager_overlay_display_title">Overlay #<xliff:g id="id">%1$d</xliff:g>: <xliff:g id="width">%2$d</xliff:g>x<xliff:g id="height">%3$d</xliff:g>, <xliff:g id="dpi">%4$d</xliff:g> dpi</string>
+
+ <!-- Keyguard strings -->
+ <string name="kg_emergency_call_label">Emergency call</string>
+ <string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
+ <string name="kg_wrong_pattern">Wrong Pattern</string>
+ <string name="kg_wrong_password">Wrong Password</string>
+ <string name="kg_wrong_pin">Wrong PIN</string>
+ <string name="kg_too_many_failed_attempts_countdown">Too many attempts</string>
+ <string name="kg_pattern_instructions">Draw your pattern</string>
+ <string name="kg_sim_pin_instructions">Enter SIM PIN</string>
+ <string name="kg_pin_instructions">Enter PIN</string>
+ <string name="kg_password_instructions">Enter Password</string>
+ <string name="kg_puk_enter_puk_hint">PUK code</string>
+ <string name="kg_puk_enter_pin_hint">New PIN code</string>
+ <string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
+ <string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
+ <string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
+ <string name="kg_invalid_sim_puk_hint">Type a PUK that is 8 numbers or longer.</string>
+ <string name="kg_sim_puk_recovery_hint">Type PUK and new PIN code</string>
+ <string name="kg_invalid_puk">The PUK you typed isn\'t correct.</string>
+
+ <string name="kg_login_too_many_attempts">Too many pattern attempts</string>
+ <string name="kg_login_instructions">To unlock, sign in with your Google account.</string>
+ <string name="kg_login_username_hint">Username (email)</string>
+ <string name="kg_login_password_hint">Password</string>
+ <string name="kg_login_submit_button">Sign in</string>
+ <string name="kg_login_invalid_input">Invalid username or password.</string>
+ <string name="kg_login_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b>.</string>
+ <string name="kg_login_checking_password">Checking\u2026</string>
+ <string name="kg_temp_back_string"> &lt; </string> <!-- TODO: remove this -->
</resources>