diff options
Diffstat (limited to 'core')
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 Binary files differnew file mode 100644 index 0000000..c30eb1c --- /dev/null +++ b/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_left.9.png 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 Binary files differnew file mode 100644 index 0000000..e5d5771 --- /dev/null +++ b/core/res/res/drawable-nodpi/kg_widget_overscroll_layer_right.9.png 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"> < </string> <!-- TODO: remove this --> </resources> |
