diff options
185 files changed, 4480 insertions, 1456 deletions
@@ -420,6 +420,8 @@ aidl_files := \ frameworks/base/core/java/android/view/MotionEvent.aidl \ frameworks/base/core/java/android/view/Surface.aidl \ frameworks/base/core/java/android/view/WindowManager.aidl \ + frameworks/base/core/java/android/view/WindowAnimationFrameStats.aidl \ + frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \ frameworks/base/core/java/android/widget/RemoteViews.aidl \ frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerService.aidl \ frameworks/base/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl \ diff --git a/api/current.txt b/api/current.txt index 3230bd8..7de59d5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1132,6 +1132,7 @@ package android { field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043 field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301 field public static final int textAppearanceListItem = 16843678; // 0x101039e + field public static final int textAppearanceListItemSecondary = 16843838; // 0x101043e field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f field public static final int textAppearanceMedium = 16842817; // 0x1010041 field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044 @@ -4452,6 +4453,7 @@ package android.app { ctor public Notification.Builder(android.content.Context); method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent); method public android.app.Notification.Builder addExtras(android.os.Bundle); + method public android.app.Notification.Builder addPerson(java.lang.String); method public android.app.Notification build(); method public android.os.Bundle getExtras(); method public deprecated android.app.Notification getNotification(); @@ -4750,9 +4752,13 @@ package android.app { } public final class UiAutomation { + method public void clearWindowAnimationFrameStats(); + method public boolean clearWindowContentFrameStats(int); method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException; method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow(); method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo(); + method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats(); + method public android.view.WindowContentFrameStats getWindowContentFrameStats(int); method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows(); method public boolean injectInputEvent(android.view.InputEvent, boolean); method public final boolean performGlobalAction(int); @@ -10632,6 +10638,7 @@ package android.graphics.drawable { method public void setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); method public final void setTileModeY(android.graphics.Shader.TileMode); method public void setTint(android.content.res.ColorStateList); + method public void setTintMode(android.graphics.PorterDuff.Mode); } public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback { @@ -10909,6 +10916,7 @@ package android.graphics.drawable { method public void setTargetDensity(android.util.DisplayMetrics); method public void setTargetDensity(int); method public void setTint(android.content.res.ColorStateList); + method public void setTintMode(android.graphics.PorterDuff.Mode); } public class PaintDrawable extends android.graphics.drawable.ShapeDrawable { @@ -10999,6 +11007,9 @@ package android.graphics.drawable { public class TouchFeedbackDrawable extends android.graphics.drawable.LayerDrawable { method public android.graphics.Rect getDirtyBounds(); + method public android.content.res.ColorStateList getTint(); + method public void setTint(android.content.res.ColorStateList); + method public void setTintMode(android.graphics.PorterDuff.Mode); } public class TransitionDrawable extends android.graphics.drawable.LayerDrawable implements android.graphics.drawable.Drawable.Callback { @@ -11020,8 +11031,6 @@ package android.graphics.drawable { method public void setAnimationFraction(float); method public void setColorFilter(android.graphics.ColorFilter); method public void setDuration(long); - method public void setIntrinsicHeight(int); - method public void setIntrinsicWidth(int); method public void setPadding(android.graphics.Rect); method public void setPadding(int, int, int, int); method public void setRepeatCount(int); @@ -11721,6 +11730,7 @@ package android.hardware.camera2 { field public static final int CONTROL_AWB_STATE_LOCKED = 3; // 0x3 field public static final int CONTROL_AWB_STATE_SEARCHING = 1; // 0x1 field public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0; // 0x0 + field public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6; // 0x6 field public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1; // 0x1 field public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2; // 0x2 field public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3; // 0x3 @@ -28437,6 +28447,18 @@ package android.view { method public static android.view.FocusFinder getInstance(); } + public abstract class FrameStats { + ctor public FrameStats(); + method public final long getEndTimeNano(); + method public final int getFrameCount(); + method public final long getFramePresentedTimeNano(int); + method public final long getRefreshPeriodNano(); + method public final long getStartTimeNano(); + field public static final long UNDEFINED_TIME_NANO = -1L; // 0xffffffffffffffffL + field protected long[] mFramesPresentedTimeNano; + field protected long mRefreshPeriodNano; + } + public class GestureDetector { ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler); ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener); @@ -30761,6 +30783,20 @@ package android.view { method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); } + public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + + public final class WindowContentFrameStats extends android.view.FrameStats implements android.os.Parcelable { + method public int describeContents(); + method public long getFramePostedTimeNano(int); + method public long getFrameReadyTimeNano(int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + public class WindowId implements android.os.Parcelable { method public int describeContents(); method public boolean isFocused(); diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 09bf829..347de97 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -19,6 +19,8 @@ package android.app; import android.accessibilityservice.IAccessibilityServiceClient; import android.graphics.Bitmap; import android.view.InputEvent; +import android.view.WindowContentFrameStats; +import android.view.WindowAnimationFrameStats; import android.os.ParcelFileDescriptor; /** @@ -26,7 +28,7 @@ import android.os.ParcelFileDescriptor; * on behalf of an instrumentation that it runs. These operations require * special permissions which the shell user has but the instrumentation does * not. Running privileged operations by the shell user on behalf of an - * instrumentation is needed for running UiTestCases. + * instrumentation is needed for running UiTestCases. * * {@hide} */ @@ -37,4 +39,8 @@ interface IUiAutomationConnection { boolean setRotation(int rotation); Bitmap takeScreenshot(int width, int height); void shutdown(); + boolean clearWindowContentFrameStats(int windowId); + WindowContentFrameStats getWindowContentFrameStats(int windowId); + void clearWindowAnimationFrameStats(); + WindowAnimationFrameStats getWindowAnimationFrameStats(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 36d2635..fe629f6 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1311,6 +1311,7 @@ public class Notification implements Parcelable private Notification mPublicVersion = null; private boolean mQuantumTheme; private final LegacyNotificationUtil mLegacyNotificationUtil; + private ArrayList<String> mPeople; /** * Constructs a new Builder with the defaults: @@ -1338,6 +1339,7 @@ public class Notification implements Parcelable mWhen = System.currentTimeMillis(); mAudioStreamType = STREAM_DEFAULT; mPriority = PRIORITY_DEFAULT; + mPeople = new ArrayList<String>(); // TODO: Decide on targetSdk from calling app whether to use quantum theme. mQuantumTheme = true; @@ -1723,6 +1725,16 @@ public class Notification implements Parcelable } /** + * Add a person that is relevant to this notification. + * + * @see Notification#EXTRA_PEOPLE + */ + public Builder addPerson(String handle) { + mPeople.add(handle); + return this; + } + + /** * Merge additional metadata into this notification. * * <p>Values within the Bundle will replace existing extras values in this Builder. @@ -2149,6 +2161,9 @@ public class Notification implements Parcelable if (mLargeIcon != null) { extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon); } + if (!mPeople.isEmpty()) { + extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()])); + } } /** diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 354a19f..8523d0c 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -33,6 +33,8 @@ import android.view.Display; import android.view.InputEvent; import android.view.KeyEvent; import android.view.Surface; +import android.view.WindowAnimationFrameStats; +import android.view.WindowContentFrameStats; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; @@ -674,6 +676,148 @@ public final class UiAutomation { } } + /** + * Clears the frame statistics for the content of a given window. These + * statistics contain information about the most recently rendered content + * frames. + * + * @param windowId The window id. + * @return Whether the window is present and its frame statistics + * were cleared. + * + * @see android.view.WindowContentFrameStats + * @see #getWindowContentFrameStats(int) + * @see #getWindows() + * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId() + */ + public boolean clearWindowContentFrameStats(int windowId) { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + try { + if (DEBUG) { + Log.i(LOG_TAG, "Clearing content frame stats for window: " + windowId); + } + // Calling out without a lock held. + return mUiAutomationConnection.clearWindowContentFrameStats(windowId); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error clearing window content frame stats!", re); + } + return false; + } + + /** + * Gets the frame statistics for a given window. These statistics contain + * information about the most recently rendered content frames. + * <p> + * A typical usage requires clearing the window frame statistics via {@link + * #clearWindowContentFrameStats(int)} followed by an interaction with the UI and + * finally getting the window frame statistics via calling this method. + * </p> + * <pre> + * // Assume we have at least one window. + * final int windowId = getWindows().get(0).getId(); + * + * // Start with a clean slate. + * uiAutimation.clearWindowContentFrameStats(windowId); + * + * // Do stuff with the UI. + * + * // Get the frame statistics. + * WindowContentFrameStats stats = uiAutomation.getWindowContentFrameStats(windowId); + * </pre> + * + * @param windowId The window id. + * @return The window frame statistics, or null if the window is not present. + * + * @see android.view.WindowContentFrameStats + * @see #clearWindowContentFrameStats(int) + * @see #getWindows() + * @see AccessibilityWindowInfo#getId() AccessibilityWindowInfo.getId() + */ + public WindowContentFrameStats getWindowContentFrameStats(int windowId) { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + try { + if (DEBUG) { + Log.i(LOG_TAG, "Getting content frame stats for window: " + windowId); + } + // Calling out without a lock held. + return mUiAutomationConnection.getWindowContentFrameStats(windowId); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error getting window content frame stats!", re); + } + return null; + } + + /** + * Clears the window animation rendering statistics. These statistics contain + * information about the most recently rendered window animation frames, i.e. + * for window transition animations. + * + * @see android.view.WindowAnimationFrameStats + * @see #getWindowAnimationFrameStats() + * @see android.R.styleable#WindowAnimation + */ + public void clearWindowAnimationFrameStats() { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + try { + if (DEBUG) { + Log.i(LOG_TAG, "Clearing window animation frame stats"); + } + // Calling out without a lock held. + mUiAutomationConnection.clearWindowAnimationFrameStats(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error clearing window animation frame stats!", re); + } + } + + /** + * Gets the window animation frame statistics. These statistics contain + * information about the most recently rendered window animation frames, i.e. + * for window transition animations. + * + * <p> + * A typical usage requires clearing the window animation frame statistics via + * {@link #clearWindowAnimationFrameStats()} followed by an interaction that causes + * a window transition which uses a window animation and finally getting the window + * animation frame statistics by calling this method. + * </p> + * <pre> + * // Start with a clean slate. + * uiAutimation.clearWindowAnimationFrameStats(); + * + * // Do stuff to trigger a window transition. + * + * // Get the frame statistics. + * WindowAnimationFrameStats stats = uiAutomation.getWindowAnimationFrameStats(); + * </pre> + * + * @return The window animation frame statistics. + * + * @see android.view.WindowAnimationFrameStats + * @see #clearWindowAnimationFrameStats() + * @see android.R.styleable#WindowAnimation + */ + public WindowAnimationFrameStats getWindowAnimationFrameStats() { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + try { + if (DEBUG) { + Log.i(LOG_TAG, "Getting window animation frame stats"); + } + // Calling out without a lock held. + return mUiAutomationConnection.getWindowAnimationFrameStats(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error getting window animation frame stats!", re); + } + return null; + } + private static float getDegreesForRotation(int value) { switch (value) { case Surface.ROTATION_90: { diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index 91b0d7c..fa40286 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -22,12 +22,15 @@ import android.content.Context; import android.graphics.Bitmap; import android.hardware.input.InputManager; import android.os.Binder; +import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.view.IWindowManager; import android.view.InputEvent; import android.view.SurfaceControl; +import android.view.WindowAnimationFrameStats; +import android.view.WindowContentFrameStats; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.IAccessibilityManager; @@ -47,6 +50,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Service.WINDOW_SERVICE)); + private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface( + ServiceManager.getService(Service.ACCESSIBILITY_SERVICE)); + private final Object mLock = new Object(); private final Binder mToken = new Binder(); @@ -144,6 +150,76 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } @Override + public boolean clearWindowContentFrameStats(int windowId) throws RemoteException { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + final long identity = Binder.clearCallingIdentity(); + try { + IBinder token = mAccessibilityManager.getWindowToken(windowId); + if (token == null) { + return false; + } + return mWindowManager.clearWindowContentFrameStats(token); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public WindowContentFrameStats getWindowContentFrameStats(int windowId) throws RemoteException { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + final long identity = Binder.clearCallingIdentity(); + try { + IBinder token = mAccessibilityManager.getWindowToken(windowId); + if (token == null) { + return null; + } + return mWindowManager.getWindowContentFrameStats(token); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void clearWindowAnimationFrameStats() { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + final long identity = Binder.clearCallingIdentity(); + try { + SurfaceControl.clearAnimationFrameStats(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public WindowAnimationFrameStats getWindowAnimationFrameStats() { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + final long identity = Binder.clearCallingIdentity(); + try { + WindowAnimationFrameStats stats = new WindowAnimationFrameStats(); + SurfaceControl.getAnimationFrameStats(stats); + return stats; + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void shutdown() { synchronized (mLock) { if (isConnectedLocked()) { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 30c84f6..d8be439 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1534,10 +1534,10 @@ public class DevicePolicyManager { /** * @hide */ - public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) { + public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing, int userHandle) { if (mService != null) { try { - mService.setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId()); + mService.setActiveAdmin(policyReceiver, refreshing, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1545,6 +1545,13 @@ public class DevicePolicyManager { } /** + * @hide + */ + public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) { + setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId()); + } + + /** * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data * @hide */ diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 101b721..ff3af7c 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -50,6 +50,7 @@ public final class BluetoothGatt implements BluetoothProfile { private boolean mAutoConnect; private int mConnState; private final Object mStateLock = new Object(); + private Boolean mDeviceBusy = false; private static final int CONN_STATE_IDLE = 0; private static final int CONN_STATE_CONNECTING = 1; @@ -166,6 +167,10 @@ public final class BluetoothGatt implements BluetoothProfile { mConnState = CONN_STATE_IDLE; } } + + synchronized(mDeviceBusy) { + mDeviceBusy = false; + } } /** @@ -301,6 +306,11 @@ public final class BluetoothGatt implements BluetoothProfile { if (!address.equals(mDevice.getAddress())) { return; } + + synchronized(mDeviceBusy) { + mDeviceBusy = false; + } + if ((status == GATT_INSUFFICIENT_AUTHENTICATION || status == GATT_INSUFFICIENT_ENCRYPTION) && mAuthRetry == false) { @@ -348,6 +358,11 @@ public final class BluetoothGatt implements BluetoothProfile { if (!address.equals(mDevice.getAddress())) { return; } + + synchronized(mDeviceBusy) { + mDeviceBusy = false; + } + BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(), srvcInstId, srvcType); if (service == null) return; @@ -425,6 +440,11 @@ public final class BluetoothGatt implements BluetoothProfile { if (!address.equals(mDevice.getAddress())) { return; } + + synchronized(mDeviceBusy) { + mDeviceBusy = false; + } + BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(), srvcInstId, srvcType); if (service == null) return; @@ -474,6 +494,11 @@ public final class BluetoothGatt implements BluetoothProfile { if (!address.equals(mDevice.getAddress())) { return; } + + synchronized(mDeviceBusy) { + mDeviceBusy = false; + } + BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(), srvcInstId, srvcType); if (service == null) return; @@ -519,6 +544,11 @@ public final class BluetoothGatt implements BluetoothProfile { if (!address.equals(mDevice.getAddress())) { return; } + + synchronized(mDeviceBusy) { + mDeviceBusy = false; + } + try { mCallback.onReliableWriteCompleted(BluetoothGatt.this, status); } catch (Exception ex) { @@ -851,6 +881,11 @@ public final class BluetoothGatt implements BluetoothProfile { BluetoothDevice device = service.getDevice(); if (device == null) return false; + synchronized(mDeviceBusy) { + if (mDeviceBusy) return false; + mDeviceBusy = true; + } + try { mService.readCharacteristic(mClientIf, device.getAddress(), service.getType(), service.getInstanceId(), @@ -858,6 +893,7 @@ public final class BluetoothGatt implements BluetoothProfile { new ParcelUuid(characteristic.getUuid()), AUTHENTICATION_NONE); } catch (RemoteException e) { Log.e(TAG,"",e); + mDeviceBusy = false; return false; } @@ -890,6 +926,11 @@ public final class BluetoothGatt implements BluetoothProfile { BluetoothDevice device = service.getDevice(); if (device == null) return false; + synchronized(mDeviceBusy) { + if (mDeviceBusy) return false; + mDeviceBusy = true; + } + try { mService.writeCharacteristic(mClientIf, device.getAddress(), service.getType(), service.getInstanceId(), @@ -899,6 +940,7 @@ public final class BluetoothGatt implements BluetoothProfile { characteristic.getValue()); } catch (RemoteException e) { Log.e(TAG,"",e); + mDeviceBusy = false; return false; } @@ -930,6 +972,11 @@ public final class BluetoothGatt implements BluetoothProfile { BluetoothDevice device = service.getDevice(); if (device == null) return false; + synchronized(mDeviceBusy) { + if (mDeviceBusy) return false; + mDeviceBusy = true; + } + try { mService.readDescriptor(mClientIf, device.getAddress(), service.getType(), service.getInstanceId(), new ParcelUuid(service.getUuid()), @@ -938,6 +985,7 @@ public final class BluetoothGatt implements BluetoothProfile { AUTHENTICATION_NONE); } catch (RemoteException e) { Log.e(TAG,"",e); + mDeviceBusy = false; return false; } @@ -968,6 +1016,11 @@ public final class BluetoothGatt implements BluetoothProfile { BluetoothDevice device = service.getDevice(); if (device == null) return false; + synchronized(mDeviceBusy) { + if (mDeviceBusy) return false; + mDeviceBusy = true; + } + try { mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(), service.getInstanceId(), new ParcelUuid(service.getUuid()), @@ -977,6 +1030,7 @@ public final class BluetoothGatt implements BluetoothProfile { descriptor.getValue()); } catch (RemoteException e) { Log.e(TAG,"",e); + mDeviceBusy = false; return false; } @@ -1034,10 +1088,16 @@ public final class BluetoothGatt implements BluetoothProfile { if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress()); if (mService == null || mClientIf == 0) return false; + synchronized(mDeviceBusy) { + if (mDeviceBusy) return false; + mDeviceBusy = true; + } + try { mService.endReliableWrite(mClientIf, mDevice.getAddress(), true); } catch (RemoteException e) { Log.e(TAG,"",e); + mDeviceBusy = false; return false; } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 5d02ae9..0d1b262 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -447,6 +447,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public String nativeLibraryDir; /** + * The ABI that this application requires, This is inferred from the ABIs + * of the native JNI libraries the application bundles. Will be {@code null} + * if this application does not require any particular ABI. + * + * {@hide} + */ + public String requiredCpuAbi; + + /** * The kernel user-ID that has been assigned to this application; * currently this is not a unique ID (multiple applications can have * the same uid). @@ -583,6 +592,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { sourceDir = orig.sourceDir; publicSourceDir = orig.publicSourceDir; nativeLibraryDir = orig.nativeLibraryDir; + requiredCpuAbi = orig.requiredCpuAbi; resourceDirs = orig.resourceDirs; seinfo = orig.seinfo; sharedLibraryFiles = orig.sharedLibraryFiles; @@ -624,6 +634,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(sourceDir); dest.writeString(publicSourceDir); dest.writeString(nativeLibraryDir); + dest.writeString(requiredCpuAbi); dest.writeStringArray(resourceDirs); dest.writeString(seinfo); dest.writeStringArray(sharedLibraryFiles); @@ -664,6 +675,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { sourceDir = source.readString(); publicSourceDir = source.readString(); nativeLibraryDir = source.readString(); + requiredCpuAbi = source.readString(); resourceDirs = source.readStringArray(); seinfo = source.readString(); sharedLibraryFiles = source.readStringArray(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3300e9d..d24a472 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -698,6 +698,25 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112; /** + * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} + * if the system failed to install the package because its packaged native code did not + * match any of the ABIs supported by the system. + * + * @hide + */ + public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -113; + + /** + * Internal return code for NativeLibraryHelper methods to indicate that the package + * being processed did not contain any native code. This is placed here only so that + * it can belong to the same value space as the other install failure codes. + * + * @hide + */ + public static final int NO_NATIVE_LIBRARIES = -114; + + /** * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the * package's data directory. * diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 1e34498..9b1bc53 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -940,6 +940,17 @@ public abstract class CameraMetadata { */ public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5; + /** + * <p>This request is for manual capture use case where + * the applications want to directly control the capture parameters + * (e.g. {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} etc.).</p> + * + * @see CaptureRequest#SENSOR_EXPOSURE_TIME + * @see CaptureRequest#SENSOR_SENSITIVITY + * @see CaptureRequest#CONTROL_CAPTURE_INTENT + */ + public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6; + // // Enumeration values for CaptureRequest#CONTROL_EFFECT_MODE // diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 7656505..c4e342c 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -714,16 +714,21 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * auto-focus, auto-white balance) routines about the purpose * of this capture, to help the camera device to decide optimal 3A * strategy.</p> - * <p>This control is only effective if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> - * and any 3A routine is active.</p> + * <p>This control (except for MANUAL) is only effective if + * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p> + * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} + * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} + * contains MANUAL_SENSOR.</p> * * @see CaptureRequest#CONTROL_MODE + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES * @see #CONTROL_CAPTURE_INTENT_CUSTOM * @see #CONTROL_CAPTURE_INTENT_PREVIEW * @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE * @see #CONTROL_CAPTURE_INTENT_VIDEO_RECORD * @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT * @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG + * @see #CONTROL_CAPTURE_INTENT_MANUAL */ public static final Key<Integer> CONTROL_CAPTURE_INTENT = new Key<Integer>("android.control.captureIntent", int.class); diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/CaptureResultExtras.aidl new file mode 100644 index 0000000..6587f02 --- /dev/null +++ b/core/java/android/hardware/camera2/CaptureResultExtras.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +/** @hide */ +parcelable CaptureResultExtras; diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/CaptureResultExtras.java new file mode 100644 index 0000000..e5c2c1c --- /dev/null +++ b/core/java/android/hardware/camera2/CaptureResultExtras.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class CaptureResultExtras implements Parcelable { + private int requestId; + private int subsequenceId; + private int afTriggerId; + private int precaptureTriggerId; + private long frameNumber; + + public static final Parcelable.Creator<CaptureResultExtras> CREATOR = + new Parcelable.Creator<CaptureResultExtras>() { + @Override + public CaptureResultExtras createFromParcel(Parcel in) { + return new CaptureResultExtras(in); + } + + @Override + public CaptureResultExtras[] newArray(int size) { + return new CaptureResultExtras[size]; + } + }; + + private CaptureResultExtras(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(requestId); + dest.writeInt(subsequenceId); + dest.writeInt(afTriggerId); + dest.writeInt(precaptureTriggerId); + dest.writeLong(frameNumber); + } + + public void readFromParcel(Parcel in) { + requestId = in.readInt(); + subsequenceId = in.readInt(); + afTriggerId = in.readInt(); + precaptureTriggerId = in.readInt(); + frameNumber = in.readLong(); + } + + public int getRequestId() { + return requestId; + } + + public int getSubsequenceId() { + return subsequenceId; + } + + public int getAfTriggerId() { + return afTriggerId; + } + + public int getPrecaptureTriggerId() { + return precaptureTriggerId; + } + + public long getFrameNumber() { + return frameNumber; + } + +} diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl index 02a73d66..a14d38b 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl @@ -17,6 +17,7 @@ package android.hardware.camera2; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.CaptureResultExtras; /** @hide */ interface ICameraDeviceCallbacks @@ -25,8 +26,9 @@ interface ICameraDeviceCallbacks * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h */ - oneway void onCameraError(int errorCode); + oneway void onCameraError(int errorCode, in CaptureResultExtras resultExtras); oneway void onCameraIdle(); - oneway void onCaptureStarted(int requestId, long timestamp); - oneway void onResultReceived(int requestId, in CameraMetadataNative result); + oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp); + oneway void onResultReceived(in CameraMetadataNative result, + in CaptureResultExtras resultExtras); } diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index 1936963..d77f3d1 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -20,6 +20,8 @@ import android.view.Surface; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.LongParcelable; + /** @hide */ interface ICameraDeviceUser { @@ -31,9 +33,13 @@ interface ICameraDeviceUser // ints here are status_t // non-negative value is the requestId. negative value is status_t - int submitRequest(in CaptureRequest request, boolean streaming); + int submitRequest(in CaptureRequest request, boolean streaming, + out LongParcelable lastFrameNumber); + + int submitRequestList(in List<CaptureRequest> requestList, boolean streaming, + out LongParcelable lastFrameNumber); - int cancelRequest(int requestId); + int cancelRequest(int requestId, out LongParcelable lastFrameNumber); int deleteStream(int streamId); @@ -46,5 +52,5 @@ interface ICameraDeviceUser int waitUntilIdle(); - int flush(); + int flush(out LongParcelable lastFrameNumber); } diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/LongParcelable.aidl new file mode 100644 index 0000000..7d7e51b --- /dev/null +++ b/core/java/android/hardware/camera2/LongParcelable.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +/** @hide */ +parcelable LongParcelable;
\ No newline at end of file diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/LongParcelable.java new file mode 100644 index 0000000..97b0631 --- /dev/null +++ b/core/java/android/hardware/camera2/LongParcelable.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class LongParcelable implements Parcelable { + private long number; + + public LongParcelable() { + this.number = 0; + } + + public LongParcelable(long number) { + this.number = number; + } + + public static final Parcelable.Creator<LongParcelable> CREATOR = + new Parcelable.Creator<LongParcelable>() { + @Override + public LongParcelable createFromParcel(Parcel in) { + return new LongParcelable(in); + } + + @Override + public LongParcelable[] newArray(int size) { + return new LongParcelable[size]; + } + }; + + private LongParcelable(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(number); + } + + public void readFromParcel(Parcel in) { + number = in.readLong(); + } + + public long getNumber() { + return number; + } + + public void setNumber(long number) { + this.number = number; + } + +} diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java index ecc461e..cd44b51 100644 --- a/core/java/android/hardware/camera2/impl/CameraDevice.java +++ b/core/java/android/hardware/camera2/impl/CameraDevice.java @@ -21,8 +21,10 @@ import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.CaptureResultExtras; import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; +import android.hardware.camera2.LongParcelable; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; import android.os.Handler; @@ -33,10 +35,12 @@ import android.util.Log; import android.util.SparseArray; import android.view.Surface; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.TreeSet; /** * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate @@ -69,10 +73,24 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { private final String mCameraId; + /** + * A list tracking request and its expected last frame. + * Updated when calling ICameraDeviceUser methods. + */ + private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>> + mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>(); + + /** + * An object tracking received frame numbers. + * Updated when receiving callbacks from ICameraDeviceCallbacks. + */ + private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker(); + // Runnables for all state transitions, except error, which needs the // error code argument private final Runnable mCallOnOpened = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onOpened(CameraDevice.this); @@ -81,6 +99,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnUnconfigured = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onUnconfigured(CameraDevice.this); @@ -89,6 +108,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnActive = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onActive(CameraDevice.this); @@ -97,6 +117,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnBusy = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onBusy(CameraDevice.this); @@ -105,12 +126,14 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnClosed = new Runnable() { + @Override public void run() { mDeviceListener.onClosed(CameraDevice.this); } }; private final Runnable mCallOnIdle = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onIdle(CameraDevice.this); @@ -119,6 +142,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnDisconnected = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onDisconnected(CameraDevice.this); @@ -249,22 +273,26 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { @Override public int capture(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException { - return submitCaptureRequest(request, listener, handler, /*streaming*/false); + if (DEBUG) { + Log.d(TAG, "calling capture"); + } + List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); + requestList.add(request); + return submitCaptureRequest(requestList, listener, handler, /*streaming*/false); } @Override public int captureBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException { + // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc. if (requests.isEmpty()) { Log.w(TAG, "Capture burst request list is empty, do nothing!"); return -1; } - // TODO - throw new UnsupportedOperationException("Burst capture implemented yet"); - + return submitCaptureRequest(requests, listener, handler, /*streaming*/false); } - private int submitCaptureRequest(CaptureRequest request, CaptureListener listener, + private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener, Handler handler, boolean repeating) throws CameraAccessException { // Need a valid handler, or current thread needs to have a looper, if @@ -281,8 +309,13 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { stopRepeating(); } + LongParcelable lastFrameNumberRef = new LongParcelable(); try { - requestId = mRemoteDevice.submitRequest(request, repeating); + requestId = mRemoteDevice.submitRequestList(requestList, repeating, + /*out*/lastFrameNumberRef); + if (!repeating) { + Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber()); + } } catch (CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { @@ -290,12 +323,29 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { return -1; } if (listener != null) { - mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request, - handler, repeating)); + mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, + requestList, handler, repeating)); } + long lastFrameNumber = lastFrameNumberRef.getNumber(); + /** + * If it's the first repeating request, then returned lastFrameNumber can be + * negative. Otherwise, it should always be non-negative. + */ + if (((lastFrameNumber < 0) && (requestId > 0)) + || ((lastFrameNumber < 0) && (!repeating))) { + throw new AssertionError(String.format("returned bad frame number %d", + lastFrameNumber)); + } if (repeating) { + if (mRepeatingRequestId != REQUEST_ID_NONE) { + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId)); + } mRepeatingRequestId = requestId; + } else { + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, requestId)); } if (mIdle) { @@ -310,18 +360,20 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { @Override public int setRepeatingRequest(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException { - return submitCaptureRequest(request, listener, handler, /*streaming*/true); + List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); + requestList.add(request); + return submitCaptureRequest(requestList, listener, handler, /*streaming*/true); } @Override public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException { + // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc. if (requests.isEmpty()) { Log.w(TAG, "Set Repeating burst request list is empty, do nothing!"); return -1; } - // TODO - throw new UnsupportedOperationException("Burst capture implemented yet"); + return submitCaptureRequest(requests, listener, handler, /*streaming*/true); } @Override @@ -340,7 +392,15 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } try { - mRemoteDevice.cancelRequest(requestId); + LongParcelable lastFrameNumberRef = new LongParcelable(); + mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef); + long lastFrameNumber = lastFrameNumberRef.getNumber(); + if ((lastFrameNumber < 0) && (requestId > 0)) { + throw new AssertionError(String.format("returned bad frame number %d", + lastFrameNumber)); + } + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, requestId)); } catch (CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { @@ -379,7 +439,17 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { mDeviceHandler.post(mCallOnBusy); try { - mRemoteDevice.flush(); + LongParcelable lastFrameNumberRef = new LongParcelable(); + mRemoteDevice.flush(/*out*/lastFrameNumberRef); + if (mRepeatingRequestId != REQUEST_ID_NONE) { + long lastFrameNumber = lastFrameNumberRef.getNumber(); + if (lastFrameNumber < 0) { + Log.e(TAG, String.format("returned bad frame number %d", lastFrameNumber)); + } + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId)); + mRepeatingRequestId = REQUEST_ID_NONE; + } } catch (CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { @@ -425,18 +495,18 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { private final boolean mRepeating; private final CaptureListener mListener; - private final CaptureRequest mRequest; + private final List<CaptureRequest> mRequestList; private final Handler mHandler; - CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler, - boolean repeating) { + CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList, + Handler handler, boolean repeating) { if (listener == null || handler == null) { throw new UnsupportedOperationException( "Must have a valid handler and a valid listener"); } mRepeating = repeating; mHandler = handler; - mRequest = request; + mRequestList = new ArrayList<CaptureRequest>(requestList); mListener = listener; } @@ -448,8 +518,24 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { return mListener; } + public CaptureRequest getRequest(int subsequenceId) { + if (subsequenceId >= mRequestList.size()) { + throw new IllegalArgumentException( + String.format( + "Requested subsequenceId %d is larger than request list size %d.", + subsequenceId, mRequestList.size())); + } else { + if (subsequenceId < 0) { + throw new IllegalArgumentException(String.format( + "Requested subsequenceId %d is negative", subsequenceId)); + } else { + return mRequestList.get(subsequenceId); + } + } + } + public CaptureRequest getRequest() { - return mRequest; + return getRequest(0); } public Handler getHandler() { @@ -458,6 +544,105 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } + /** + * This class tracks the last frame number for submitted requests. + */ + public class FrameNumberTracker { + + private long mCompletedFrameNumber = -1; + private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>(); + + private void update() { + Iterator<Long> iter = mFutureErrorSet.iterator(); + while (iter.hasNext()) { + long errorFrameNumber = iter.next(); + if (errorFrameNumber == mCompletedFrameNumber + 1) { + mCompletedFrameNumber++; + iter.remove(); + } else { + break; + } + } + } + + /** + * This function is called every time when a result or an error is received. + * @param frameNumber: the frame number corresponding to the result or error + * @param isError: true if it is an error, false if it is not an error + */ + public void updateTracker(long frameNumber, boolean isError) { + if (isError) { + mFutureErrorSet.add(frameNumber); + } else { + /** + * HAL cannot send an OnResultReceived for frame N unless it knows for + * sure that all frames prior to N have either errored out or completed. + * So if the current frame is not an error, then all previous frames + * should have arrived. The following line checks whether this holds. + */ + if (frameNumber != mCompletedFrameNumber + 1) { + throw new AssertionError(String.format( + "result frame number %d comes out of order", + frameNumber)); + } + mCompletedFrameNumber++; + } + update(); + } + + public long getCompletedFrameNumber() { + return mCompletedFrameNumber; + } + + } + + private void checkAndFireSequenceComplete() { + long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber(); + Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator(); + while (iter.hasNext()) { + final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next(); + if (frameNumberRequestPair.getKey() <= completedFrameNumber) { + + // remove request from mCaptureListenerMap + final int requestId = frameNumberRequestPair.getValue(); + final CaptureListenerHolder holder; + synchronized (mLock) { + int index = CameraDevice.this.mCaptureListenerMap.indexOfKey(requestId); + holder = (index >= 0) ? CameraDevice.this.mCaptureListenerMap.valueAt(index) + : null; + if (holder != null) { + CameraDevice.this.mCaptureListenerMap.removeAt(index); + } + } + iter.remove(); + + // Call onCaptureSequenceCompleted + if (holder != null) { + Runnable resultDispatch = new Runnable() { + @Override + public void run() { + if (!CameraDevice.this.isClosed()){ + if (DEBUG) { + Log.d(TAG, String.format( + "fire sequence complete for request %d", + requestId)); + } + + holder.getListener().onCaptureSequenceCompleted( + CameraDevice.this, + requestId, + // TODO: this is problematic, crop long to int + frameNumberRequestPair.getKey().intValue()); + } + } + }; + holder.getHandler().post(resultDispatch); + } + + } + } + } + public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { // @@ -492,7 +677,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override - public void onCameraError(final int errorCode) { + public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) { Runnable r = null; if (isClosed()) return; @@ -507,6 +692,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { case ERROR_CAMERA_DEVICE: case ERROR_CAMERA_SERVICE: r = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onError(CameraDevice.this, errorCode); @@ -517,6 +703,11 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } CameraDevice.this.mDeviceHandler.post(r); } + + // Fire onCaptureSequenceCompleted + mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true); + checkAndFireSequenceComplete(); + } @Override @@ -535,7 +726,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override - public void onCaptureStarted(int requestId, final long timestamp) { + public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) { + int requestId = resultExtras.getRequestId(); if (DEBUG) { Log.d(TAG, "Capture started for id " + requestId); } @@ -555,11 +747,12 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { // Dispatch capture start notice holder.getHandler().post( new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { holder.getListener().onCaptureStarted( CameraDevice.this, - holder.getRequest(), + holder.getRequest(resultExtras.getSubsequenceId()), timestamp); } } @@ -567,48 +760,18 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override - public void onResultReceived(int requestId, CameraMetadataNative result) - throws RemoteException { + public void onResultReceived(CameraMetadataNative result, + CaptureResultExtras resultExtras) throws RemoteException { + int requestId = resultExtras.getRequestId(); if (DEBUG) { Log.d(TAG, "Received result for id " + requestId); } - final CaptureListenerHolder holder; + final CaptureListenerHolder holder = + CameraDevice.this.mCaptureListenerMap.get(requestId); Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT); boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial); - synchronized (mLock) { - // TODO: move this whole map into this class to make it more testable, - // exposing the methods necessary like subscribeToRequest, unsubscribe.. - // TODO: make class static class - - holder = CameraDevice.this.mCaptureListenerMap.get(requestId); - - // Clean up listener once we no longer expect to see it. - if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) { - CameraDevice.this.mCaptureListenerMap.remove(requestId); - } - - // TODO: add 'capture sequence completed' callback to the - // service, and clean up repeating requests there instead. - - // If we received a result for a repeating request and have - // prior repeating requests queued for deletion, remove those - // requests from mCaptureListenerMap. - if (holder != null && holder.isRepeating() && !quirkIsPartialResult - && mRepeatingRequestIdDeletedList.size() > 0) { - Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator(); - while (iter.hasNext()) { - int deletedRequestId = iter.next(); - if (deletedRequestId < requestId) { - CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId); - iter.remove(); - } - } - } - - } - // Check if we have a listener for this if (holder == null) { return; @@ -616,7 +779,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { if (isClosed()) return; - final CaptureRequest request = holder.getRequest(); + final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId()); final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId); Runnable resultDispatch = null; @@ -651,6 +814,12 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } holder.getHandler().post(resultDispatch); + + // Fire onCaptureSequenceCompleted + if (!quirkIsPartialResult) { + mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false); + checkAndFireSequenceComplete(); + } } } diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 0d4a4cb..c5e5753 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -461,6 +461,10 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return (T) getFaces(); } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { return (T) getFaceRectangles(); + } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) { + return (T) getAvailableStreamConfigurations(); + } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) { + return (T) getAvailableMinFrameDurations(); } // For other keys, get() falls back to getBase() @@ -481,6 +485,50 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return availableFormats; } + private int[] getAvailableStreamConfigurations() { + final int NUM_ELEMENTS_IN_CONFIG = 4; + int[] availableConfigs = + getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); + if (availableConfigs != null) { + if (availableConfigs.length % NUM_ELEMENTS_IN_CONFIG != 0) { + Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple" + + " of " + NUM_ELEMENTS_IN_CONFIG); + return availableConfigs; + } + + for (int i = 0; i < availableConfigs.length; i += NUM_ELEMENTS_IN_CONFIG) { + // JPEG has different value between native and managed side, need override. + if (availableConfigs[i] == NATIVE_JPEG_FORMAT) { + availableConfigs[i] = ImageFormat.JPEG; + } + } + } + + return availableConfigs; + } + + private long[] getAvailableMinFrameDurations() { + final int NUM_ELEMENTS_IN_DURATION = 4; + long[] availableMinDurations = + getBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); + if (availableMinDurations != null) { + if (availableMinDurations.length % NUM_ELEMENTS_IN_DURATION != 0) { + Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple" + + " of " + NUM_ELEMENTS_IN_DURATION); + return availableMinDurations; + } + + for (int i = 0; i < availableMinDurations.length; i += NUM_ELEMENTS_IN_DURATION) { + // JPEG has different value between native and managed side, need override. + if (availableMinDurations[i] == NATIVE_JPEG_FORMAT) { + availableMinDurations[i] = ImageFormat.JPEG; + } + } + } + + return availableMinDurations; + } + private Face[] getFaces() { final int FACE_LANDMARK_SIZE = 6; @@ -607,12 +655,56 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return setAvailableFormats((int[]) value); } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { return setFaceRectangles((Rect[]) value); + } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) { + return setAvailableStreamConfigurations((int[])value); + } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) { + return setAvailableMinFrameDurations((long[])value); } // For other keys, set() falls back to setBase(). return false; } + private boolean setAvailableStreamConfigurations(int[] value) { + final int NUM_ELEMENTS_IN_CONFIG = 4; + int[] availableConfigs = value; + if (value == null) { + // Let setBase() to handle the null value case. + return false; + } + + int[] newValues = new int[availableConfigs.length]; + for (int i = 0; i < availableConfigs.length; i++) { + newValues[i] = availableConfigs[i]; + if (i % NUM_ELEMENTS_IN_CONFIG == 0 && availableConfigs[i] == ImageFormat.JPEG) { + newValues[i] = NATIVE_JPEG_FORMAT; + } + } + + setBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, newValues); + return true; + } + + private boolean setAvailableMinFrameDurations(long[] value) { + final int NUM_ELEMENTS_IN_DURATION = 4; + long[] availableDurations = value; + if (value == null) { + // Let setBase() to handle the null value case. + return false; + } + + long[] newValues = new long[availableDurations.length]; + for (int i = 0; i < availableDurations.length; i++) { + newValues[i] = availableDurations[i]; + if (i % NUM_ELEMENTS_IN_DURATION == 0 && availableDurations[i] == ImageFormat.JPEG) { + newValues[i] = NATIVE_JPEG_FORMAT; + } + } + + setBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS, newValues); + return true; + } + private boolean setAvailableFormats(int[] value) { int[] availableFormat = value; if (value == null) { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index c8051aa..7f1a2e4 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -74,7 +74,14 @@ public class Build { /** A hardware serial number, if available. Alphanumeric only, case-insensitive. */ public static final String SERIAL = getString("ro.serialno"); - + + /** + * A list of ABIs (in priority) order supported by this device. + * + * @hide + */ + public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(","); + /** Various version strings. */ public static class VERSION { /** diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 79ff49c..c947eda 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -466,6 +466,7 @@ public class Process { * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param seInfo null-ok SELinux information for the new process. + * @param abi non-null the ABI this app should be started with. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. @@ -479,12 +480,12 @@ public class Process { int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, + String abi, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, - null, /* zygoteAbi TODO: Replace this with the real ABI */ - zygoteArgs); + abi, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -702,13 +703,6 @@ public class Process { primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET, getNumTries(primaryZygoteState)); } - // TODO: Revert this temporary change. This is required to test - // and submit this change ahead of the package manager changes - // that supply this abi. - if (abi == null) { - return primaryZygoteState; - } - if (primaryZygoteState.matches(abi)) { return primaryZygoteState; } diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 2ef5b66..939cda9 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -625,12 +625,13 @@ public interface IMountService extends IInterface { return _result; } - public int encryptStorage(String password) throws RemoteException { + public int encryptStorage(int type, String password) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(type); _data.writeString(password); mRemote.transact(Stub.TRANSACTION_encryptStorage, _data, _reply, 0); _reply.readException(); @@ -1210,8 +1211,9 @@ public interface IMountService extends IInterface { } case TRANSACTION_encryptStorage: { data.enforceInterface(DESCRIPTOR); + int type = data.readInt(); String password = data.readString(); - int result = encryptStorage(password); + int result = encryptStorage(type, password); reply.writeNoException(); reply.writeInt(result); return true; @@ -1495,7 +1497,7 @@ public interface IMountService extends IInterface { /** * Encrypts storage. */ - public int encryptStorage(String password) throws RemoteException; + public int encryptStorage(int type, String password) throws RemoteException; /** * Changes the encryption password. diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 144c909..56d5617 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -533,8 +533,7 @@ public class Preference implements Comparable<Preference> { * @see #onCreateView(ViewGroup) */ protected void onBindView(View view) { - final TextView titleView = (TextView) view.findViewById( - com.android.internal.R.id.title); + final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title); if (titleView != null) { final CharSequence title = getTitle(); if (!TextUtils.isEmpty(title)) { @@ -557,7 +556,7 @@ public class Preference implements Comparable<Preference> { } } - ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon); + final ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon); if (imageView != null) { if (mIconResId != 0 || mIcon != null) { if (mIcon == null) { @@ -570,6 +569,11 @@ public class Preference implements Comparable<Preference> { imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE); } + final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame); + if (imageFrame != null) { + imageFrame.setVisibility(mIcon != null ? View.VISIBLE : View.GONE); + } + if (mShouldDisableView) { setEnabledStateOnViews(view, isEnabled()); } diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java index 05f3a1c..1754dce 100644 --- a/core/java/android/provider/SearchIndexablesContract.java +++ b/core/java/android/provider/SearchIndexablesContract.java @@ -58,33 +58,64 @@ public class SearchIndexablesContract { * Indexable xml resources colums. */ public static final String[] INDEXABLES_XML_RES_COLUMNS = new String[] { - XmlResource.COLUMN_RANK, - XmlResource.COLUMN_XML_RESID, - XmlResource.COLUMN_CLASS_NAME, - XmlResource.COLUMN_ICON_RESID, - XmlResource.COLUMN_INTENT_ACTION, - XmlResource.COLUMN_INTENT_TARGET_PACKAGE, - XmlResource.COLUMN_INTENT_TARGET_CLASS + XmlResource.COLUMN_RANK, // 0 + XmlResource.COLUMN_XML_RESID, // 1 + XmlResource.COLUMN_CLASS_NAME, // 2 + XmlResource.COLUMN_ICON_RESID, // 3 + XmlResource.COLUMN_INTENT_ACTION, // 4 + XmlResource.COLUMN_INTENT_TARGET_PACKAGE, // 5 + XmlResource.COLUMN_INTENT_TARGET_CLASS // 6 }; /** + * Indexable xml resources colums indices. + */ + public static final int COLUMN_INDEX_XML_RES_RANK = 0; + public static final int COLUMN_INDEX_XML_RES_RESID = 1; + public static final int COLUMN_INDEX_XML_RES_CLASS_NAME = 2; + public static final int COLUMN_INDEX_XML_RES_ICON_RESID = 3; + public static final int COLUMN_INDEX_XML_RES_INTENT_ACTION = 4; + public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE = 5; + public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS = 6; + + /** * Indexable raw data colums. */ public static final String[] INDEXABLES_RAW_COLUMNS = new String[] { - RawData.COLUMN_RANK, - RawData.COLUMN_TITLE, - RawData.COLUMN_SUMMARY_ON, - RawData.COLUMN_SUMMARY_OFF, - RawData.COLUMN_KEYWORDS, - RawData.COLUMN_SCREEN_TITLE, - RawData.COLUMN_CLASS_NAME, - RawData.COLUMN_ICON_RESID, - RawData.COLUMN_INTENT_ACTION, - RawData.COLUMN_INTENT_TARGET_PACKAGE, - RawData.COLUMN_INTENT_TARGET_CLASS, + RawData.COLUMN_RANK, // 0 + RawData.COLUMN_TITLE, // 1 + RawData.COLUMN_SUMMARY_ON, // 2 + RawData.COLUMN_SUMMARY_OFF, // 3 + RawData.COLUMN_ENTRIES, // 4 + RawData.COLUMN_KEYWORDS, // 5 + RawData.COLUMN_SCREEN_TITLE, // 6 + RawData.COLUMN_CLASS_NAME, // 7 + RawData.COLUMN_ICON_RESID, // 8 + RawData.COLUMN_INTENT_ACTION, // 9 + RawData.COLUMN_INTENT_TARGET_PACKAGE, // 10 + RawData.COLUMN_INTENT_TARGET_CLASS, // 11 + RawData.COLUMN_KEY, // 12 }; /** + * Indexable raw data colums indices. + */ + public static final int COLUMN_INDEX_RAW_RANK = 0; + public static final int COLUMN_INDEX_RAW_TITLE = 1; + public static final int COLUMN_INDEX_RAW_SUMMARY_ON = 2; + public static final int COLUMN_INDEX_RAW_SUMMARY_OFF = 3; + public static final int COLUMN_INDEX_RAW_ENTRIES = 4; + public static final int COLUMN_INDEX_RAW_KEYWORDS = 5; + public static final int COLUMN_INDEX_RAW_SCREEN_TITLE = 6; + public static final int COLUMN_INDEX_RAW_CLASS_NAME = 7; + public static final int COLUMN_INDEX_RAW_ICON_RESID = 8; + public static final int COLUMN_INDEX_RAW_INTENT_ACTION = 9; + public static final int COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE = 10; + public static final int COLUMN_INDEX_RAW_INTENT_TARGET_CLASS = 11; + public static final int COLUMN_INDEX_RAW_KEY = 12; + + + /** * Constants related to a {@link SearchIndexableResource}. * * This is a description of @@ -134,6 +165,11 @@ public class SearchIndexablesContract { public static final String COLUMN_SUMMARY_OFF = "summaryOff"; /** + * Entries associated with the raw data (when the data can can several values). + */ + public static final String COLUMN_ENTRIES = "entries"; + + /** * Keywords' raw data. */ public static final String COLUMN_KEYWORDS = "keywords"; @@ -142,6 +178,11 @@ public class SearchIndexablesContract { * Fragment's title associated with the raw data. */ public static final String COLUMN_SCREEN_TITLE = "screenTitle"; + + /** + * Key associated with the raw data. The key needs to be unique. + */ + public static final String COLUMN_KEY = "key"; } /** diff --git a/core/java/android/view/AnimationRenderStats.aidl b/core/java/android/view/AnimationRenderStats.aidl new file mode 100644 index 0000000..4599708 --- /dev/null +++ b/core/java/android/view/AnimationRenderStats.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +parcelable AnimationRenderStats; diff --git a/core/java/android/view/FrameStats.java b/core/java/android/view/FrameStats.java new file mode 100644 index 0000000..541b336 --- /dev/null +++ b/core/java/android/view/FrameStats.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This is the base class for frame statistics. + */ +public abstract class FrameStats { + /** + * Undefined time. + */ + public static final long UNDEFINED_TIME_NANO = -1; + + protected long mRefreshPeriodNano; + protected long[] mFramesPresentedTimeNano; + + /** + * Gets the refresh period of the display hosting the window(s) for + * which these statistics apply. + * + * @return The refresh period in nanoseconds. + */ + public final long getRefreshPeriodNano() { + return mRefreshPeriodNano; + } + + /** + * Gets the number of frames for which there is data. + * + * @return The number of frames. + */ + public final int getFrameCount() { + return mFramesPresentedTimeNano != null + ? mFramesPresentedTimeNano.length : 0; + } + + /** + * Gets the start time of the interval for which these statistics + * apply. The start interval is the time when the first frame was + * presented. + * + * @return The start time in nanoseconds or {@link #UNDEFINED_TIME_NANO} + * if there is no frame data. + */ + public final long getStartTimeNano() { + if (getFrameCount() <= 0) { + return UNDEFINED_TIME_NANO; + } + return mFramesPresentedTimeNano[0]; + } + + /** + * Gets the end time of the interval for which these statistics + * apply. The end interval is the time when the last frame was + * presented. + * + * @return The end time in nanoseconds or {@link #UNDEFINED_TIME_NANO} + * if there is no frame data. + */ + public final long getEndTimeNano() { + if (getFrameCount() <= 0) { + return UNDEFINED_TIME_NANO; + } + return mFramesPresentedTimeNano[mFramesPresentedTimeNano.length - 1]; + } + + /** + * Get the time a frame at a given index was presented. + * + * @param index The frame index. + * @return The presented time in nanoseconds or {@link #UNDEFINED_TIME_NANO} + * if the frame is not presented yet. + */ + public final long getFramePresentedTimeNano(int index) { + if (mFramesPresentedTimeNano == null) { + throw new IndexOutOfBoundsException(); + } + return mFramesPresentedTimeNano[index]; + } +} diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index ad33b6f..eba4f7f 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -838,6 +838,11 @@ public class GLRenderer extends HardwareRenderer { } } + @Override + void pauseSurface(Surface surface) { + // No-op + } + boolean initializeEgl() { synchronized (sEglLock) { if (sEgl == null && sEglConfig == null) { @@ -1221,11 +1226,6 @@ public class GLRenderer extends HardwareRenderer { } } - void setDisplayListData(long displayList, long newData) { - nSetDisplayListData(displayList, newData); - } - private static native void nSetDisplayListData(long displayList, long newData); - @Override void fence() { // Everything is immediate, so this is a no-op @@ -1317,7 +1317,7 @@ public class GLRenderer extends HardwareRenderer { } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList"); - nUpdateRenderNodeProperties(displayList.getNativeDisplayList()); + nPrepareTree(displayList.getNativeDisplayList()); try { status |= canvas.drawDisplayList(displayList, mRedrawClip, RenderNode.FLAG_CLIP_CHILDREN); @@ -1476,7 +1476,7 @@ public class GLRenderer extends HardwareRenderer { static native void nDestroyLayer(long layerPtr); - private static native void nUpdateRenderNodeProperties(long displayListPtr); + private static native void nPrepareTree(long displayListPtr); class DrawPerformanceDataProvider extends GraphDataProvider { private final int mGraphType; diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 92d85d1..56d96e1 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -234,6 +234,13 @@ public abstract class HardwareRenderer { abstract void updateSurface(Surface surface) throws OutOfResourcesException; /** + * Stops any rendering into the surface. Use this if it is unclear whether + * or not the surface used by the HardwareRenderer will be changing. It + * Suspends any rendering into the surface, but will not do any destruction + */ + abstract void pauseSurface(Surface surface); + + /** * Destroys all hardware rendering resources associated with the specified * view hierarchy. * @@ -573,8 +580,6 @@ public abstract class HardwareRenderer { mRequested = requested; } - abstract void setDisplayListData(long displayList, long newData); - /** * Blocks until all previously queued work has completed. */ diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 8f542bb..80d5bf2 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -37,6 +37,7 @@ import android.view.MotionEvent; import android.view.InputChannel; import android.view.InputDevice; import android.view.IInputFilter; +import android.view.WindowContentFrameStats; /** * System private interface to the window manager. @@ -233,4 +234,20 @@ interface IWindowManager * Device is in safe mode. */ boolean isSafeModeEnabled(); + + /** + * Clears the frame statistics for a given window. + * + * @param token The window token. + * @return Whether the frame statistics were cleared. + */ + boolean clearWindowContentFrameStats(IBinder token); + + /** + * Gets the content frame statistics for a given window. + * + * @param token The window token. + * @return The frame statistics or null if the window does not exist. + */ + WindowContentFrameStats getWindowContentFrameStats(IBinder token); } diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 78ddf5b..30e4281 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -174,12 +174,10 @@ public class RenderNode { public static final int STATUS_DREW = 0x4; private boolean mValid; - private final long mNativeDisplayList; - private HardwareRenderer mRenderer; + private final long mNativeRenderNode; private RenderNode(String name) { - mNativeDisplayList = nCreate(); - nSetDisplayListName(mNativeDisplayList, name); + mNativeRenderNode = nCreate(name); } /** @@ -202,7 +200,7 @@ public class RenderNode { * stored in this display list. * * Calling this method will mark the render node invalid until - * {@link #end(HardwareRenderer, HardwareCanvas)} is called. + * {@link #end(HardwareCanvas)} is called. * Only valid render nodes can be replayed. * * @param width The width of the recording viewport @@ -210,7 +208,7 @@ public class RenderNode { * * @return A canvas to record drawing operations. * - * @see #end(HardwareRenderer, HardwareCanvas) + * @see #end(HardwareCanvas) * @see #isValid() */ public HardwareCanvas start(int width, int height) { @@ -229,21 +227,15 @@ public class RenderNode { * @see #start(int, int) * @see #isValid() */ - public void end(HardwareRenderer renderer, HardwareCanvas endCanvas) { + public void end(HardwareCanvas endCanvas) { if (!(endCanvas instanceof GLES20RecordingCanvas)) { throw new IllegalArgumentException("Passed an invalid canvas to end!"); } GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas; canvas.onPostDraw(); - long displayListData = canvas.finishRecording(); - if (renderer != mRenderer) { - // If we are changing renderers first destroy with the old - // renderer, then set with the new one - destroyDisplayListData(); - } - mRenderer = renderer; - setDisplayListData(displayListData); + long renderNodeData = canvas.finishRecording(); + nSetDisplayListData(mNativeRenderNode, renderNodeData); canvas.recycle(); mValid = true; } @@ -258,19 +250,10 @@ public class RenderNode { public void destroyDisplayListData() { if (!mValid) return; - setDisplayListData(0); - mRenderer = null; + nSetDisplayListData(mNativeRenderNode, 0); mValid = false; } - private void setDisplayListData(long newData) { - if (mRenderer != null) { - mRenderer.setDisplayListData(mNativeDisplayList, newData); - } else { - throw new IllegalStateException("Trying to set data without a renderer! data=" + newData); - } - } - /** * Returns whether the RenderNode's display list content is currently usable. * If this returns false, the display list should be re-recorded prior to replaying it. @@ -283,7 +266,7 @@ public class RenderNode { if (!mValid) { throw new IllegalStateException("The display list is not valid."); } - return mNativeDisplayList; + return mNativeRenderNode; } /////////////////////////////////////////////////////////////////////////// @@ -291,15 +274,15 @@ public class RenderNode { /////////////////////////////////////////////////////////////////////////// public boolean hasIdentityMatrix() { - return nHasIdentityMatrix(mNativeDisplayList); + return nHasIdentityMatrix(mNativeRenderNode); } public void getMatrix(@NonNull Matrix outMatrix) { - nGetTransformMatrix(mNativeDisplayList, outMatrix.native_instance); + nGetTransformMatrix(mNativeRenderNode, outMatrix.native_instance); } public void getInverseMatrix(@NonNull Matrix outMatrix) { - nGetInverseTransformMatrix(mNativeDisplayList, outMatrix.native_instance); + nGetInverseTransformMatrix(mNativeRenderNode, outMatrix.native_instance); } /////////////////////////////////////////////////////////////////////////// @@ -316,7 +299,7 @@ public class RenderNode { * @hide */ public void setCaching(boolean caching) { - nSetCaching(mNativeDisplayList, caching); + nSetCaching(mNativeRenderNode, caching); } /** @@ -326,7 +309,7 @@ public class RenderNode { * @param clipToBounds true if the display list should clip to its bounds */ public void setClipToBounds(boolean clipToBounds) { - nSetClipToBounds(mNativeDisplayList, clipToBounds); + nSetClipToBounds(mNativeRenderNode, clipToBounds); } /** @@ -337,7 +320,7 @@ public class RenderNode { * containing volume. */ public void setProjectBackwards(boolean shouldProject) { - nSetProjectBackwards(mNativeDisplayList, shouldProject); + nSetProjectBackwards(mNativeRenderNode, shouldProject); } /** @@ -346,7 +329,7 @@ public class RenderNode { * ProjectBackwards=true directly on top of it. Default value is false. */ public void setProjectionReceiver(boolean shouldRecieve) { - nSetProjectionReceiver(mNativeDisplayList, shouldRecieve); + nSetProjectionReceiver(mNativeRenderNode, shouldRecieve); } /** @@ -357,14 +340,14 @@ public class RenderNode { */ public void setOutline(Outline outline) { if (outline == null) { - nSetOutlineEmpty(mNativeDisplayList); + nSetOutlineEmpty(mNativeRenderNode); } else if (!outline.isValid()) { throw new IllegalArgumentException("Outline must be valid"); } else if (outline.mRect != null) { - nSetOutlineRoundRect(mNativeDisplayList, outline.mRect.left, outline.mRect.top, + nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top, outline.mRect.right, outline.mRect.bottom, outline.mRadius); } else if (outline.mPath != null) { - nSetOutlineConvexPath(mNativeDisplayList, outline.mPath.mNativePath); + nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath); } } @@ -374,7 +357,7 @@ public class RenderNode { * @param clipToOutline true if clipping to the outline. */ public void setClipToOutline(boolean clipToOutline) { - nSetClipToOutline(mNativeDisplayList, clipToOutline); + nSetClipToOutline(mNativeRenderNode, clipToOutline); } /** @@ -382,7 +365,7 @@ public class RenderNode { */ public void setRevealClip(boolean shouldClip, boolean inverseClip, float x, float y, float radius) { - nSetRevealClip(mNativeDisplayList, shouldClip, inverseClip, x, y, radius); + nSetRevealClip(mNativeRenderNode, shouldClip, inverseClip, x, y, radius); } /** @@ -392,7 +375,7 @@ public class RenderNode { * @param matrix A transform matrix to apply to this display list */ public void setStaticMatrix(Matrix matrix) { - nSetStaticMatrix(mNativeDisplayList, matrix.native_instance); + nSetStaticMatrix(mNativeRenderNode, matrix.native_instance); } /** @@ -406,7 +389,7 @@ public class RenderNode { * @hide */ public void setAnimationMatrix(Matrix matrix) { - nSetAnimationMatrix(mNativeDisplayList, + nSetAnimationMatrix(mNativeRenderNode, (matrix != null) ? matrix.native_instance : 0); } @@ -419,7 +402,7 @@ public class RenderNode { * @see #getAlpha() */ public void setAlpha(float alpha) { - nSetAlpha(mNativeDisplayList, alpha); + nSetAlpha(mNativeRenderNode, alpha); } /** @@ -430,7 +413,7 @@ public class RenderNode { * @see #setAlpha(float) */ public float getAlpha() { - return nGetAlpha(mNativeDisplayList); + return nGetAlpha(mNativeRenderNode); } /** @@ -445,7 +428,7 @@ public class RenderNode { * @see #hasOverlappingRendering() */ public void setHasOverlappingRendering(boolean hasOverlappingRendering) { - nSetHasOverlappingRendering(mNativeDisplayList, hasOverlappingRendering); + nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering); } /** @@ -457,7 +440,7 @@ public class RenderNode { */ public boolean hasOverlappingRendering() { //noinspection SimplifiableIfStatement - return nHasOverlappingRendering(mNativeDisplayList); + return nHasOverlappingRendering(mNativeRenderNode); } /** @@ -469,7 +452,7 @@ public class RenderNode { * @see #getTranslationX() */ public void setTranslationX(float translationX) { - nSetTranslationX(mNativeDisplayList, translationX); + nSetTranslationX(mNativeRenderNode, translationX); } /** @@ -478,7 +461,7 @@ public class RenderNode { * @see #setTranslationX(float) */ public float getTranslationX() { - return nGetTranslationX(mNativeDisplayList); + return nGetTranslationX(mNativeRenderNode); } /** @@ -490,7 +473,7 @@ public class RenderNode { * @see #getTranslationY() */ public void setTranslationY(float translationY) { - nSetTranslationY(mNativeDisplayList, translationY); + nSetTranslationY(mNativeRenderNode, translationY); } /** @@ -499,7 +482,7 @@ public class RenderNode { * @see #setTranslationY(float) */ public float getTranslationY() { - return nGetTranslationY(mNativeDisplayList); + return nGetTranslationY(mNativeRenderNode); } /** @@ -509,7 +492,7 @@ public class RenderNode { * @see #getTranslationZ() */ public void setTranslationZ(float translationZ) { - nSetTranslationZ(mNativeDisplayList, translationZ); + nSetTranslationZ(mNativeRenderNode, translationZ); } /** @@ -518,7 +501,7 @@ public class RenderNode { * @see #setTranslationZ(float) */ public float getTranslationZ() { - return nGetTranslationZ(mNativeDisplayList); + return nGetTranslationZ(mNativeRenderNode); } /** @@ -530,7 +513,7 @@ public class RenderNode { * @see #getRotation() */ public void setRotation(float rotation) { - nSetRotation(mNativeDisplayList, rotation); + nSetRotation(mNativeRenderNode, rotation); } /** @@ -539,7 +522,7 @@ public class RenderNode { * @see #setRotation(float) */ public float getRotation() { - return nGetRotation(mNativeDisplayList); + return nGetRotation(mNativeRenderNode); } /** @@ -551,7 +534,7 @@ public class RenderNode { * @see #getRotationX() */ public void setRotationX(float rotationX) { - nSetRotationX(mNativeDisplayList, rotationX); + nSetRotationX(mNativeRenderNode, rotationX); } /** @@ -560,7 +543,7 @@ public class RenderNode { * @see #setRotationX(float) */ public float getRotationX() { - return nGetRotationX(mNativeDisplayList); + return nGetRotationX(mNativeRenderNode); } /** @@ -572,7 +555,7 @@ public class RenderNode { * @see #getRotationY() */ public void setRotationY(float rotationY) { - nSetRotationY(mNativeDisplayList, rotationY); + nSetRotationY(mNativeRenderNode, rotationY); } /** @@ -581,7 +564,7 @@ public class RenderNode { * @see #setRotationY(float) */ public float getRotationY() { - return nGetRotationY(mNativeDisplayList); + return nGetRotationY(mNativeRenderNode); } /** @@ -593,7 +576,7 @@ public class RenderNode { * @see #getScaleX() */ public void setScaleX(float scaleX) { - nSetScaleX(mNativeDisplayList, scaleX); + nSetScaleX(mNativeRenderNode, scaleX); } /** @@ -602,7 +585,7 @@ public class RenderNode { * @see #setScaleX(float) */ public float getScaleX() { - return nGetScaleX(mNativeDisplayList); + return nGetScaleX(mNativeRenderNode); } /** @@ -614,7 +597,7 @@ public class RenderNode { * @see #getScaleY() */ public void setScaleY(float scaleY) { - nSetScaleY(mNativeDisplayList, scaleY); + nSetScaleY(mNativeRenderNode, scaleY); } /** @@ -623,7 +606,7 @@ public class RenderNode { * @see #setScaleY(float) */ public float getScaleY() { - return nGetScaleY(mNativeDisplayList); + return nGetScaleY(mNativeRenderNode); } /** @@ -635,7 +618,7 @@ public class RenderNode { * @see #getPivotX() */ public void setPivotX(float pivotX) { - nSetPivotX(mNativeDisplayList, pivotX); + nSetPivotX(mNativeRenderNode, pivotX); } /** @@ -644,7 +627,7 @@ public class RenderNode { * @see #setPivotX(float) */ public float getPivotX() { - return nGetPivotX(mNativeDisplayList); + return nGetPivotX(mNativeRenderNode); } /** @@ -656,7 +639,7 @@ public class RenderNode { * @see #getPivotY() */ public void setPivotY(float pivotY) { - nSetPivotY(mNativeDisplayList, pivotY); + nSetPivotY(mNativeRenderNode, pivotY); } /** @@ -665,11 +648,11 @@ public class RenderNode { * @see #setPivotY(float) */ public float getPivotY() { - return nGetPivotY(mNativeDisplayList); + return nGetPivotY(mNativeRenderNode); } public boolean isPivotExplicitlySet() { - return nIsPivotExplicitlySet(mNativeDisplayList); + return nIsPivotExplicitlySet(mNativeRenderNode); } /** @@ -683,7 +666,7 @@ public class RenderNode { * @see #getCameraDistance() */ public void setCameraDistance(float distance) { - nSetCameraDistance(mNativeDisplayList, distance); + nSetCameraDistance(mNativeRenderNode, distance); } /** @@ -692,7 +675,7 @@ public class RenderNode { * @see #setCameraDistance(float) */ public float getCameraDistance() { - return nGetCameraDistance(mNativeDisplayList); + return nGetCameraDistance(mNativeRenderNode); } /** @@ -704,7 +687,7 @@ public class RenderNode { * @see #getLeft() */ public void setLeft(int left) { - nSetLeft(mNativeDisplayList, left); + nSetLeft(mNativeRenderNode, left); } /** @@ -713,7 +696,7 @@ public class RenderNode { * @see #setLeft(int) */ public float getLeft() { - return nGetLeft(mNativeDisplayList); + return nGetLeft(mNativeRenderNode); } /** @@ -725,7 +708,7 @@ public class RenderNode { * @see #getTop() */ public void setTop(int top) { - nSetTop(mNativeDisplayList, top); + nSetTop(mNativeRenderNode, top); } /** @@ -734,7 +717,7 @@ public class RenderNode { * @see #setTop(int) */ public float getTop() { - return nGetTop(mNativeDisplayList); + return nGetTop(mNativeRenderNode); } /** @@ -746,7 +729,7 @@ public class RenderNode { * @see #getRight() */ public void setRight(int right) { - nSetRight(mNativeDisplayList, right); + nSetRight(mNativeRenderNode, right); } /** @@ -755,7 +738,7 @@ public class RenderNode { * @see #setRight(int) */ public float getRight() { - return nGetRight(mNativeDisplayList); + return nGetRight(mNativeRenderNode); } /** @@ -767,7 +750,7 @@ public class RenderNode { * @see #getBottom() */ public void setBottom(int bottom) { - nSetBottom(mNativeDisplayList, bottom); + nSetBottom(mNativeRenderNode, bottom); } /** @@ -776,7 +759,7 @@ public class RenderNode { * @see #setBottom(int) */ public float getBottom() { - return nGetBottom(mNativeDisplayList); + return nGetBottom(mNativeRenderNode); } /** @@ -793,7 +776,7 @@ public class RenderNode { * @see View#setBottom(int) */ public void setLeftTopRightBottom(int left, int top, int right, int bottom) { - nSetLeftTopRightBottom(mNativeDisplayList, left, top, right, bottom); + nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom); } /** @@ -805,7 +788,7 @@ public class RenderNode { * @see View#offsetLeftAndRight(int) */ public void offsetLeftAndRight(float offset) { - nOffsetLeftAndRight(mNativeDisplayList, offset); + nOffsetLeftAndRight(mNativeRenderNode, offset); } /** @@ -817,7 +800,7 @@ public class RenderNode { * @see View#offsetTopAndBottom(int) */ public void offsetTopAndBottom(float offset) { - nOffsetTopAndBottom(mNativeDisplayList, offset); + nOffsetTopAndBottom(mNativeRenderNode, offset); } /** @@ -827,80 +810,80 @@ public class RenderNode { * @hide */ public void output() { - nOutput(mNativeDisplayList); + nOutput(mNativeRenderNode); } /////////////////////////////////////////////////////////////////////////// // Native methods /////////////////////////////////////////////////////////////////////////// - private static native long nCreate(); - private static native void nDestroyDisplayList(long displayList); - private static native void nSetDisplayListName(long displayList, String name); + private static native long nCreate(String name); + private static native void nDestroyRenderNode(long renderNode); + private static native void nSetDisplayListData(long renderNode, long newData); // Matrix - private static native void nGetTransformMatrix(long displayList, long nativeMatrix); - private static native void nGetInverseTransformMatrix(long displayList, long nativeMatrix); - private static native boolean nHasIdentityMatrix(long displayList); + private static native void nGetTransformMatrix(long renderNode, long nativeMatrix); + private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix); + private static native boolean nHasIdentityMatrix(long renderNode); // Properties - private static native void nOffsetTopAndBottom(long displayList, float offset); - private static native void nOffsetLeftAndRight(long displayList, float offset); - private static native void nSetLeftTopRightBottom(long displayList, int left, int top, + private static native void nOffsetTopAndBottom(long renderNode, float offset); + private static native void nOffsetLeftAndRight(long renderNode, float offset); + private static native void nSetLeftTopRightBottom(long renderNode, int left, int top, int right, int bottom); - private static native void nSetBottom(long displayList, int bottom); - private static native void nSetRight(long displayList, int right); - private static native void nSetTop(long displayList, int top); - private static native void nSetLeft(long displayList, int left); - private static native void nSetCameraDistance(long displayList, float distance); - private static native void nSetPivotY(long displayList, float pivotY); - private static native void nSetPivotX(long displayList, float pivotX); - private static native void nSetCaching(long displayList, boolean caching); - private static native void nSetClipToBounds(long displayList, boolean clipToBounds); - private static native void nSetProjectBackwards(long displayList, boolean shouldProject); - private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve); - private static native void nSetOutlineRoundRect(long displayList, int left, int top, + private static native void nSetBottom(long renderNode, int bottom); + private static native void nSetRight(long renderNode, int right); + private static native void nSetTop(long renderNode, int top); + private static native void nSetLeft(long renderNode, int left); + private static native void nSetCameraDistance(long renderNode, float distance); + private static native void nSetPivotY(long renderNode, float pivotY); + private static native void nSetPivotX(long renderNode, float pivotX); + private static native void nSetCaching(long renderNode, boolean caching); + private static native void nSetClipToBounds(long renderNode, boolean clipToBounds); + private static native void nSetProjectBackwards(long renderNode, boolean shouldProject); + private static native void nSetProjectionReceiver(long renderNode, boolean shouldRecieve); + private static native void nSetOutlineRoundRect(long renderNode, int left, int top, int right, int bottom, float radius); - private static native void nSetOutlineConvexPath(long displayList, long nativePath); - private static native void nSetOutlineEmpty(long displayList); - private static native void nSetClipToOutline(long displayList, boolean clipToOutline); - private static native void nSetRevealClip(long displayList, + private static native void nSetOutlineConvexPath(long renderNode, long nativePath); + private static native void nSetOutlineEmpty(long renderNode); + private static native void nSetClipToOutline(long renderNode, boolean clipToOutline); + private static native void nSetRevealClip(long renderNode, boolean shouldClip, boolean inverseClip, float x, float y, float radius); - private static native void nSetAlpha(long displayList, float alpha); - private static native void nSetHasOverlappingRendering(long displayList, + private static native void nSetAlpha(long renderNode, float alpha); + private static native void nSetHasOverlappingRendering(long renderNode, boolean hasOverlappingRendering); - private static native void nSetTranslationX(long displayList, float translationX); - private static native void nSetTranslationY(long displayList, float translationY); - private static native void nSetTranslationZ(long displayList, float translationZ); - private static native void nSetRotation(long displayList, float rotation); - private static native void nSetRotationX(long displayList, float rotationX); - private static native void nSetRotationY(long displayList, float rotationY); - private static native void nSetScaleX(long displayList, float scaleX); - private static native void nSetScaleY(long displayList, float scaleY); - private static native void nSetStaticMatrix(long displayList, long nativeMatrix); - private static native void nSetAnimationMatrix(long displayList, long animationMatrix); - - private static native boolean nHasOverlappingRendering(long displayList); - private static native float nGetAlpha(long displayList); - private static native float nGetLeft(long displayList); - private static native float nGetTop(long displayList); - private static native float nGetRight(long displayList); - private static native float nGetBottom(long displayList); - private static native float nGetCameraDistance(long displayList); - private static native float nGetScaleX(long displayList); - private static native float nGetScaleY(long displayList); - private static native float nGetTranslationX(long displayList); - private static native float nGetTranslationY(long displayList); - private static native float nGetTranslationZ(long displayList); - private static native float nGetRotation(long displayList); - private static native float nGetRotationX(long displayList); - private static native float nGetRotationY(long displayList); - private static native boolean nIsPivotExplicitlySet(long displayList); - private static native float nGetPivotX(long displayList); - private static native float nGetPivotY(long displayList); - private static native void nOutput(long displayList); + private static native void nSetTranslationX(long renderNode, float translationX); + private static native void nSetTranslationY(long renderNode, float translationY); + private static native void nSetTranslationZ(long renderNode, float translationZ); + private static native void nSetRotation(long renderNode, float rotation); + private static native void nSetRotationX(long renderNode, float rotationX); + private static native void nSetRotationY(long renderNode, float rotationY); + private static native void nSetScaleX(long renderNode, float scaleX); + private static native void nSetScaleY(long renderNode, float scaleY); + private static native void nSetStaticMatrix(long renderNode, long nativeMatrix); + private static native void nSetAnimationMatrix(long renderNode, long animationMatrix); + + private static native boolean nHasOverlappingRendering(long renderNode); + private static native float nGetAlpha(long renderNode); + private static native float nGetLeft(long renderNode); + private static native float nGetTop(long renderNode); + private static native float nGetRight(long renderNode); + private static native float nGetBottom(long renderNode); + private static native float nGetCameraDistance(long renderNode); + private static native float nGetScaleX(long renderNode); + private static native float nGetScaleY(long renderNode); + private static native float nGetTranslationX(long renderNode); + private static native float nGetTranslationY(long renderNode); + private static native float nGetTranslationZ(long renderNode); + private static native float nGetRotation(long renderNode); + private static native float nGetRotationX(long renderNode); + private static native float nGetRotationY(long renderNode); + private static native boolean nIsPivotExplicitlySet(long renderNode); + private static native float nGetPivotX(long renderNode); + private static native float nGetPivotY(long renderNode); + private static native void nOutput(long renderNode); /////////////////////////////////////////////////////////////////////////// // Finalization @@ -909,7 +892,7 @@ public class RenderNode { @Override protected void finalize() throws Throwable { try { - nDestroyDisplayList(mNativeDisplayList); + nDestroyRenderNode(mNativeRenderNode); } finally { super.finalize(); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 5a8d2c8..2d55a01 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -20,7 +20,6 @@ import dalvik.system.CloseGuard; import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.Region; -import android.view.Surface; import android.os.IBinder; import android.util.Log; import android.view.Surface.OutOfResourcesException; @@ -59,6 +58,11 @@ public class SurfaceControl { private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b); private static native void nativeSetLayerStack(long nativeObject, int layerStack); + private static native boolean nativeClearContentFrameStats(long nativeObject); + private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats); + private static native boolean nativeClearAnimationFrameStats(); + private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats); + private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId); private static native IBinder nativeCreateDisplay(String name, boolean secure); private static native void nativeDestroyDisplay(IBinder displayToken); @@ -357,6 +361,24 @@ public class SurfaceControl { nativeSetTransparentRegionHint(mNativeObject, region); } + public boolean clearContentFrameStats() { + checkNotReleased(); + return nativeClearContentFrameStats(mNativeObject); + } + + public boolean getContentFrameStats(WindowContentFrameStats outStats) { + checkNotReleased(); + return nativeGetContentFrameStats(mNativeObject, outStats); + } + + public static boolean clearAnimationFrameStats() { + return nativeClearAnimationFrameStats(); + } + + public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) { + return nativeGetAnimationFrameStats(outStats); + } + /** * Sets an alpha value for the entire Surface. This value is combined with the * per-pixel alpha. It may be used with opaque Surfaces. @@ -542,7 +564,6 @@ public class SurfaceControl { return nativeGetBuiltInDisplay(builtInDisplayId); } - /** * Copy the current screen contents into the provided {@link Surface} * @@ -592,7 +613,6 @@ public class SurfaceControl { screenshot(display, consumer, 0, 0, 0, 0, true, false); } - /** * Copy the current screen contents into a bitmap and return it. * @@ -626,8 +646,8 @@ public class SurfaceControl { } /** - * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all - * Surfaces in the screenshot. + * Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but + * includes all Surfaces in the screenshot. * * @param width The desired width of the returned bitmap; the raw * screen will be scaled down to this size. diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index a747ab6..789b761 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -54,28 +54,46 @@ public class ThreadedRenderer extends HardwareRenderer { private int mWidth, mHeight; private long mNativeProxy; + private boolean mInitialized = false; ThreadedRenderer(boolean translucent) { mNativeProxy = nCreateProxy(translucent); - setEnabled(mNativeProxy != 0); } @Override void destroy(boolean full) { + mInitialized = false; + updateEnabledState(null); nDestroyCanvas(mNativeProxy); } + private void updateEnabledState(Surface surface) { + if (surface == null || !surface.isValid()) { + setEnabled(false); + } else { + setEnabled(mInitialized); + } + } + @Override boolean initialize(Surface surface) throws OutOfResourcesException { + mInitialized = true; + updateEnabledState(surface); return nInitialize(mNativeProxy, surface); } @Override void updateSurface(Surface surface) throws OutOfResourcesException { + updateEnabledState(surface); nUpdateSurface(mNativeProxy, surface); } @Override + void pauseSurface(Surface surface) { + nPauseSurface(mNativeProxy, surface); + } + + @Override void destroyHardwareResources(View view) { destroyResources(view); // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); @@ -148,11 +166,6 @@ public class ThreadedRenderer extends HardwareRenderer { } @Override - void setDisplayListData(long displayList, long newData) { - nSetDisplayListData(mNativeProxy, displayList, newData); - } - - @Override void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) { attachInfo.mIgnoreDirtyState = true; attachInfo.mDrawingTime = SystemClock.uptimeMillis(); @@ -177,12 +190,12 @@ public class ThreadedRenderer extends HardwareRenderer { @Override void detachFunctor(long functor) { - nDetachFunctor(mNativeProxy, functor); + // no-op, we never attach functors to need to detach them } @Override void attachFunctor(AttachInfo attachInfo, long functor) { - nAttachFunctor(mNativeProxy, functor); + invokeFunctor(functor, true); } @Override @@ -267,6 +280,7 @@ public class ThreadedRenderer extends HardwareRenderer { private static native boolean nInitialize(long nativeProxy, Surface window); private static native void nUpdateSurface(long nativeProxy, Surface window); + private static native void nPauseSurface(long nativeProxy, Surface window); private static native void nSetup(long nativeProxy, int width, int height); private static native void nSetDisplayListData(long nativeProxy, long displayList, long newData); @@ -275,8 +289,6 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nRunWithGlContext(long nativeProxy, Runnable runnable); private static native void nDestroyCanvas(long nativeProxy); - private static native void nAttachFunctor(long nativeProxy, long functor); - private static native void nDetachFunctor(long nativeProxy, long functor); private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion); private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6c414f6..9761f1a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13549,11 +13549,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return A new or reused DisplayList object. */ private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) { - final HardwareRenderer renderer = getHardwareRenderer(); if (renderNode == null) { throw new IllegalArgumentException("RenderNode must not be null"); } - if (renderer == null || !canHaveDisplayList()) { + if (!canHaveDisplayList()) { // can't populate RenderNode, don't try return; } @@ -13627,21 +13626,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } finally { - renderNode.end(renderer, canvas); + renderNode.end(canvas); renderNode.setCaching(caching); if (isLayer) { renderNode.setLeftTopRightBottom(0, 0, width, height); } else { setDisplayListProperties(renderNode); } - - if (renderer != getHardwareRenderer()) { - Log.w(VIEW_LOG_TAG, "View was detached during a draw() call!"); - // TODO: Should this be elevated to a crash? - // For now have it behaves the same as it previously did, it - // will result in the DisplayListData being destroyed later - // than it could be but oh well... - } } } else if (!isLayer) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; @@ -14913,7 +14904,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final int height = bounds.height(); final HardwareCanvas canvas = displayList.start(width, height); drawable.draw(canvas); - displayList.end(getHardwareRenderer(), canvas); + displayList.end(canvas); // Set up drawable properties that are view-independent. displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 94f0683..65ac50d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1421,6 +1421,12 @@ public final class ViewRootImpl implements ViewParent, host.getMeasuredHeight() + ", params=" + params); } + if (mAttachInfo.mHardwareRenderer != null) { + // relayoutWindow may decide to destroy mSurface. As that decision + // happens in WindowManager service, we need to be defensive here + // and stop using the surface in case it gets destroyed. + mAttachInfo.mHardwareRenderer.pauseSurface(mSurface); + } final int surfaceGenerationId = mSurface.getGenerationId(); relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); if (!mDrawDuringWindowsAnimating && @@ -1499,7 +1505,7 @@ public final class ViewRootImpl implements ViewParent, com.android.internal.R.integer.config_mediumAnimTime); layerCanvas.restoreToCount(restoreCount); - layerRenderNode.end(mAttachInfo.mHardwareRenderer, layerCanvas); + layerRenderNode.end(layerCanvas); layerRenderNode.setCaching(true); layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight); mTempRect.set(0, 0, mWidth, mHeight); diff --git a/core/java/android/view/WindowAnimationFrameStats.aidl b/core/java/android/view/WindowAnimationFrameStats.aidl new file mode 100644 index 0000000..77f544b --- /dev/null +++ b/core/java/android/view/WindowAnimationFrameStats.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +parcelable WindowAnimationFrameStats; diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java new file mode 100644 index 0000000..c60b96c --- /dev/null +++ b/core/java/android/view/WindowAnimationFrameStats.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class contains window animation frame statistics. For example, a window + * animation is usually performed when the application is transitioning from one + * activity to another. The frame statistics are a snapshot for the time interval + * from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}. + * <p> + * The key idea is that in order to provide a smooth user experience the system should + * run window animations at a specific time interval obtained by calling {@link + * #getRefreshPeriodNano()}. If the system does not render a frame every refresh + * period the user will see irregular window transitions. The time when the frame was + * actually presented on the display by calling {@link #getFramePresentedTimeNano(int)}. + */ +public final class WindowAnimationFrameStats extends FrameStats implements Parcelable { + /** + * @hide + */ + public WindowAnimationFrameStats() { + /* do nothing */ + } + + /** + * Initializes this isntance. + * + * @param refreshPeriodNano The display refresh period. + * @param framesPresentedTimeNano The presented frame times. + * + * @hide + */ + public void init(long refreshPeriodNano, long[] framesPresentedTimeNano) { + mRefreshPeriodNano = refreshPeriodNano; + mFramesPresentedTimeNano = framesPresentedTimeNano; + } + + private WindowAnimationFrameStats(Parcel parcel) { + mRefreshPeriodNano = parcel.readLong(); + mFramesPresentedTimeNano = parcel.createLongArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeLong(mRefreshPeriodNano); + parcel.writeLongArray(mFramesPresentedTimeNano); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("WindowAnimationFrameStats["); + builder.append("frameCount:" + getFrameCount()); + builder.append(", fromTimeNano:" + getStartTimeNano()); + builder.append(", toTimeNano:" + getEndTimeNano()); + builder.append(']'); + return builder.toString(); + } + + public static final Creator<WindowAnimationFrameStats> CREATOR = + new Creator<WindowAnimationFrameStats>() { + @Override + public WindowAnimationFrameStats createFromParcel(Parcel parcel) { + return new WindowAnimationFrameStats(parcel); + } + + @Override + public WindowAnimationFrameStats[] newArray(int size) { + return new WindowAnimationFrameStats[size]; + } + }; +} diff --git a/core/java/android/view/WindowContentFrameStats.aidl b/core/java/android/view/WindowContentFrameStats.aidl new file mode 100644 index 0000000..aa9c2d6 --- /dev/null +++ b/core/java/android/view/WindowContentFrameStats.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +parcelable WindowContentFrameStats; diff --git a/core/java/android/view/WindowContentFrameStats.java b/core/java/android/view/WindowContentFrameStats.java new file mode 100644 index 0000000..c6da2fb --- /dev/null +++ b/core/java/android/view/WindowContentFrameStats.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class contains window content frame statistics. For example, a window content + * is rendred in frames when a view is scrolled. The frame statistics are a snapshot + * for the time interval from {@link #getStartTimeNano()} to {@link #getEndTimeNano()}. + * <p> + * The key idea is that in order to provide a smooth user experience an application + * has to draw a frame at a specific time interval obtained by calling {@link + * #getRefreshPeriodNano()}. If the application does not render a frame every refresh + * period the user will see irregular UI transitions. + * </p> + * <p> + * An application posts a frame for presentation by synchronously rendering its contents + * in a buffer which is then posted or posting a buffer to which the application is + * asychronously rendering the content via GL. After the frame is posted and rendered + * (potentially asynchronosly) it is presented to the user. The time a frame was posted + * can be obtained via {@link #getFramePostedTimeNano(int)}, the time a frame content + * was rendered and ready for dsiplay (GL case) via {@link #getFrameReadyTimeNano(int)}, + * and the time a frame was presented on the screen via {@link #getFramePresentedTimeNano(int)}. + * </p> + */ +public final class WindowContentFrameStats extends FrameStats implements Parcelable { + private long[] mFramesPostedTimeNano; + private long[] mFramesReadyTimeNano; + + /** + * @hide + */ + public WindowContentFrameStats() { + /* do nothing */ + } + + /** + * Initializes this isntance. + * + * @param refreshPeriodNano The display refresh period. + * @param framesPostedTimeNano The times in milliseconds for when the frame contents were posted. + * @param framesPresentedTimeNano The times in milliseconds for when the frame contents were presented. + * @param framesReadyTimeNano The times in milliseconds for when the frame contents were ready to be presented. + * + * @hide + */ + public void init(long refreshPeriodNano, long[] framesPostedTimeNano, + long[] framesPresentedTimeNano, long[] framesReadyTimeNano) { + mRefreshPeriodNano = refreshPeriodNano; + mFramesPostedTimeNano = framesPostedTimeNano; + mFramesPresentedTimeNano = framesPresentedTimeNano; + mFramesReadyTimeNano = framesReadyTimeNano; + } + + private WindowContentFrameStats(Parcel parcel) { + mRefreshPeriodNano = parcel.readLong(); + mFramesPostedTimeNano = parcel.createLongArray(); + mFramesPresentedTimeNano = parcel.createLongArray(); + mFramesReadyTimeNano = parcel.createLongArray(); + } + + /** + * Get the time a frame at a given index was posted by the producer (e.g. the application). + * It is either explicitly set or defaulted to the time when the render buffer was posted. + * <p> + * <strong>Note:</strong> A frame can be posted and still it contents being rendered + * asynchronously in GL. To get the time the frame content was completely rendered and + * ready to display call {@link #getFrameReadyTimeNano(int)}. + * </p> + * + * @param index The frame index. + * @return The posted time in nanoseconds. + */ + public long getFramePostedTimeNano(int index) { + if (mFramesPostedTimeNano == null) { + throw new IndexOutOfBoundsException(); + } + return mFramesPostedTimeNano[index]; + } + + /** + * Get the time a frame at a given index was ready for presentation. + * <p> + * <strong>Note:</strong> A frame can be posted and still it contents being rendered + * asynchronously in GL. In such a case this is the time when the frame contents were + * completely rendered. + * </p> + * + * @param index The frame index. + * @return The ready time in nanoseconds or {@link #UNDEFINED_TIME_NANO} + * if the frame is not ready yet. + */ + public long getFrameReadyTimeNano(int index) { + if (mFramesReadyTimeNano == null) { + throw new IndexOutOfBoundsException(); + } + return mFramesReadyTimeNano[index]; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeLong(mRefreshPeriodNano); + parcel.writeLongArray(mFramesPostedTimeNano); + parcel.writeLongArray(mFramesPresentedTimeNano); + parcel.writeLongArray(mFramesReadyTimeNano); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("WindowContentFrameStats["); + builder.append("frameCount:" + getFrameCount()); + builder.append(", fromTimeNano:" + getStartTimeNano()); + builder.append(", toTimeNano:" + getEndTimeNano()); + builder.append(']'); + return builder.toString(); + } + + public static final Parcelable.Creator<WindowContentFrameStats> CREATOR = + new Creator<WindowContentFrameStats>() { + @Override + public WindowContentFrameStats createFromParcel(Parcel parcel) { + return new WindowContentFrameStats(parcel); + } + + @Override + public WindowContentFrameStats[] newArray(int size) { + return new WindowContentFrameStats[size]; + } + }; +} diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index fe3e5c6..b6570cc 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -57,4 +57,6 @@ interface IAccessibilityManager { void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service, boolean touchExplorationEnabled); + + IBinder getWindowToken(int windowId); } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 14e7951..b0a4e24 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1338,7 +1338,6 @@ public class Editor { layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical, firstLine, lastLine); - final HardwareRenderer renderer = mTextView.getHardwareRenderer(); if (layout instanceof DynamicLayout) { if (mTextDisplayLists == null) { @@ -1402,7 +1401,7 @@ public class Editor { // No need to untranslate, previous context is popped after // drawDisplayList } finally { - blockDisplayList.end(renderer, hardwareCanvas); + blockDisplayList.end(hardwareCanvas); // Same as drawDisplayList below, handled by our TextView's parent blockDisplayList.setClipToBounds(false); } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 6d65782..ba419f9 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -16,7 +16,7 @@ package com.android.internal.content; -import android.os.Build; +import android.content.pm.PackageManager; import android.util.Slog; import java.io.File; @@ -31,38 +31,76 @@ public class NativeLibraryHelper { private static final boolean DEBUG_NATIVE = false; - private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2); + /** + * A handle to an opened APK. Used as input to the various NativeLibraryHelper + * methods. Allows us to scan and parse the APK exactly once instead of doing + * it multiple times. + * + * @hide + */ + public static class ApkHandle { + final String apkPath; + final long apkHandle; + + public ApkHandle(String path) { + apkPath = path; + apkHandle = nativeOpenApk(apkPath); + } + + public ApkHandle(File apkFile) { + apkPath = apkFile.getPath(); + apkHandle = nativeOpenApk(apkPath); + } + + public void close() { + nativeClose(apkHandle); + } + } + + + private static native long nativeOpenApk(String path); + private static native void nativeClose(long handle); + + private static native long nativeSumNativeBinaries(long handle, String cpuAbi); /** - * Sums the size of native binaries in an APK. + * Sums the size of native binaries in an APK for a given ABI. * - * @param apkFile APK file to scan for native libraries * @return size of all native binary files in bytes */ - public static long sumNativeBinariesLI(File apkFile) { - final String cpuAbi = Build.CPU_ABI; - final String cpuAbi2 = Build.CPU_ABI2; - return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2); + public static long sumNativeBinariesLI(ApkHandle handle, String abi) { + return nativeSumNativeBinaries(handle.apkHandle, abi); } - private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath, - String cpuAbi, String cpuAbi2); + private native static int nativeCopyNativeBinaries(long handle, + String sharedLibraryPath, String abiToCopy); /** * Copies native binaries to a shared library directory. * - * @param apkFile APK file to scan for native libraries + * @param handle APK file to scan for native libraries * @param sharedLibraryDir directory for libraries to be copied to * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another * error code from that class if not */ - public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) { - final String cpuAbi = Build.CPU_ABI; - final String cpuAbi2 = Build.CPU_ABI2; - return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi, - cpuAbi2); + public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir, + String abi) { + return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi); } + /** + * Checks if a given APK contains native code for any of the provided + * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching + * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the + * APK doesn't contain any native code, and + * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match. + */ + public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) { + return nativeFindSupportedAbi(handle.apkHandle, supportedAbis); + } + + private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis); + // Convenience method to call removeNativeBinariesFromDirLI(File) public static boolean removeNativeBinariesLI(String nativeLibraryPath) { return removeNativeBinariesFromDirLI(new File(nativeLibraryPath)); diff --git a/core/java/com/android/internal/notification/PeopleNotificationScorer.java b/core/java/com/android/internal/notification/PeopleNotificationScorer.java new file mode 100644 index 0000000..efb5f63 --- /dev/null +++ b/core/java/com/android/internal/notification/PeopleNotificationScorer.java @@ -0,0 +1,227 @@ +/* +* Copyright (C) 2014 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package com.android.internal.notification; + +import android.app.Notification; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract; +import android.provider.ContactsContract.Contacts; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.LruCache; +import android.util.Slog; + +/** + * This {@link NotificationScorer} attempts to validate people references. + * Also elevates the priority of real people. + */ +public class PeopleNotificationScorer implements NotificationScorer { + private static final String TAG = "PeopleNotificationScorer"; + private static final boolean DBG = false; + + private static final boolean ENABLE_PEOPLE_SCORER = true; + private static final String SETTING_ENABLE_PEOPLE_SCORER = "people_scorer_enabled"; + private static final String[] LOOKUP_PROJECTION = { Contacts._ID }; + private static final int MAX_PEOPLE = 10; + private static final int PEOPLE_CACHE_SIZE = 200; + // see NotificationManagerService + private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; + + protected boolean mEnabled; + private Context mContext; + + // maps raw person handle to resolved person object + private LruCache<String, LookupResult> mPeopleCache; + + private float findMaxContactScore(Bundle extras) { + if (extras == null) { + return 0f; + } + + final String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE); + if (people == null || people.length == 0) { + return 0f; + } + + float rank = 0f; + for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) { + final String handle = people[personIdx]; + if (TextUtils.isEmpty(handle)) continue; + + LookupResult lookupResult = mPeopleCache.get(handle); + if (lookupResult == null || lookupResult.isExpired()) { + final Uri uri = Uri.parse(handle); + if ("tel".equals(uri.getScheme())) { + if (DBG) Slog.w(TAG, "checking telephone URI: " + handle); + lookupResult = lookupPhoneContact(handle, uri.getSchemeSpecificPart()); + } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) { + if (DBG) Slog.w(TAG, "checking lookup URI: " + handle); + lookupResult = resolveContactsUri(handle, uri); + } else { + if (DBG) Slog.w(TAG, "unsupported URI " + handle); + } + } else { + if (DBG) Slog.w(TAG, "using cached lookupResult: " + lookupResult.mId); + } + if (lookupResult != null) { + rank = Math.max(rank, lookupResult.getRank()); + } + } + return rank; + } + + private LookupResult lookupPhoneContact(final String handle, final String number) { + LookupResult lookupResult = null; + Cursor c = null; + try { + Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, + Uri.encode(number)); + c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null); + if (c != null && c.getCount() > 0) { + c.moveToFirst(); + final int idIdx = c.getColumnIndex(Contacts._ID); + final int id = c.getInt(idIdx); + if (DBG) Slog.w(TAG, "is valid: " + id); + lookupResult = new LookupResult(id); + } + } catch(Throwable t) { + Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t); + } finally { + if (c != null) { + c.close(); + } + } + if (lookupResult == null) { + lookupResult = new LookupResult(LookupResult.INVALID_ID); + } + mPeopleCache.put(handle, lookupResult); + return lookupResult; + } + + private LookupResult resolveContactsUri(String handle, final Uri personUri) { + LookupResult lookupResult = null; + Cursor c = null; + try { + c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null); + if (c != null && c.getCount() > 0) { + c.moveToFirst(); + final int idIdx = c.getColumnIndex(Contacts._ID); + final int id = c.getInt(idIdx); + if (DBG) Slog.w(TAG, "is valid: " + id); + lookupResult = new LookupResult(id); + } + } catch(Throwable t) { + Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t); + } finally { + if (c != null) { + c.close(); + } + } + if (lookupResult == null) { + lookupResult = new LookupResult(LookupResult.INVALID_ID); + } + mPeopleCache.put(handle, lookupResult); + return lookupResult; + } + + private final static int clamp(int x, int low, int high) { + return (x < low) ? low : ((x > high) ? high : x); + } + + // TODO: rework this function before shipping + private static int priorityBumpMap(int incomingScore) { + //assumption is that scale runs from [-2*pm, 2*pm] + int pm = NOTIFICATION_PRIORITY_MULTIPLIER; + int theScore = incomingScore; + // enforce input in range + theScore = clamp(theScore, -2 * pm, 2 * pm); + if (theScore != incomingScore) return incomingScore; + // map -20 -> -20 and -10 -> 5 (when pm = 10) + if (theScore <= -pm) { + theScore += 1.5 * (theScore + 2 * pm); + } else { + // map 0 -> 10, 10 -> 15, 20 -> 20; + theScore += 0.5 * (2 * pm - theScore); + } + if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore + + ", score after " + theScore + "."); + return theScore; + } + + @Override + public void initialize(Context context) { + if (DBG) Slog.v(TAG, "Initializing " + getClass().getSimpleName() + "."); + mContext = context; + mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE); + mEnabled = ENABLE_PEOPLE_SCORER && 1 == Settings.Global.getInt( + mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_SCORER, 0); + } + + @Override + public int getScore(Notification notification, int score) { + if (notification == null || !mEnabled) { + if (DBG) Slog.w(TAG, "empty notification? scorer disabled?"); + return score; + } + float contactScore = findMaxContactScore(notification.extras); + if (contactScore > 0f) { + if (DBG) Slog.v(TAG, "Notification references a real contact. Promoted!"); + score = priorityBumpMap(score); + } else { + if (DBG) Slog.v(TAG, "Notification lacks any valid contact reference. Not promoted!"); + } + return score; + } + + private static class LookupResult { + private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr + public static final int INVALID_ID = -1; + + private final long mExpireMillis; + private int mId; + + public LookupResult(int id) { + mId = id; + mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS; + } + + public boolean isExpired() { + return mExpireMillis < System.currentTimeMillis(); + } + + public boolean isInvalid() { + return mId == INVALID_ID || isExpired(); + } + + public float getRank() { + if (isInvalid()) { + return 0f; + } else { + return 1f; // TODO: finer grained score + } + } + + public LookupResult setId(int id) { + mId = id; + return this; + } + } +} + diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp index 180c625..6ae6c8f 100644 --- a/core/jni/android_view_GLRenderer.cpp +++ b/core/jni/android_view_GLRenderer.cpp @@ -142,19 +142,12 @@ static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz, LayerRenderer::destroyLayer(layer); } -static void android_view_GLRenderer_setDisplayListData(JNIEnv* env, jobject clazz, - jlong displayListPtr, jlong newDataPtr) { - using namespace android::uirenderer; - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); - displayList->setData(newData); -} - -static void android_view_GLRenderer_updateRenderNodeProperties(JNIEnv* env, jobject clazz, +static void android_view_GLRenderer_prepareTree(JNIEnv* env, jobject clazz, jlong renderNodePtr) { using namespace android::uirenderer; RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->updateProperties(); + TreeInfo info = {0}; + renderNode->prepareTree(info); } static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz, @@ -195,8 +188,7 @@ static JNINativeMethod gMethods[] = { { "getSystemTime", "()J", (void*) android_view_GLRenderer_getSystemTime }, { "nDestroyLayer", "(J)V", (void*) android_view_GLRenderer_destroyLayer }, - { "nSetDisplayListData", "(JJ)V", (void*) android_view_GLRenderer_setDisplayListData }, - { "nUpdateRenderNodeProperties", "(J)V", (void*) android_view_GLRenderer_updateRenderNodeProperties }, + { "nPrepareTree", "(J)V", (void*) android_view_GLRenderer_prepareTree }, { "nInvokeFunctor", "(JZ)V", (void*) android_view_GLRenderer_invokeFunctor }, #endif diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp index 4bf5f78..2eb0d78 100644 --- a/core/jni/android_view_HardwareLayer.cpp +++ b/core/jni/android_view_HardwareLayer.cpp @@ -127,7 +127,8 @@ static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject cl static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz, jlong layerUpdaterPtr) { DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); - return layer->apply(); + bool ignoredHasFunctors; + return layer->apply(&ignoredHasFunctors); } static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz, diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index cf95657..31a1de6 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -41,32 +41,34 @@ using namespace uirenderer; // DisplayList view properties // ---------------------------------------------------------------------------- -static void android_view_RenderNode_setDisplayListName(JNIEnv* env, - jobject clazz, jlong displayListPtr, jstring name) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); +static void android_view_RenderNode_output(JNIEnv* env, + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->output(); +} + +static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz, jstring name) { + RenderNode* renderNode = new RenderNode(); + renderNode->incStrong(0); if (name != NULL) { const char* textArray = env->GetStringUTFChars(name, NULL); - displayList->setName(textArray); + renderNode->setName(textArray); env->ReleaseStringUTFChars(name, textArray); } + return reinterpret_cast<jlong>(renderNode); } -static void android_view_RenderNode_output(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->output(); -} - -static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz) { - RenderNode* displayList = new RenderNode(); - displayList->incStrong(0); - return reinterpret_cast<jlong>(displayList); +static void android_view_RenderNode_destroyRenderNode(JNIEnv* env, + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->decStrong(0); } -static void android_view_RenderNode_destroyDisplayList(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->decStrong(0); +static void android_view_RenderNode_setDisplayListData(JNIEnv* env, + jobject clazz, jlong renderNodePtr, jlong newDataPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); + renderNode->setStagingDisplayList(newData); } // ---------------------------------------------------------------------------- @@ -74,201 +76,201 @@ static void android_view_RenderNode_destroyDisplayList(JNIEnv* env, // ---------------------------------------------------------------------------- static void android_view_RenderNode_setCaching(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean caching) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setCaching(caching); + jobject clazz, jlong renderNodePtr, jboolean caching) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setCaching(caching); } static void android_view_RenderNode_setStaticMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong matrixPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + jobject clazz, jlong renderNodePtr, jlong matrixPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - displayList->mutateStagingProperties().setStaticMatrix(matrix); + renderNode->mutateStagingProperties().setStaticMatrix(matrix); } static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong matrixPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + jobject clazz, jlong renderNodePtr, jlong matrixPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - displayList->mutateStagingProperties().setAnimationMatrix(matrix); + renderNode->mutateStagingProperties().setAnimationMatrix(matrix); } static void android_view_RenderNode_setClipToBounds(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean clipToBounds) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setClipToBounds(clipToBounds); + jobject clazz, jlong renderNodePtr, jboolean clipToBounds) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setClipToBounds(clipToBounds); } static void android_view_RenderNode_setProjectBackwards(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean shouldProject) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setProjectBackwards(shouldProject); + jobject clazz, jlong renderNodePtr, jboolean shouldProject) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setProjectBackwards(shouldProject); } static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean shouldRecieve) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setProjectionReceiver(shouldRecieve); + jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve); } static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env, - jobject clazz, jlong displayListPtr, jint left, jint top, + jobject clazz, jlong renderNodePtr, jint left, jint top, jint right, jint bottom, jfloat radius) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius); - displayList->mutateStagingProperties().updateClipPath(); + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius); + renderNode->mutateStagingProperties().updateClipPath(); } static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong outlinePathPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + jobject clazz, jlong renderNodePtr, jlong outlinePathPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr); - displayList->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath); - displayList->mutateStagingProperties().updateClipPath(); + renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath); + renderNode->mutateStagingProperties().updateClipPath(); } static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().mutableOutline().setEmpty(); - displayList->mutateStagingProperties().updateClipPath(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().mutableOutline().setEmpty(); + renderNode->mutateStagingProperties().updateClipPath(); } static void android_view_RenderNode_setClipToOutline(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean clipToOutline) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline); - displayList->mutateStagingProperties().updateClipPath(); + jobject clazz, jlong renderNodePtr, jboolean clipToOutline) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline); + renderNode->mutateStagingProperties().updateClipPath(); } static void android_view_RenderNode_setRevealClip(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean shouldClip, jboolean inverseClip, + jobject clazz, jlong renderNodePtr, jboolean shouldClip, jboolean inverseClip, jfloat x, jfloat y, jfloat radius) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().mutableRevealClip().set( + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().mutableRevealClip().set( shouldClip, inverseClip, x, y, radius); - displayList->mutateStagingProperties().updateClipPath(); + renderNode->mutateStagingProperties().updateClipPath(); } static void android_view_RenderNode_setAlpha(JNIEnv* env, - jobject clazz, jlong displayListPtr, float alpha) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setAlpha(alpha); + jobject clazz, jlong renderNodePtr, float alpha) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setAlpha(alpha); } static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env, - jobject clazz, jlong displayListPtr, bool hasOverlappingRendering) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering); + jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering); } static void android_view_RenderNode_setTranslationX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float tx) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setTranslationX(tx); + jobject clazz, jlong renderNodePtr, float tx) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setTranslationX(tx); } static void android_view_RenderNode_setTranslationY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float ty) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setTranslationY(ty); + jobject clazz, jlong renderNodePtr, float ty) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setTranslationY(ty); } static void android_view_RenderNode_setTranslationZ(JNIEnv* env, - jobject clazz, jlong displayListPtr, float tz) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setTranslationZ(tz); + jobject clazz, jlong renderNodePtr, float tz) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setTranslationZ(tz); } static void android_view_RenderNode_setRotation(JNIEnv* env, - jobject clazz, jlong displayListPtr, float rotation) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setRotation(rotation); + jobject clazz, jlong renderNodePtr, float rotation) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setRotation(rotation); } static void android_view_RenderNode_setRotationX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float rx) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setRotationX(rx); + jobject clazz, jlong renderNodePtr, float rx) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setRotationX(rx); } static void android_view_RenderNode_setRotationY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float ry) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setRotationY(ry); + jobject clazz, jlong renderNodePtr, float ry) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setRotationY(ry); } static void android_view_RenderNode_setScaleX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float sx) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setScaleX(sx); + jobject clazz, jlong renderNodePtr, float sx) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setScaleX(sx); } static void android_view_RenderNode_setScaleY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float sy) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setScaleY(sy); + jobject clazz, jlong renderNodePtr, float sy) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setScaleY(sy); } static void android_view_RenderNode_setPivotX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float px) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setPivotX(px); + jobject clazz, jlong renderNodePtr, float px) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setPivotX(px); } static void android_view_RenderNode_setPivotY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float py) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setPivotY(py); + jobject clazz, jlong renderNodePtr, float py) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setPivotY(py); } static void android_view_RenderNode_setCameraDistance(JNIEnv* env, - jobject clazz, jlong displayListPtr, float distance) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setCameraDistance(distance); + jobject clazz, jlong renderNodePtr, float distance) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setCameraDistance(distance); } static void android_view_RenderNode_setLeft(JNIEnv* env, - jobject clazz, jlong displayListPtr, int left) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setLeft(left); + jobject clazz, jlong renderNodePtr, int left) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setLeft(left); } static void android_view_RenderNode_setTop(JNIEnv* env, - jobject clazz, jlong displayListPtr, int top) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setTop(top); + jobject clazz, jlong renderNodePtr, int top) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setTop(top); } static void android_view_RenderNode_setRight(JNIEnv* env, - jobject clazz, jlong displayListPtr, int right) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setRight(right); + jobject clazz, jlong renderNodePtr, int right) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setRight(right); } static void android_view_RenderNode_setBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr, int bottom) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setBottom(bottom); + jobject clazz, jlong renderNodePtr, int bottom) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setBottom(bottom); } static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr, int left, int top, + jobject clazz, jlong renderNodePtr, int left, int top, int right, int bottom) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom); + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom); } static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env, - jobject clazz, jlong displayListPtr, float offset) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().offsetLeftRight(offset); + jobject clazz, jlong renderNodePtr, float offset) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().offsetLeftRight(offset); } static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr, float offset) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().offsetTopBottom(offset); + jobject clazz, jlong renderNodePtr, float offset) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().offsetTopBottom(offset); } // ---------------------------------------------------------------------------- @@ -276,105 +278,105 @@ static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, // ---------------------------------------------------------------------------- static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().hasOverlappingRendering(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().hasOverlappingRendering(); } static jfloat android_view_RenderNode_getAlpha(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getAlpha(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getAlpha(); } static jfloat android_view_RenderNode_getLeft(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getLeft(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getLeft(); } static jfloat android_view_RenderNode_getTop(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getTop(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getTop(); } static jfloat android_view_RenderNode_getRight(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getRight(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getRight(); } static jfloat android_view_RenderNode_getBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getBottom(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getBottom(); } static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getCameraDistance(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getCameraDistance(); } static jfloat android_view_RenderNode_getScaleX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getScaleX(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getScaleX(); } static jfloat android_view_RenderNode_getScaleY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getScaleY(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getScaleY(); } static jfloat android_view_RenderNode_getTranslationX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getTranslationX(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getTranslationX(); } static jfloat android_view_RenderNode_getTranslationY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getTranslationY(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getTranslationY(); } static jfloat android_view_RenderNode_getTranslationZ(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getTranslationZ(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getTranslationZ(); } static jfloat android_view_RenderNode_getRotation(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getRotation(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getRotation(); } static jfloat android_view_RenderNode_getRotationX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getRotationX(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getRotationX(); } static jfloat android_view_RenderNode_getRotationY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getRotationY(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getRotationY(); } static jboolean android_view_RenderNode_isPivotExplicitlySet(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().isPivotExplicitlySet(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().isPivotExplicitlySet(); } static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - return displayList->stagingProperties().getMatrixFlags() == 0; + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + return renderNode->stagingProperties().getMatrixFlags() == 0; } // ---------------------------------------------------------------------------- @@ -382,16 +384,16 @@ static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env, // ---------------------------------------------------------------------------- static void android_view_RenderNode_getTransformMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong outMatrixPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr); - displayList->mutateStagingProperties().updateMatrix(); - const SkMatrix* transformMatrix = displayList->stagingProperties().getTransformMatrix(); + renderNode->mutateStagingProperties().updateMatrix(); + const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix(); - if (displayList->stagingProperties().getMatrixFlags() == TRANSLATION) { - outMatrix->setTranslate(displayList->stagingProperties().getTranslationX(), - displayList->stagingProperties().getTranslationY()); + if (renderNode->stagingProperties().getMatrixFlags() == TRANSLATION) { + outMatrix->setTranslate(renderNode->stagingProperties().getTranslationX(), + renderNode->stagingProperties().getTranslationY()); } else if (transformMatrix) { *outMatrix = *transformMatrix; } else { @@ -400,9 +402,9 @@ static void android_view_RenderNode_getTransformMatrix(JNIEnv* env, } static void android_view_RenderNode_getInverseTransformMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong outMatrixPtr) { + jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) { // load transform matrix - android_view_RenderNode_getTransformMatrix(env, clazz, displayListPtr, outMatrixPtr); + android_view_RenderNode_getTransformMatrix(env, clazz, renderNodePtr, outMatrixPtr); SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr); // return it inverted @@ -413,17 +415,17 @@ static void android_view_RenderNode_getInverseTransformMatrix(JNIEnv* env, } static jfloat android_view_RenderNode_getPivotX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().updateMatrix(); - return displayList->stagingProperties().getPivotX(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().updateMatrix(); + return renderNode->stagingProperties().getPivotX(); } static jfloat android_view_RenderNode_getPivotY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - displayList->mutateStagingProperties().updateMatrix(); - return displayList->stagingProperties().getPivotY(); + jobject clazz, jlong renderNodePtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->mutateStagingProperties().updateMatrix(); + return renderNode->stagingProperties().getPivotY(); } #endif // USE_OPENGL_RENDERER @@ -436,10 +438,9 @@ const char* const kClassPathName = "android/view/RenderNode"; static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER - { "nCreate", "()J", (void*) android_view_RenderNode_create }, - { "nDestroyDisplayList", "(J)V", (void*) android_view_RenderNode_destroyDisplayList }, - { "nSetDisplayListName", "(JLjava/lang/String;)V", - (void*) android_view_RenderNode_setDisplayListName }, + { "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create }, + { "nDestroyRenderNode", "(J)V", (void*) android_view_RenderNode_destroyRenderNode }, + { "nSetDisplayListData", "(JJ)V", (void*) android_view_RenderNode_setDisplayListData }, { "nOutput", "(J)V", (void*) android_view_RenderNode_output }, { "nSetCaching", "(JZ)V", (void*) android_view_RenderNode_setCaching }, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 159ffb2..8141a00 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -34,6 +34,7 @@ #include <gui/SurfaceComposerClient.h> #include <ui/DisplayInfo.h> +#include <ui/FrameStats.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -64,6 +65,16 @@ void DeleteScreenshot(void* addr, void* context) { delete ((ScreenshotClient*) context); } +static struct { + nsecs_t UNDEFINED_TIME_NANO; + jmethodID init; +} gWindowContentFrameStatsClassInfo; + +static struct { + nsecs_t UNDEFINED_TIME_NANO; + jmethodID init; +} gWindowAnimationFrameStatsClassInfo; + // ---------------------------------------------------------------------------- static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, @@ -371,6 +382,151 @@ static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) { SurfaceComposerClient::unblankDisplay(token); } +static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) { + SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + status_t err = ctrl->clearLayerFrameStats(); + + if (err < 0 && err != NO_INIT) { + doThrowIAE(env); + } + + // The other end is not ready, just report we failed. + if (err == NO_INIT) { + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject, + jobject outStats) { + FrameStats stats; + + SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + status_t err = ctrl->getLayerFrameStats(&stats); + if (err < 0 && err != NO_INIT) { + doThrowIAE(env); + } + + // The other end is not ready, fine just return empty stats. + if (err == NO_INIT) { + return JNI_FALSE; + } + + jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano); + size_t frameCount = stats.desiredPresentTimesNano.size(); + + jlongArray postedTimesNanoDst = env->NewLongArray(frameCount); + if (postedTimesNanoDst == NULL) { + return JNI_FALSE; + } + + jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount); + if (presentedTimesNanoDst == NULL) { + return JNI_FALSE; + } + + jlongArray readyTimesNanoDst = env->NewLongArray(frameCount); + if (readyTimesNanoDst == NULL) { + return JNI_FALSE; + } + + nsecs_t postedTimesNanoSrc[frameCount]; + nsecs_t presentedTimesNanoSrc[frameCount]; + nsecs_t readyTimesNanoSrc[frameCount]; + + for (size_t i = 0; i < frameCount; i++) { + nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i]; + if (postedTimeNano == INT64_MAX) { + postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO; + } + postedTimesNanoSrc[i] = postedTimeNano; + + nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i]; + if (presentedTimeNano == INT64_MAX) { + presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO; + } + presentedTimesNanoSrc[i] = presentedTimeNano; + + nsecs_t readyTimeNano = stats.frameReadyTimesNano[i]; + if (readyTimeNano == INT64_MAX) { + readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO; + } + readyTimesNanoSrc[i] = readyTimeNano; + } + + env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc); + env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc); + env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc); + + env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano, + postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst); + + if (env->ExceptionCheck()) { + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) { + status_t err = SurfaceComposerClient::clearAnimationFrameStats(); + + if (err < 0 && err != NO_INIT) { + doThrowIAE(env); + } + + // The other end is not ready, just report we failed. + if (err == NO_INIT) { + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) { + FrameStats stats; + + status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats); + if (err < 0 && err != NO_INIT) { + doThrowIAE(env); + } + + // The other end is not ready, fine just return empty stats. + if (err == NO_INIT) { + return JNI_FALSE; + } + + jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano); + size_t frameCount = stats.desiredPresentTimesNano.size(); + + jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount); + if (presentedTimesNanoDst == NULL) { + return JNI_FALSE; + } + + nsecs_t presentedTimesNanoSrc[frameCount]; + + for (size_t i = 0; i < frameCount; i++) { + nsecs_t presentedTimeNano = stats.desiredPresentTimesNano[i]; + if (presentedTimeNano == INT64_MAX) { + presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO; + } + presentedTimesNanoSrc[i] = presentedTimeNano; + } + + env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc); + + env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano, + presentedTimesNanoDst); + + if (env->ExceptionCheck()) { + return JNI_FALSE; + } + + return JNI_TRUE; +} + // ---------------------------------------------------------------------------- static JNINativeMethod sSurfaceControlMethods[] = { @@ -426,6 +582,14 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeBlankDisplay }, {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V", (void*)nativeUnblankDisplay }, + {"nativeClearContentFrameStats", "(J)Z", + (void*)nativeClearContentFrameStats }, + {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z", + (void*)nativeGetContentFrameStats }, + {"nativeClearAnimationFrameStats", "()Z", + (void*)nativeClearAnimationFrameStats }, + {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z", + (void*)nativeGetAnimationFrameStats }, }; int register_android_view_SurfaceControl(JNIEnv* env) @@ -441,6 +605,19 @@ int register_android_view_SurfaceControl(JNIEnv* env) gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F"); gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F"); gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z"); + + jclass frameStatsClazz = env->FindClass("android/view/FrameStats"); + jfieldID undefined_time_nano_field = env->GetStaticFieldID(frameStatsClazz, "UNDEFINED_TIME_NANO", "J"); + nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field); + + jclass contFrameStatsClazz = env->FindClass("android/view/WindowContentFrameStats"); + gWindowContentFrameStatsClassInfo.init = env->GetMethodID(contFrameStatsClazz, "init", "(J[J[J[J)V"); + gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano; + + jclass animFrameStatsClazz = env->FindClass("android/view/WindowAnimationFrameStats"); + gWindowAnimationFrameStatsClassInfo.init = env->GetMethodID(animFrameStatsClazz, "init", "(J[J)V"); + gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano; + return err; } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 32890cf..30d3e0c 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -84,7 +84,7 @@ static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject cl jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface); - return proxy->initialize(window.get()); + return proxy->initialize(window); } static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz, @@ -94,21 +94,23 @@ static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject cla if (jsurface) { window = android_view_Surface_getNativeWindow(env, jsurface); } - proxy->updateSurface(window.get()); + proxy->updateSurface(window); } -static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, - jlong proxyPtr, jint width, jint height) { +static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz, + jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->setup(width, height); + sp<ANativeWindow> window; + if (jsurface) { + window = android_view_Surface_getNativeWindow(env, jsurface); + } + proxy->pauseSurface(window); } -static void android_view_ThreadedRenderer_setDisplayListData(JNIEnv* env, jobject clazz, - jlong proxyPtr, jlong displayListPtr, jlong newDataPtr) { +static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, + jlong proxyPtr, jint width, jint height) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); - proxy->setDisplayListData(displayList, newData); + proxy->setup(width, height); } static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz, @@ -125,20 +127,6 @@ static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject cla proxy->destroyCanvas(); } -static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz, - jlong proxyPtr, jlong functorPtr) { - RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - Functor* functor = reinterpret_cast<Functor*>(functorPtr); - proxy->attachFunctor(functor); -} - -static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz, - jlong proxyPtr, jlong functorPtr) { - RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - Functor* functor = reinterpret_cast<Functor*>(functorPtr); - proxy->detachFunctor(functor); -} - static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, jlong proxyPtr, jlong functorPtr, jboolean waitForCompletion) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); @@ -203,12 +191,10 @@ static JNINativeMethod gMethods[] = { { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize }, { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, + { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface }, { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup }, - { "nSetDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_setDisplayListData }, { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList }, { "nDestroyCanvas", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvas }, - { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor }, - { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor }, { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext }, { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer }, diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index a860918..230658f 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -19,11 +19,12 @@ #include <android_runtime/AndroidRuntime.h> -#include <utils/Log.h> -#include <androidfw/ZipFileRO.h> -#include <androidfw/ZipUtils.h> #include <ScopedUtfChars.h> #include <UniquePtr.h> +#include <androidfw/ZipFileRO.h> +#include <androidfw/ZipUtils.h> +#include <utils/Log.h> +#include <utils/Vector.h> #include <zlib.h> @@ -54,17 +55,19 @@ namespace android { // These match PackageManager.java install codes -typedef enum { +enum install_status_t { INSTALL_SUCCEEDED = 1, INSTALL_FAILED_INVALID_APK = -2, INSTALL_FAILED_INSUFFICIENT_STORAGE = -4, INSTALL_FAILED_CONTAINER_ERROR = -18, INSTALL_FAILED_INTERNAL_ERROR = -110, -} install_status_t; + INSTALL_FAILED_NO_MATCHING_ABIS = -113, + NO_NATIVE_LIBRARIES = -114 +}; typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*); -// Equivalent to isFilenameSafe +// Equivalent to android.os.FileUtils.isFilenameSafe static bool isFilenameSafe(const char* filename) { @@ -268,126 +271,252 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr return INSTALL_SUCCEEDED; } -static install_status_t -iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, jstring javaCpuAbi2, - iterFunc callFunc, void* callArg) { - ScopedUtfChars filePath(env, javaFilePath); - ScopedUtfChars cpuAbi(env, javaCpuAbi); - ScopedUtfChars cpuAbi2(env, javaCpuAbi2); - - UniquePtr<ZipFileRO> zipFile(ZipFileRO::open(filePath.c_str())); - if (zipFile.get() == NULL) { - ALOGI("Couldn't open APK %s\n", filePath.c_str()); - return INSTALL_FAILED_INVALID_APK; +/* + * An iterator over all shared libraries in a zip file. An entry is + * considered to be a shared library if all of the conditions below are + * satisfied : + * + * - The entry is under the lib/ directory. + * - The entry name ends with ".so" and the entry name starts with "lib", + * an exception is made for entries whose name is "gdbserver". + * - The entry filename is "safe" (as determined by isFilenameSafe). + * + */ +class NativeLibrariesIterator { +private: + NativeLibrariesIterator(ZipFileRO* zipFile, void* cookie) + : mZipFile(zipFile), mCookie(cookie), mLastSlash(NULL) { + fileName[0] = '\0'; } - char fileName[PATH_MAX]; - bool hasPrimaryAbi = false; +public: + static NativeLibrariesIterator* create(ZipFileRO* zipFile) { + void* cookie = NULL; + if (!zipFile->startIteration(&cookie)) { + return NULL; + } - void* cookie = NULL; - if (!zipFile->startIteration(&cookie)) { - ALOGI("Couldn't iterate over APK%s\n", filePath.c_str()); - return INSTALL_FAILED_INVALID_APK; + return new NativeLibrariesIterator(zipFile, cookie); } - ZipEntryRO entry = NULL; - while ((entry = zipFile->nextEntry(cookie)) != NULL) { - // Make sure this entry has a filename. - if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) { - continue; - } + ZipEntryRO next() { + ZipEntryRO next = NULL; + while ((next = mZipFile->nextEntry(mCookie)) != NULL) { + // Make sure this entry has a filename. + if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) { + continue; + } - // Make sure we're in the lib directory of the ZIP. - if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) { - continue; - } + // Make sure we're in the lib directory of the ZIP. + if (strncmp(fileName, APK_LIB, APK_LIB_LEN)) { + continue; + } - // Make sure the filename is at least to the minimum library name size. - const size_t fileNameLen = strlen(fileName); - static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN; - if (fileNameLen < minLength) { - continue; - } + // Make sure the filename is at least to the minimum library name size. + const size_t fileNameLen = strlen(fileName); + static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN; + if (fileNameLen < minLength) { + continue; + } - const char* lastSlash = strrchr(fileName, '/'); - ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName); + const char* lastSlash = strrchr(fileName, '/'); + ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName); - // Check to make sure the CPU ABI of this file is one we support. - const char* cpuAbiOffset = fileName + APK_LIB_LEN; - const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset; + // Exception: If we find the gdbserver binary, return it. + if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) { + break; + } - ALOGV("Comparing ABIs %s and %s versus %s\n", cpuAbi.c_str(), cpuAbi2.c_str(), cpuAbiOffset); - if (cpuAbi.size() == cpuAbiRegionSize - && *(cpuAbiOffset + cpuAbi.size()) == '/' - && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) { - ALOGV("Using primary ABI %s\n", cpuAbi.c_str()); - hasPrimaryAbi = true; - } else if (cpuAbi2.size() == cpuAbiRegionSize - && *(cpuAbiOffset + cpuAbi2.size()) == '/' - && !strncmp(cpuAbiOffset, cpuAbi2.c_str(), cpuAbiRegionSize)) { - - /* - * If this library matches both the primary and secondary ABIs, - * only use the primary ABI. - */ - if (hasPrimaryAbi) { - ALOGV("Already saw primary ABI, skipping secondary ABI %s\n", cpuAbi2.c_str()); + // Make sure the filename starts with lib and ends with ".so". + if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN) + || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) { continue; - } else { - ALOGV("Using secondary ABI %s\n", cpuAbi2.c_str()); } - } else { - ALOGV("abi didn't match anything: %s (end at %zd)\n", cpuAbiOffset, cpuAbiRegionSize); - continue; + + // Make sure the filename is safe. + if (!isFilenameSafe(lastSlash + 1)) { + continue; + } + + mLastSlash = lastSlash; + break; } - // If this is a .so file, check to see if we need to copy it. - if ((!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN) - && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN) - && isFilenameSafe(lastSlash + 1)) - || !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) { + return next; + } + + inline const char* currentEntry() const { + return fileName; + } + + inline const char* lastSlash() const { + return mLastSlash; + } + + virtual ~NativeLibrariesIterator() { + mZipFile->endIteration(mCookie); + } +private: + + char fileName[PATH_MAX]; + ZipFileRO* const mZipFile; + void* mCookie; + const char* mLastSlash; +}; - install_status_t ret = callFunc(env, callArg, zipFile.get(), entry, lastSlash + 1); +static install_status_t +iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi, + iterFunc callFunc, void* callArg) { + ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle); + if (zipFile == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile)); + if (it.get() == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + const ScopedUtfChars cpuAbi(env, javaCpuAbi); + if (cpuAbi.c_str() == NULL) { + // This would've thrown, so this return code isn't observable by + // Java. + return INSTALL_FAILED_INVALID_APK; + } + ZipEntryRO entry = NULL; + while ((entry = it->next()) != NULL) { + const char* fileName = it->currentEntry(); + const char* lastSlash = it->lastSlash(); + + // Check to make sure the CPU ABI of this file is one we support. + const char* cpuAbiOffset = fileName + APK_LIB_LEN; + const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset; + + if (cpuAbi.size() == cpuAbiRegionSize && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) { + install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1); if (ret != INSTALL_SUCCEEDED) { ALOGV("Failure for entry %s", lastSlash + 1); - zipFile->endIteration(cookie); return ret; } } } - zipFile->endIteration(cookie); - return INSTALL_SUCCEEDED; } + +static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray) { + const int numAbis = env->GetArrayLength(supportedAbisArray); + Vector<ScopedUtfChars*> supportedAbis; + + for (int i = 0; i < numAbis; ++i) { + supportedAbis.add(new ScopedUtfChars(env, + (jstring) env->GetObjectArrayElement(supportedAbisArray, i))); + } + + ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle); + if (zipFile == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile)); + if (it.get() == NULL) { + return INSTALL_FAILED_INVALID_APK; + } + + ZipEntryRO entry = NULL; + char fileName[PATH_MAX]; + int status = NO_NATIVE_LIBRARIES; + while ((entry = it->next()) != NULL) { + // We're currently in the lib/ directory of the APK, so it does have some native + // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the + // libraries match. + if (status == NO_NATIVE_LIBRARIES) { + status = INSTALL_FAILED_NO_MATCHING_ABIS; + } + + const char* fileName = it->currentEntry(); + const char* lastSlash = it->lastSlash(); + + // Check to see if this CPU ABI matches what we are looking for. + const char* abiOffset = fileName + APK_LIB_LEN; + const size_t abiSize = lastSlash - abiOffset; + for (int i = 0; i < numAbis; i++) { + const ScopedUtfChars* abi = supportedAbis[i]; + if (abi->size() == abiSize && !strncmp(abiOffset, abi->c_str(), abiSize)) { + // The entry that comes in first (i.e. with a lower index) has the higher priority. + if (((i < status) && (status >= 0)) || (status < 0) ) { + status = i; + } + } + } + } + + for (int i = 0; i < numAbis; ++i) { + delete supportedAbis[i]; + } + + return status; +} + static jint com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz, - jstring javaFilePath, jstring javaNativeLibPath, jstring javaCpuAbi, jstring javaCpuAbi2) + jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi) { - return (jint) iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2, + return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, copyFileIfChanged, &javaNativeLibPath); } static jlong com_android_internal_content_NativeLibraryHelper_sumNativeBinaries(JNIEnv *env, jclass clazz, - jstring javaFilePath, jstring javaCpuAbi, jstring javaCpuAbi2) + jlong apkHandle, jstring javaCpuAbi) { size_t totalSize = 0; - iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2, sumFiles, &totalSize); + iterateOverNativeFiles(env, apkHandle, javaCpuAbi, sumFiles, &totalSize); return totalSize; } +static jint +com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, jclass clazz, + jlong apkHandle, jobjectArray javaCpuAbisToSearch) +{ + return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch); +} + +static jlong +com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, jstring apkPath) +{ + ScopedUtfChars filePath(env, apkPath); + ZipFileRO* zipFile = ZipFileRO::open(filePath.c_str()); + + return reinterpret_cast<jlong>(zipFile); +} + +static void +com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle) +{ + delete reinterpret_cast<ZipFileRO*>(apkHandle); +} + static JNINativeMethod gMethods[] = { + {"nativeOpenApk", + "(Ljava/lang/String;)J", + (void *)com_android_internal_content_NativeLibraryHelper_openApk}, + {"nativeClose", + "(J)V", + (void *)com_android_internal_content_NativeLibraryHelper_close}, {"nativeCopyNativeBinaries", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", + "(JLjava/lang/String;Ljava/lang/String;)I", (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries}, {"nativeSumNativeBinaries", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", + "(JLjava/lang/String;)J", (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries}, + {"nativeFindSupportedAbi", + "(J[Ljava/lang/String;)I", + (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi}, }; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 0f772f1..a83942f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1921,6 +1921,18 @@ android:description="@string/permdesc_filter_events" android:protectionLevel="signature" /> + <!-- @hide Allows an application to retrieve the window token from the accessibility manager. --> + <permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" + android:label="@string/permlab_retrieveWindowToken" + android:description="@string/permdesc_retrieveWindowToken" + android:protectionLevel="signature" /> + + <!-- @hide Allows an application to collect frame statistics --> + <permission android:name="android.permission.FRAME_STATS" + android:label="@string/permlab_frameStats" + android:description="@string/permdesc_frameStats" + android:protectionLevel="signature" /> + <!-- @hide Allows an application to temporary enable accessibility on the device. --> <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY" android:label="@string/permlab_temporary_enable_accessibility" diff --git a/core/res/res/layout/preference_category_quantum.xml b/core/res/res/layout/preference_category_quantum.xml new file mode 100644 index 0000000..032e09d --- /dev/null +++ b/core/res/res/layout/preference_category_quantum.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Layout used for PreferenceCategory in a PreferenceActivity. --> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+android:id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="16dip" + android:textAppearance="@style/TextAppearance.Quantum.Body2" + android:textColor="?android:attr/textColorSecondary" + android:textStyle="bold" + android:paddingStart="?attr/listPreferredItemPaddingStart" + android:paddingEnd="?attr/listPreferredItemPaddingEnd" + android:paddingTop="16dip" /> diff --git a/core/res/res/layout/preference_child_quantum.xml b/core/res/res/layout/preference_child_quantum.xml new file mode 100644 index 0000000..690d64a --- /dev/null +++ b/core/res/res/layout/preference_child_quantum.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Layout for a visually child-like Preference in a PreferenceActivity. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="?attr/listPreferredItemPaddingStart" + android:minHeight="?android:attr/listPreferredItemHeight" + android:gravity="center_vertical" + android:paddingStart="?attr/listPreferredItemPaddingStart" + android:paddingEnd="?attr/listPreferredItemPaddingEnd"> + + <LinearLayout + android:id="@+android:id/icon_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="58dip" + android:gravity="left|center_vertical" + android:orientation="horizontal"> + <ImageView + android:id="@+android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dip" /> + </LinearLayout> + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingTop="16dip" + android:paddingBottom="16dip"> + + <TextView android:id="@+android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceListItem" /> + + <TextView android:id="@+android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_alignStart="@android:id/title" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" + android:textColor="?android:attr/textColorSecondary" + android:maxLines="10" /> + + </RelativeLayout> + + <!-- Preference should place its actual preference widget here. --> + <LinearLayout android:id="@+android:id/widget_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="58dip" + android:gravity="right|center_vertical" + android:orientation="vertical" /> + +</LinearLayout> diff --git a/core/res/res/layout/preference_information_quantum.xml b/core/res/res/layout/preference_information_quantum.xml new file mode 100644 index 0000000..f21640f --- /dev/null +++ b/core/res/res/layout/preference_information_quantum.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Layout for a Preference in a PreferenceActivity. The + Preference is able to place a specific widget for its particular + type in the "widget_frame" layout. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:gravity="center_vertical" + android:paddingStart="?attr/listPreferredItemPaddingStart" + android:paddingEnd="?attr/listPreferredItemPaddingEnd"> + + <LinearLayout + android:id="@+android:id/icon_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="58dip" + android:gravity="left|center_vertical" + android:orientation="horizontal"> + <ImageView + android:id="@+android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="8dip" /> + </LinearLayout> + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingTop="16dip" + android:paddingBottom="16dip"> + + <TextView android:id="@+android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceListItem" /> + + <TextView android:id="@+android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_alignStart="@android:id/title" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" + android:textColor="?android:attr/textColorSecondary" + android:maxLines="10" /> + + </RelativeLayout> + + <!-- Preference should place its actual preference widget here. --> + <LinearLayout android:id="@+android:id/widget_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="58dip" + android:gravity="right|center_vertical" + android:orientation="vertical" /> + +</LinearLayout> diff --git a/core/res/res/layout/preference_quantum.xml b/core/res/res/layout/preference_quantum.xml new file mode 100644 index 0000000..a4fe73d --- /dev/null +++ b/core/res/res/layout/preference_quantum.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Layout for a Preference in a PreferenceActivity. The + Preference is able to place a specific widget for its particular + type in the "widget_frame" layout. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:gravity="center_vertical" + android:paddingStart="?attr/listPreferredItemPaddingStart" + android:paddingEnd="?attr/listPreferredItemPaddingEnd" + android:background="?android:attr/activatedBackgroundIndicator"> + + <LinearLayout + android:id="@+android:id/icon_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="58dip" + android:gravity="left|center_vertical" + android:orientation="horizontal"> + <ImageView + android:id="@+android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:scaleType="centerInside" + android:layout_marginEnd="8dip" /> + </LinearLayout> + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingTop="16dip" + android:paddingBottom="16dip"> + + <TextView android:id="@+android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceListItem" + android:ellipsize="marquee" /> + + <TextView android:id="@+android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_alignStart="@android:id/title" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" + android:textColor="?android:attr/textColorSecondary" + android:maxLines="10" /> + + </RelativeLayout> + + <!-- Preference should place its actual preference widget here. --> + <LinearLayout android:id="@+android:id/widget_frame" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="58dip" + android:gravity="right|center_vertical" + android:orientation="vertical" /> + +</LinearLayout> diff --git a/core/res/res/layout/preference_widget_checkbox.xml b/core/res/res/layout/preference_widget_checkbox.xml index 33a43f4..bfd7f0a 100644 --- a/core/res/res/layout/preference_widget_checkbox.xml +++ b/core/res/res/layout/preference_widget_checkbox.xml @@ -20,6 +20,5 @@ android:id="@+android:id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" android:focusable="false" android:clickable="false" /> diff --git a/core/res/res/layout/preference_widget_switch.xml b/core/res/res/layout/preference_widget_switch.xml index 83ef097..534c7ec 100644 --- a/core/res/res/layout/preference_widget_switch.xml +++ b/core/res/res/layout/preference_widget_switch.xml @@ -20,6 +20,5 @@ android:id="@+android:id/switchWidget" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center" android:padding="16dip" android:focusable="false" /> diff --git a/core/res/res/layout/simple_list_item_1.xml b/core/res/res/layout/simple_list_item_1.xml index 4249d10..43a5635 100644 --- a/core/res/res/layout/simple_list_item_1.xml +++ b/core/res/res/layout/simple_list_item_1.xml @@ -22,5 +22,4 @@ android:gravity="center_vertical" android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:minHeight="?android:attr/listPreferredItemHeightSmall" -/> + android:minHeight="?android:attr/listPreferredItemHeightSmall" /> diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml index 63c542b..b47a346 100644 --- a/core/res/res/layout/simple_list_item_2.xml +++ b/core/res/res/layout/simple_list_item_2.xml @@ -20,22 +20,19 @@ android:minHeight="?android:attr/listPreferredItemHeight" android:mode="twoLine" android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" -> - + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> + <TextView android:id="@android:id/text1" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="8dip" - android:textAppearance="?android:attr/textAppearanceListItem" - /> - + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dip" + android:textAppearance="?android:attr/textAppearanceListItem" /> + <TextView android:id="@android:id/text2" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@android:id/text1" - android:layout_alignStart="@android:id/text1" - android:textAppearance="?android:attr/textAppearanceSmall" - /> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@android:id/text1" + android:layout_alignStart="@android:id/text1" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" /> </TwoLineListItem> diff --git a/core/res/res/layout/simple_list_item_2_single_choice.xml b/core/res/res/layout/simple_list_item_2_single_choice.xml index 5629567..65c5856 100644 --- a/core/res/res/layout/simple_list_item_2_single_choice.xml +++ b/core/res/res/layout/simple_list_item_2_single_choice.xml @@ -22,31 +22,34 @@ android:paddingStart="16dip" android:paddingEnd="12dip" android:minHeight="?android:attr/listPreferredItemHeightSmall"> + <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:gravity="center_vertical"> + <TextView android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceMedium" + android:textAppearance="?android:attr/textAppearanceListItem" android:textColor="?android:attr/textColorAlertDialogListItem" android:gravity="center_vertical|start" android:singleLine="true" - android:ellipsize="marquee" - /> + android:ellipsize="marquee" /> + <TextView android:id="@android:id/text2" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorAlertDialogListItem" android:gravity="center_vertical|start" android:singleLine="true" - android:ellipsize="marquee" - /> + android:ellipsize="marquee" /> + </LinearLayout> + <RadioButton android:id="@+id/radio" android:layout_width="35dip" @@ -54,6 +57,6 @@ android:paddingEnd="12dip" android:gravity="center_vertical" android:focusable="false" - android:clickable="false" - /> + android:clickable="false" /> + </LinearLayout> diff --git a/core/res/res/layout/simple_list_item_activated_1.xml b/core/res/res/layout/simple_list_item_activated_1.xml index 41155e4..9b778d7 100644 --- a/core/res/res/layout/simple_list_item_activated_1.xml +++ b/core/res/res/layout/simple_list_item_activated_1.xml @@ -23,5 +23,4 @@ android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:background="?android:attr/activatedBackgroundIndicator" - android:minHeight="?android:attr/listPreferredItemHeightSmall" -/> + android:minHeight="?android:attr/listPreferredItemHeightSmall" /> diff --git a/core/res/res/layout/simple_list_item_activated_2.xml b/core/res/res/layout/simple_list_item_activated_2.xml index 725697d..5036813 100644 --- a/core/res/res/layout/simple_list_item_activated_2.xml +++ b/core/res/res/layout/simple_list_item_activated_2.xml @@ -21,23 +21,20 @@ android:layout_height="wrap_content" android:background="?android:attr/activatedBackgroundIndicator" android:minHeight="?android:attr/listPreferredItemHeight" - android:mode="twoLine" -> + android:mode="twoLine"> <TextView android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="?android:attr/listPreferredItemPaddingStart" android:layout_marginTop="6dip" - android:textAppearance="?android:attr/textAppearanceListItem" - /> + android:textAppearance="?android:attr/textAppearanceListItem" /> <TextView android:id="@android:id/text2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@android:id/text1" android:layout_alignStart="@android:id/text1" - android:textAppearance="?android:attr/textAppearanceSmall" - /> + android:textAppearance="?android:attr/textAppearanceListItemSecondary" /> </TwoLineListItem> diff --git a/core/res/res/layout/simple_list_item_checked.xml b/core/res/res/layout/simple_list_item_checked.xml index 0c497d6..4673e27 100644 --- a/core/res/res/layout/simple_list_item_checked.xml +++ b/core/res/res/layout/simple_list_item_checked.xml @@ -22,5 +22,4 @@ android:gravity="center_vertical" android:checkMark="?android:attr/textCheckMark" android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" -/> + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" /> diff --git a/core/res/res/layout/simple_list_item_multiple_choice.xml b/core/res/res/layout/simple_list_item_multiple_choice.xml index 076d8c6..440b6fd 100644 --- a/core/res/res/layout/simple_list_item_multiple_choice.xml +++ b/core/res/res/layout/simple_list_item_multiple_choice.xml @@ -22,5 +22,4 @@ android:gravity="center_vertical" android:checkMark="?android:attr/listChoiceIndicatorMultiple" android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" -/> + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" /> diff --git a/core/res/res/layout/simple_list_item_single_choice.xml b/core/res/res/layout/simple_list_item_single_choice.xml index 4c1af09..02cb7f7 100644 --- a/core/res/res/layout/simple_list_item_single_choice.xml +++ b/core/res/res/layout/simple_list_item_single_choice.xml @@ -22,5 +22,4 @@ android:gravity="center_vertical" android:checkMark="?android:attr/listChoiceIndicatorSingle" android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" -/> + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" /> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index b9bdfb9..88f5c54 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"voeg \'n toesteladministrateur by of verwyder een"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Laat die houer aktiewe toesteladministrateurs byvoeg of verwyder. Behoort nooit nodig te wees vir normale programme nie."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"verander skermoriëntasie"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 22246c1..9795461 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"የመሣሪያ አስተዳዳሪ ያክሉ ወይም ያስወግዱ"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ያዢው ንቁ የመሣሪያ አስተዳዳሪዎች እንዲያክል ወይም እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች ጭራሽ ሊያስፈልግ አይገባም።"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"የማያ ገፀ አቀማመጥን ለውጥ"</string> @@ -688,7 +692,7 @@ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"የግቤት መሣሪያ ማስተካከያ ቀይር"</string> <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"መተግበሪያው የማያ ንካ የማስተካከያ ልኬቶቹን እንዲቀይር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string> <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"የDRM የምስክር ወረቀቶች ላይ ይድረሱ"</string> - <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"አንድ መተግበሪያ የDRM የምስክር ወረቀቶችን እንዲሰጥና እንዲጠም ያስችላል። ለመደበኛ መተግበሪያዎች በፍጹም አስፈላጊ አይሆንም።"</string> + <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"አንድ መተግበሪያ የDRM የምስክር ወረቀቶችን እንዲሰጥና እንዲጠቀም ያስችላል። ለመደበኛ መተግበሪያዎች በፍጹም አስፈላጊ አይሆንም።"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 9efd8eb..101c4dc 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"إضافة مشرف جهاز أو إزالته"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"للسماح بحامل البطاقة بإضافة مشرفي أجهزة نشطين أو إزالتهم. لا يلزم ذلك أبدًا للتطبيقات العادية."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 366de7c..499280e 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"добавяне или премахване на администратор на устройства"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Разрешава на притежателя да добавя или премахва администратори на активни устройства. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 6cba689..1d063f6 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"afegeix un administrador al dispositiu o suprimeix-lo"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet que el titular afegeixi administradors actius al dispositiu o en suprimeixi. No s\'hauria de necessitar per a les aplicacions normals."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string> @@ -687,7 +691,7 @@ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string> <string name="permlab_setInputCalibration" msgid="4902620118878467615">"canviar el calibratge del dispositiu d\'entrada"</string> <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet que l\'aplicació modifiqui els paràmetres de calibratge de la pantalla tàctil. No ha de ser mai necessari per a aplicacions normals."</string> - <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accés als certificats de DRM"</string> + <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accedir als certificats de DRM"</string> <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permet que una aplicació proporcioni i utilitzi certificats de gestió de drets digitals (DRM, Digital Rights Management). No ha de ser mai necessari per a aplicacions normals."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index b4972ef..6a14d0e 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"přidat nebo odebrat správce zařízení"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Opravňuje držitele přidávat nebo odebírat aktivní správce zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index d3469f1..3c113f0 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tilføje eller fjerne en enhedsadministrator"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillader, at man tilføjer eller fjerner aktive enhedsadministratorer. Dette burde aldrig være nødvendigt til normale apps."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 52ea81c..c2c8600 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Geräteadministrator hinzufügen oder entfernen"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ermöglicht dem Inhaber, aktive Geräteadministratoren hinzuzufügen oder zu entfernen. Sollte für normale Apps nie benötigt werden."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 8b7e618..e1e9106 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"προσθήκη ή κατάργηση ενός διαχειριστή συσκευής"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Επιτρέπει στον κάτοχο να προσθέτει ή να καταργεί ενεργούς διαχειριστές συσκευών. Δεν θα πρέπει να ζητείται ποτέ για κανονικές εφαρμογές."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 179691b..8da35f1 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 179691b..8da35f1 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index dc67e27..ae96d40 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"agregar o eliminar un administrador de dispositivos"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite al propietario agregar o eliminar administradores de dispositivos activos. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 8386b02..638b9f4 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"añadir o eliminar un administrador de dispositivos"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite añadir o eliminar administradores de dispositivos activos. No debe ser necesario para aplicaciones normales."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index 4d15e4a..adb033f 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"seadme administraatori lisamine või eemaldamine"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Võimaldab omanikul lisada või eemaldada aktiivseid seadme administraatoreid. Tavarakenduste puhul ei tohiks see kunagi vajalik olla."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"muuda ekraani paigutust"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index b621d49..3375255 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"به دارنده اجازه میدهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامههای معمولی هیچگاه به این ویژگی نیازی ندارند."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"اضافه یا حذف سرپرست دستگاه"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"به دارنده اجازه میدهد سرپرستان دستگاه فعال را اضافه یا حذف کند.هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 6dd5e56..d2bf01c 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lisää tai poista laitteen järjestelmänvalvoja"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Haltija voi lisätä tai poistaa aktiivisen laitteen järjestelmänvalvojia. Tätä ei pitäisi tarvita tavallisille sovelluksille."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 7a8c975..74df7fe 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient jamais utiliser cette autorisation."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"modifier l\'orientation de l\'écran"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index a57823f..691c6a4 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application autorisée d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient pas nécessiter cette autorisation."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index bdba457..1419bc4 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण उपकरण सुचारू ढ़ंग से चलाने वाले को जोड़ें या निकालें"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"स्क्रीन अभिविन्यास बदलें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index fcd51ab..dde0a5b 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodavanje ili uklanjanje administratora uređaja"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Omogućuje nositelju dodavanje ili uklanjanje administratora aktivnih uređaja. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string> @@ -688,7 +692,7 @@ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promjena kalibracije uređaja za unos"</string> <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Omogućuje aplikaciji izmjenu parametara kalibracije dodirnog zaslona. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string> <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"pristup DRM certifikatima"</string> - <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogućuje pružanje i korištenje DRM certifikata. Nikad ne bi trebalo biti potrebno za uobičajene aplikacije."</string> + <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogućuje pružanje i korištenje DRM certifikata. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 4932e88..41a1fb9 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string> @@ -688,7 +692,7 @@ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"beviteli eszköz kalibrációjának módosítása"</string> <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lehetővé teszi, hogy az alkalmazás módosítsa az érintőképernyő kalibrációs paramétereit. A normál alkalmazásoknál erre elvileg soha nincs szükség."</string> <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM-tanúsítványokhoz való hozzáférés"</string> - <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Engedélyezi egy alkalmazás számára a DRM-tanúsítványokhoz való hozzáférést és azok használatát. Átlagos alkalmazásoknak erre nem lehet szüksége."</string> + <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Engedélyezi egy alkalmazás számára a DRM-tanúsítványokhoz való hozzáférést és azok használatát. Átlagos alkalmazásoknak erre nem lehet szükségük."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 805f77b..d2f7c13 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Թույլ է տալիս սեփականատիրոջը ուղարկել մտադրություններ սարքի կառավարչին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ավելացնել կամ հեռացնել սարքի արդմինիստրատոր"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Թույլ է տալիս սեփականատիրոջը ավելացնել կամ հեռացնել սարքի ակտիվ ադմինիստրատորներ: Երբեք չպետք է անհրաժեշտ լինի սովորական ծրագրերին:"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"փոխել էկրանի դիրքավորումը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index e161466..b1d94e6 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"menambah atau menghapus admin perangkat"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Memungkinkan pemegang menambahkan atau menghapus administrator perangkat aktif. Tidak pernah dibutuhkan oleh aplikasi normal."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 740075f..27b05d1 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"aggiungere o rimuovere un amministratore del dispositivo"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Consente al titolare di aggiungere o rimuovere gli amministratori attivi del dispositivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 61754c3..222dfe3 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"הוספה או הסרה של מנהלי מכשיר"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"מאפשרת לבעלים להוסיף או להסיר מנהלי מכשיר פעילים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 62ee883..d1e1308 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"端末の管理者の追加または削除"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"有効な端末の管理者を追加または削除することを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index 4855f27..9ea2503 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"აპს შეეძლება მოწყობილობის ადმინისტრატორისთვის intent ობიექტების გაგზავნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"მოწყობილობის ადმინისტრატორს დამატება ან ამოშლა"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"საშუალებას აძლევს მფლობელს დაამატოს ან ამოშალოს მოწყობილობის აქტიური ადმინისტრატორები. ჩვეულებრივ აპებს, ალბათ, არასოდეს დაჭირდება"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ეკრანის ორიენტაციის შეცვლა"</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 73769fb..8dbd6ac 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មធាតុក្រាហ្វិក។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទងជាមួយអ្នកគ្រប់គ្រងឧបករណ៍"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យម្ចាស់ផ្ញើគោលបំណងទៅអ្នកគ្រប់គ្រងឧបករណ៍។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម ឬលុបកម្មវិធីគ្រប់គ្រងឧបករណ៍"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"អនុញ្ញាតឲ្យម្ចាស់បន្ថែម ឬលុបកម្មវិធីគ្រប់គ្រងឧបករណ៍សកម្មចេញ។ មិនគួរប្រើសម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ប្ដូរទិសអេក្រង់"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index bb26d4f..a389466 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"기기 관리자 추가 또는 삭제"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"권한을 가진 프로그램이 활성화된 기기의 관리자를 추가 또는 삭제하도록 합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 60b7da4..79b8a33 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສົ່ງເຈດຕະນາຫາຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ເພີ່ມ ຫຼືລຶບຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດລຶບ ຫຼືລຶບຂໍ້ມູນອຸປະກອນທີ່ນຳໃຊ້ໄດ້. ແອັບຯທົ່ວໄປບໍ່ຈຳເປັນຕ້ອງໃຊ້."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ປ່ຽນລວງຂອງໜ້າຈໍ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index b40e10b..99184d2 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridėti arba pašalinti įrenginio administratorių"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Savininkui leidžiama pridėti aktyvių įrenginio administratorių arba juos pašalinti. Neturėtų reikėti įprastoms programoms."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 6b91a6d..433115c 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pievienot vai noņemt ierīces administratoru"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ļauj īpašniekam pievienot vai noņemt aktīvos ierīces administratorus. Nekad nav nepieciešama parastām lietotnēm."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index ea1baa1..442b856 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Эзэмшигч нь төхөөрөмжийн админруу интент илгээх боломжтой. Энгийн апп-д шаардлагагүй."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"төхөөрөмжийн админ нэмэх, хасах"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Эзэмшигч нь идэвхтэй төхөөрөмжийн администраторыг нэмэх, хасах боломжтой. Энгийн апп-д шаардлагагүй."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"дэлгэцний чиглэлийг солих"</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index 219e47b..27c413d 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tambah atau alih keluar pentadbir peranti"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Membenarkan pemegang menambah atau mengalih keluar pentadbir peranti aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 593d260..a6d186f 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string> @@ -688,7 +692,7 @@ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"endre kalibreringen av inndataenheter"</string> <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lar appen endre kalibrasjonsparametrene for berøringsskjermen. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string> <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"tilgang til DRM-sertifikater"</string> - <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Lar en app klargjøre og bruke DRM-sertifikater. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string> + <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillater at en app klargjøre og bruke DRM-sertifikater. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 9225c23..9014f5a 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"een apparaatbeheerder toevoegen of verwijderen"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Hiermee kan de rechtenhouder actieve apparaatbeheerders toevoegen of verwijderen. Nooit vereist voor normale apps."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 931c24c..b08e236 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodaj lub usuń administratora urządzenia"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umożliwia właścicielowi dodawanie i usuwanie aktywnych administratorów urządzenia. Ta opcja nie jest wykorzystywana w przypadku standardowych aplikacji."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 9eb7512..379e3dd 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador de dispositivos"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o titular adicione ou remova administradores de dispositivos ativos. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index fd75660..7feb69b 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para aplicativos normais."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador do dispositivo"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o proprietário adicione ou remova administradores do dispositivo ativos. Não deve ser necessário para aplicativos comuns."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string> diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml index 4e9806b..7fc7436 100644 --- a/core/res/res/values-rm/strings.xml +++ b/core/res/res/values-rm/strings.xml @@ -601,6 +601,10 @@ <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string> <!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) --> <skip /> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) --> <skip /> <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) --> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index a8a75a5..2dfc1870 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adăugarea sau eliminarea unui administrator de dispozitiv"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite proprietarului să adauge sau să elimine administratorii activi ai dispozitivului. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string> @@ -687,7 +691,7 @@ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_setInputCalibration" msgid="4902620118878467615">"schimbați calibrarea dispozitivului de intrare"</string> <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite aplicației să modifice parametrii de calibrare a ecranului tactil. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> - <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesați certificatele DRM"</string> + <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesează certificatele DRM"</string> <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite unei aplicații să furnizeze și să utilizeze certificate DRM. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index d142e9a..7f07d6d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Добавление/удаление администратора устройства"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Владелец сможет добавлять и удалять администраторов устройства (используется лишь в некоторых приложениях)."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"Изменение ориентации экрана"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 707bdf1..aa467bb 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridanie alebo odstránenie správcu zariadenia"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umožňuje držiteľovi pridať alebo odstrániť správcov aktívnych zariadení. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index e93b128..808026c 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodajanje ali odstranjevanje skrbnikov naprave"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Imetniku omogoča, da doda ali odstrani aktivne skrbnike naprave. Normalne aplikacije tega načeloma ne potrebujejo."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index b2928e4..0fed1e3 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавање или уклањање администратора уређаја"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозвољава власнику да додаје или уклања активне администраторе уређаја. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index b134a85..5afc0cd 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lägga till eller ta bort en enhetsadministratör"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Innehavaren får lägga till eller ta bort aktiva enhetsadministratörer. Detta ska normalt inte behövas för vanliga appar."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 8f319f3..9885014 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ongeza au ondoa msimamizi wa kifaa"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Inaruhusu mmiliki kuongeza au kuondoa wasimamizi wa kifaa waliopo. Kamwe kisihitajike kwa ajili ya programu za kawaida."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"badilisha uelekezo wa skrini"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index ecb3a58..ee35eae 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"เพิ่มหรือลบผู้ดูแลระบบอุปกรณ์"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"อนุญาตให้เจ้าของเพิ่มหรือลบผู้ดูแลระบบอุปกรณ์ที่ใช้งาน ไม่ควรต้องใช้สำหรับแอปปกติ"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 0a5e64c..ba7033e 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"magdagdag o mag-alis ng admin ng device"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Pinapayagan ang may-ari na magdagdag o mag-alis ng mga aktibong administrator ng device. Hindi dapat kailanganin kailanman para sa normal na apps."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 72e149f..e78e291 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"cihaz yöneticisi ekle veya kaldır"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"İzin sahibine, etkin cihaz yöneticileri ekleyip kaldırma izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 563d5ee..e31392e 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 8c424c3..ea0ef68 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"thêm hoặc xóa quản trị viên thiết bị"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Cho phép chủ sở hữu thêm hoặc xóa quản trị viên thiết bị đang hoạt động. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index acb4a81..73f2b8d 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许用户将意向发送给设备管理员。普通应用绝不需要此权限。"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"添加或删除设备管理员"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允许应用添加或删除有效的设备管理员。普通应用绝不需要此权限。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index deb5a11..fa499d9 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (不建議一般應用程式使用)。"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (不建議一般應用程式使用)。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕瀏覽方向"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index b058860..6bf2593 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (一般應用程式並不需要)。"</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index aacd3c1..1359dd9 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -384,6 +384,10 @@ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string> + <!-- no translation found for permlab_bindTvInput (5601264742478168987) --> + <skip /> + <!-- no translation found for permdesc_bindTvInput (2371008331852001924) --> + <skip /> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> <string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 46cb9b2..f364bd0 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -245,6 +245,8 @@ <!-- The preferred TextAppearance for the primary text of list items. --> <attr name="textAppearanceListItem" format="reference" /> + <!-- The preferred TextAppearance for the secondary text of list items. --> + <attr name="textAppearanceListItemSecondary" format="reference" /> <!-- The preferred TextAppearance for the primary text of small list items. --> <attr name="textAppearanceListItemSmall" format="reference" /> @@ -4409,14 +4411,23 @@ <!-- When a tint color is set, specifies its Porter-Duff blending mode. The default value is src_in, which treats the drawable as an alpha mask. --> <attr name="tintMode"> - <!-- [Sa * Da, Sc * Da] --> - <enum name="src_in" value="0" /> - <!-- [Da, Sc * Da + (1 - Sa) * Dc] --> - <enum name="src_atop" value="1" /> - <!-- [Sa * Da, Sc * Dc] --> - <enum name="multiply" value="2" /> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> - <enum name="screen" value="3" /> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> </attr> </declare-styleable> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index fbe066a..d5e78a5 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1370,7 +1370,7 @@ </string-array> <string-array name="config_notificationScorers"> - <item>com.android.internal.notification.DemoContactNotificationScorer</item> + <item>com.android.internal.notification.PeopleNotificationScorer</item> </string-array> <!-- Flag indicating that this device does not rotate and will always remain in its default diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index acdf926..d3bee28 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2148,6 +2148,7 @@ <public type="attr" name="subtitleTextAppearance" /> <public type="attr" name="slideEdge" /> <public type="attr" name="actionBarTheme" /> + <public type="attr" name="textAppearanceListItemSecondary" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 4a121d1..6266393 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -830,6 +830,20 @@ user consent.</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_retrieveWindowToken">retrieve window token</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_retrieveWindowToken">Allows an application to retrieve + the window token. Malicious apps may perfrom unauthorized interaction with + the application window impersonating the system.</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_frameStats">retrieve frame statistics</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_frameStats">Allows an application to collect + frame statistics. Malicious apps may observe the frame statistics + of windows from other apps.</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_filter_events">filter events</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_filter_events">Allows an application to register an input filter diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml index dd148c4..2720d61 100644 --- a/core/res/res/values/styles_quantum.xml +++ b/core/res/res/values/styles_quantum.xml @@ -33,7 +33,7 @@ please see styles_device_defaults.xml. <eat-comment/> <style name="Preference.Quantum"> - <item name="layout">@layout/preference_holo</item> + <item name="layout">@layout/preference_quantum</item> </style> <style name="PreferenceFragment.Quantum"> @@ -42,13 +42,13 @@ please see styles_device_defaults.xml. </style> <style name="Preference.Quantum.Information"> - <item name="layout">@layout/preference_information_holo</item> + <item name="layout">@layout/preference_information_quantum</item> <item name="enabled">false</item> <item name="shouldDisableView">false</item> </style> <style name="Preference.Quantum.Category"> - <item name="layout">@layout/preference_category_holo</item> + <item name="layout">@layout/preference_category_quantum</item> <!-- The title should not dim if the category is disabled, instead only the preference children should dim. --> <item name="shouldDisableView">false</item> <item name="selectable">false</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b011483..ac6c15d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1835,5 +1835,6 @@ <java-symbol type="attr" name="titleTextAppearance" /> <java-symbol type="attr" name="subtitleTextAppearance" /> <java-symbol type="drawable" name="ic_lock_bugreport" /> + <java-symbol type="id" name="icon_frame" /> </resources> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 7aea814..6f9e55b 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -126,6 +126,7 @@ please see themes_device_defaults.xml. <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeight</item> <item name="textAppearanceListItem">?android:attr/textAppearanceLarge</item> <item name="textAppearanceListItemSmall">?android:attr/textAppearanceLarge</item> + <item name="textAppearanceListItemSecondary">?android:attr/textAppearanceSmall</item> <item name="listPreferredItemPaddingLeft">6dip</item> <item name="listPreferredItemPaddingRight">6dip</item> <item name="listPreferredItemPaddingStart">6dip</item> @@ -349,6 +350,7 @@ please see themes_device_defaults.xml. <item name="actionMenuTextAppearance">@android:style/TextAppearance.Holo.Widget.ActionBar.Menu</item> <item name="actionMenuTextColor">?android:attr/textColorPrimary</item> <item name="actionBarWidgetTheme">@null</item> + <item name="actionBarTheme">@null</item> <item name="actionBarDivider">?android:attr/dividerVertical</item> <item name="actionBarItemBackground">?android:attr/selectableItemBackground</item> @@ -701,6 +703,7 @@ please see themes_device_defaults.xml. <item name="itemTextAppearance">@android:style/TextAppearance.Large.Inverse</item> <item name="textAppearanceListItem">@android:style/TextAppearance.Large.Inverse</item> <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item> + <item name="textAppearanceListItemSecondary">@android:style/TextAppearance.Small.Inverse</item> </style> <!-- Default heme for the TimePicker dialog windows, which is used by the @@ -1006,6 +1009,7 @@ please see themes_device_defaults.xml. <item name="listPreferredItemHeightLarge">80dip</item> <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item> <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item> + <item name="textAppearanceListItemSecondary">?android:attr/textAppearanceSmall</item> <item name="listPreferredItemPaddingLeft">8dip</item> <item name="listPreferredItemPaddingRight">8dip</item> <item name="listPreferredItemPaddingStart">8dip</item> @@ -1194,6 +1198,7 @@ please see themes_device_defaults.xml. <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.PopupWindow.ActionMode</item> <item name="actionBarWidgetTheme">@null</item> + <item name="actionBarTheme">@null</item> <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item> <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_dark</item> @@ -1335,6 +1340,7 @@ please see themes_device_defaults.xml. <item name="listPreferredItemHeightLarge">80dip</item> <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item> <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item> + <item name="textAppearanceListItemSecondary">?android:attr/textAppearanceSmall</item> <item name="listPreferredItemPaddingLeft">8dip</item> <item name="listPreferredItemPaddingRight">8dip</item> <item name="listPreferredItemPaddingStart">8dip</item> @@ -1526,6 +1532,7 @@ please see themes_device_defaults.xml. <item name="actionBarSize">@dimen/action_bar_default_height</item> <item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item> <item name="actionBarWidgetTheme">@null</item> + <item name="actionBarTheme">@null</item> <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item> <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_light</item> @@ -1585,6 +1592,7 @@ please see themes_device_defaults.xml. <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item> <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse</item> <item name="actionBarWidgetTheme">@android:style/Theme.Holo</item> + <item name="actionBarTheme">@null</item> <item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown.ActionBar</item> <item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item> diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml index b5ac8fa..9e235d6 100644 --- a/core/res/res/values/themes_quantum.xml +++ b/core/res/res/values/themes_quantum.xml @@ -109,11 +109,13 @@ please see themes_device_defaults.xml. <item name="listPreferredItemHeightSmall">48dip</item> <item name="listPreferredItemHeightLarge">80dip</item> <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item> - <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item> - <item name="listPreferredItemPaddingLeft">8dip</item> - <item name="listPreferredItemPaddingRight">8dip</item> - <item name="listPreferredItemPaddingStart">8dip</item> - <item name="listPreferredItemPaddingEnd">8dip</item> + <item name="textAppearanceListItem">@style/TextAppearance.Quantum.Subhead</item> + <item name="textAppearanceListItemSmall">@style/TextAppearance.Quantum.Subhead</item> + <item name="textAppearanceListItemSecondary">@style/TextAppearance.Quantum.Body1</item> + <item name="listPreferredItemPaddingLeft">16dip</item> + <item name="listPreferredItemPaddingRight">16dip</item> + <item name="listPreferredItemPaddingStart">16dip</item> + <item name="listPreferredItemPaddingEnd">16dip</item> <!-- @hide --> <item name="searchResultListItemHeight">58dip</item> @@ -269,6 +271,7 @@ please see themes_device_defaults.xml. <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item> <item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item> + <item name="preferenceFragmentPaddingSide">0dip</item> <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item> <item name="preferenceStyle">@style/Preference.Quantum</item> <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item> @@ -278,7 +281,7 @@ please see themes_device_defaults.xml. <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item> <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item> <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item> - <item name="preferenceLayoutChild">@layout/preference_child_holo</item> + <item name="preferenceLayoutChild">@layout/preference_child_quantum</item> <item name="detailsElementBackground">?attr/colorBackground</item> <!-- Search widget styles --> @@ -442,11 +445,13 @@ please see themes_device_defaults.xml. <item name="listPreferredItemHeightSmall">48dip</item> <item name="listPreferredItemHeightLarge">80dip</item> <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item> - <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item> - <item name="listPreferredItemPaddingLeft">8dip</item> - <item name="listPreferredItemPaddingRight">8dip</item> - <item name="listPreferredItemPaddingStart">8dip</item> - <item name="listPreferredItemPaddingEnd">8dip</item> + <item name="textAppearanceListItem">@style/TextAppearance.Quantum.Subhead</item> + <item name="textAppearanceListItemSmall">@style/TextAppearance.Quantum.Subhead</item> + <item name="textAppearanceListItemSecondary">@style/TextAppearance.Quantum.Body1</item> + <item name="listPreferredItemPaddingLeft">16dip</item> + <item name="listPreferredItemPaddingRight">16dip</item> + <item name="listPreferredItemPaddingStart">16dip</item> + <item name="listPreferredItemPaddingEnd">16dip</item> <!-- @hide --> <item name="searchResultListItemHeight">58dip</item> @@ -601,6 +606,7 @@ please see themes_device_defaults.xml. <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item> <item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item> + <item name="preferenceFragmentPaddingSide">0dip</item> <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item> <item name="preferenceStyle">@style/Preference.Quantum</item> <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item> @@ -610,7 +616,7 @@ please see themes_device_defaults.xml. <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item> <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item> <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item> - <item name="preferenceLayoutChild">@layout/preference_child_holo</item> + <item name="preferenceLayoutChild">@layout/preference_child_quantum</item> <item name="detailsElementBackground">?attr/colorBackground</item> <!-- PreferenceFrameLayout attributes --> @@ -706,6 +712,7 @@ please see themes_device_defaults.xml. with an inverse color profile. The dark action bar sharply stands out against the light content. --> <style name="Theme.Quantum.Light.DarkActionBar"> + <item name="actionBarWidgetTheme">@null</item> <item name="actionBarTheme">@style/Theme.Quantum</item> </style> diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 19131f2..66a88a2 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -595,7 +595,6 @@ public class BitmapDrawable extends Drawable { * Specifies the blending mode used to apply tint. * * @param tintMode A Porter-Duff blending mode - * @hide Pending finalization of supported Modes */ public void setTintMode(Mode tintMode) { if (mBitmapState.mTintMode != tintMode) { @@ -606,10 +605,7 @@ public class BitmapDrawable extends Drawable { } /** - * Returns the tint mode for this drawable, or {@code null} if none set. - * - * @return the tint mode for this drawable, or {@code null} if none set - * @hide + * @hide only needed by a hack within ProgressBar */ public Mode getTintMode() { return mBitmapState.mTintMode; diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 077db7a..21cd5db 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -1248,16 +1248,14 @@ public abstract class Drawable { */ static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) { switch (value) { - case 0: - return Mode.SRC_IN; - case 1: - return Mode.SRC_ATOP; - case 2: - return Mode.MULTIPLY; - case 3: - return Mode.SCREEN; + case 3: return Mode.SRC_OVER; + case 5: return Mode.SRC_IN; + case 9: return Mode.SRC_ATOP; + case 14: return Mode.MULTIPLY; + case 15: return Mode.SCREEN; + case 16: return Mode.ADD; + default: return defaultMode; } - return defaultMode; } } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 66193a5..3e9ca0a 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -345,7 +345,6 @@ public class NinePatchDrawable extends Drawable { * Specifies the blending mode used to apply tint. * * @param tintMode A Porter-Duff blending mode - * @hide Pending finalization of supported Modes */ public void setTintMode(Mode tintMode) { if (mNinePatchState.mTintMode != tintMode) { diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index 3323a25..2810c43 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -124,6 +124,41 @@ public class TouchFeedbackDrawable extends LayerDrawable { return super.isStateful() || mState.mTint != null && mState.mTint.isStateful(); } + /** + * Specifies a tint for drawing touch feedback ripples. + * + * @param tint Color state list to use for tinting touch feedback ripples, + * or null to clear the tint + */ + public void setTint(ColorStateList tint) { + if (mState.mTint != tint) { + mState.mTint = tint; + invalidateSelf(); + } + } + + /** + * Returns the tint color for touch feedback ripples. + * + * @return Color state list to use for tinting touch feedback ripples, or + * null if none set + */ + public ColorStateList getTint() { + return mState.mTint; + } + + /** + * Specifies the blending mode used to draw touch feedback ripples. + * + * @param tintMode A Porter-Duff blending mode + */ + public void setTintMode(Mode tintMode) { + if (mState.mTintMode != tintMode) { + mState.mTintMode = tintMode; + invalidateSelf(); + } + } + @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index 6c0b722..3e68574 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -17,8 +17,8 @@ package android.graphics.drawable; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.Resources.Theme; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Matrix; @@ -47,6 +47,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; + /** * This lets you create a drawable based on an XML vector graphic * It can be defined in an XML file with the <code><vector></code> element. @@ -172,7 +173,8 @@ public class VectorDrawable extends Drawable { private static final int DEFAULT_DURATION = 1000; private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000; - private VectorDrawableState mVectorState; + private final VectorDrawableState mVectorState; + private int mAlpha = 0xFF; public VectorDrawable() { @@ -282,14 +284,17 @@ public class VectorDrawable extends Drawable { @Override protected boolean onStateChange(int[] state) { + super.onStateChange(state); + mVectorState.mVAnimatedPath.setState(state); - int direction = mVectorState.mVAnimatedPath.getTrigger(state); - if (direction>0) { + + final int direction = mVectorState.mVAnimatedPath.getTrigger(state); + if (direction > 0) { animateForward(); - } else if (direction<0) { + } else if (direction < 0) { animateBackward(); } - super.onStateChange(state); + invalidateSelf(); return true; } @@ -310,7 +315,11 @@ public class VectorDrawable extends Drawable { @Override public void draw(Canvas canvas) { - mVectorState.mVAnimatedPath.draw(canvas); + final int saveCount = canvas.save(); + final Rect bounds = getBounds(); + canvas.translate(bounds.left, bounds.top); + mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height()); + canvas.restoreToCount(saveCount); } @Override @@ -327,10 +336,6 @@ public class VectorDrawable extends Drawable { // TODO: support color filter } - /** - * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} - * value of TRANSLUCENT. - */ @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; @@ -364,38 +369,14 @@ public class VectorDrawable extends Drawable { invalidateSelf(); } - /** - * Sets the intrinsic (default) width for this shape. - * - * @param width the intrinsic width (in pixels) - */ - public void setIntrinsicWidth(int width) { - if (mVectorState.mIntrinsicWidth != width) { - mVectorState.mIntrinsicWidth = width; - invalidateSelf(); - } - } - - /** - * Sets the intrinsic (default) height for this shape. - * - * @param height the intrinsic height (in pixels) - */ - public void setIntrinsicHeight(int height) { - if (mVectorState.mIntrinsicHeight != height) { - mVectorState.mIntrinsicHeight = height; - invalidateSelf(); - } - } - @Override public int getIntrinsicWidth() { - return mVectorState.mIntrinsicWidth; + return (int) mVectorState.mVAnimatedPath.mBaseWidth; } @Override public int getIntrinsicHeight() { - return mVectorState.mIntrinsicHeight; + return (int) mVectorState.mVAnimatedPath.mBaseHeight; } @Override @@ -408,25 +389,6 @@ public class VectorDrawable extends Drawable { } } - /** @hide */ - public static VectorDrawable create(Resources resources, int rid) { - try { - VectorDrawable drawable = new VectorDrawable(); - XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); - factory.setNamespaceAware(true); - XmlPullParser xpp = resources.getXml(rid); - AttributeSet attrs = Xml.asAttributeSet(xpp); - drawable.inflate(resources, xpp, attrs); - drawable.setAnimationFraction(0); - return drawable; - } catch (XmlPullParserException e) { - Log.e(LOGTAG, "parser error", e); - } catch (IOException e) { - Log.e(LOGTAG, "parser error", e); - } - return null; - } - @Override public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { @@ -450,6 +412,27 @@ public class VectorDrawable extends Drawable { } } + /** @hide */ + public static VectorDrawable create(Resources resources, int rid) { + try { + final XmlPullParser xpp = resources.getXml(rid); + final AttributeSet attrs = Xml.asAttributeSet(xpp); + final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + factory.setNamespaceAware(true); + + final VectorDrawable drawable = new VectorDrawable(); + drawable.inflate(resources, xpp, attrs); + drawable.setAnimationFraction(0); + + return drawable; + } catch (XmlPullParserException e) { + Log.e(LOGTAG, "parser error", e); + } catch (IOException e) { + Log.e(LOGTAG, "parser error", e); + } + return null; + } + private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { final VAnimatedPath animatedPath = new VAnimatedPath(); @@ -543,9 +526,6 @@ public class VectorDrawable extends Drawable { private void setAnimatedPath(VAnimatedPath animatedPath) { mVectorState.mVAnimatedPath = animatedPath; - setIntrinsicWidth((int) mVectorState.mVAnimatedPath.mBaseWidth); - setIntrinsicHeight((int) mVectorState.mVAnimatedPath.mBaseHeight); - long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration(); if (duration == -1) { // if it set to infinite set to 1 hour duration = DEFAULT_INFINITE_DURATION; // TODO define correct approach for infinite @@ -575,18 +555,12 @@ public class VectorDrawable extends Drawable { ValueAnimator mBasicAnimator; VAnimatedPath mVAnimatedPath; Rect mPadding; - int mIntrinsicHeight; - int mIntrinsicWidth; public VectorDrawableState(VectorDrawableState copy) { if (copy != null) { mChangingConfigurations = copy.mChangingConfigurations; mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath); mPadding = new Rect(copy.mPadding); - mIntrinsicHeight = copy.mIntrinsicHeight; - mIntrinsicWidth = copy.mIntrinsicWidth; - } else { - mVAnimatedPath = new VAnimatedPath(); } } @@ -612,17 +586,31 @@ public class VectorDrawable extends Drawable { } private static class VAnimatedPath { - private ArrayList<VAnimation> mCurrentAnimList = null; + private static final int [] TRIGGER_MAP = { + 0, + R.attr.state_pressed, + R.attr.state_focused, + R.attr.state_hovered, + R.attr.state_selected, + R.attr.state_checkable, + R.attr.state_checked, + R.attr.state_activated, + R.attr.state_focused + }; + + private final Path mPath = new Path(); + private final Path mRenderPath = new Path(); + private final Matrix mMatrix = new Matrix(); + + private ArrayList<VAnimation> mCurrentAnimList; private VPath[] mCurrentPaths; - private float mAnimationValue = 0; // value goes from 0 to 1 - private Paint mStrokePaint = null; - private Paint mFillPaint = null; + private Paint mStrokePaint; + private Paint mFillPaint; private PathMeasure mPathMeasure; - private Path mPath = new Path(); - private Path mRenderPath = new Path(); - private Matrix mMatrix = new Matrix(); - private long mTotalDuration; + private int[] mCurrentState = new int[0]; + private float mAnimationValue; + private long mTotalDuration; private int mTrigger; private boolean mTriggerState; @@ -634,11 +622,9 @@ public class VectorDrawable extends Drawable { float mViewportHeight; public VAnimatedPath() { - setup(); } public VAnimatedPath(VAnimatedPath copy) { - setup(); mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList); mGroupList.addAll(copy.mGroupList); if (copy.mCurrentPaths != null) { @@ -703,28 +689,7 @@ public class VectorDrawable extends Drawable { } public void setTrigger(int trigger){ - final int [] lut = { - 0, - R.attr.state_pressed, - R.attr.state_focused, - R.attr.state_hovered, - R.attr.state_selected, - R.attr.state_checkable, - R.attr.state_checked, - R.attr.state_activated, - R.attr.state_focused - }; - - mTrigger = lut[trigger]; - } - - private void setup(){ - mStrokePaint = new Paint(); - mStrokePaint.setStyle(Paint.Style.STROKE); - mStrokePaint.setAntiAlias(true); - mFillPaint = new Paint(); - mFillPaint.setStyle(Paint.Style.FILL); - mFillPaint.setAntiAlias(true); + mTrigger = VAnimatedPath.getStateForTrigger(trigger); } public long getTotalAnimationDuration() { @@ -780,16 +745,12 @@ public class VectorDrawable extends Drawable { } } - public void draw(Canvas canvas) { + public void draw(Canvas canvas, int w, int h) { if (mCurrentPaths == null) { Log.e(LOGTAG,"mCurrentPaths == null"); return; } - // TODO: This should probably use getBounds(). - final int w = canvas.getWidth(); - final int h = canvas.getHeight(); - for (int i = 0; i < mCurrentPaths.length; i++) { if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) { drawPath(mCurrentPaths[i], canvas, w, h); @@ -801,7 +762,7 @@ public class VectorDrawable extends Drawable { final float scale = Math.min(h / mViewportHeight, w / mViewportWidth); vPath.toPath(mPath); - Path path = mPath; + final Path path = mPath; if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) { float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f; @@ -839,24 +800,36 @@ public class VectorDrawable extends Drawable { } if (vPath.mFillColor != 0) { + if (mFillPaint == null) { + mFillPaint = new Paint(); + mFillPaint.setStyle(Paint.Style.FILL); + mFillPaint.setAntiAlias(true); + } + mFillPaint.setColor(vPath.mFillColor); - int alpha = 0xFF & (vPath.mFillColor >> 24); - mFillPaint.setAlpha(alpha); canvas.drawPath(mRenderPath, mFillPaint); } if (vPath.mStrokeColor != 0) { + if (mStrokePaint == null) { + mStrokePaint = new Paint(); + mStrokePaint.setStyle(Paint.Style.STROKE); + mStrokePaint.setAntiAlias(true); + } + + final Paint strokePaint = mStrokePaint; if (vPath.mStrokeLineJoin != null) { - mStrokePaint.setStrokeJoin(vPath.mStrokeLineJoin); + strokePaint.setStrokeJoin(vPath.mStrokeLineJoin); } + if (vPath.mStrokeLineCap != null) { - mStrokePaint.setStrokeCap(vPath.mStrokeLineCap); + strokePaint.setStrokeCap(vPath.mStrokeLineCap); } - mStrokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); - mStrokePaint.setColor(vPath.mStrokeColor); - mStrokePaint.setAlpha(0xFF & (vPath.mStrokeColor >> 24)); - mStrokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); - canvas.drawPath(mRenderPath, mStrokePaint); + + strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale); + strokePaint.setColor(vPath.mStrokeColor); + strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale); + canvas.drawPath(mRenderPath, strokePaint); } } @@ -926,7 +899,7 @@ public class VectorDrawable extends Drawable { private void parseViewport(Resources r, AttributeSet attrs) throws XmlPullParserException { - TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); + final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport); mViewportWidth = a.getFloat(R.styleable.VectorDrawableViewport_viewportWidth, 0); mViewportHeight = a.getFloat(R.styleable.VectorDrawableViewport_viewportHeight, 0); if (mViewportWidth == 0 || mViewportHeight == 0) { @@ -938,7 +911,7 @@ public class VectorDrawable extends Drawable { private void parseSize(Resources r, AttributeSet attrs) throws XmlPullParserException { - TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); + final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableSize); mBaseWidth = a.getDimension(R.styleable.VectorDrawableSize_width, 0); mBaseHeight = a.getDimension(R.styleable.VectorDrawableSize_height, 0); if (mBaseWidth == 0 || mBaseHeight == 0) { @@ -947,6 +920,10 @@ public class VectorDrawable extends Drawable { } a.recycle(); } + + private static final int getStateForTrigger(int trigger) { + return TRIGGER_MAP[trigger]; + } } private static class VAnimation { @@ -1324,8 +1301,8 @@ public class VectorDrawable extends Drawable { boolean mAnimated = false; boolean mClip = false; - Paint.Cap mStrokeLineCap = null; - Paint.Join mStrokeLineJoin = null; + Paint.Cap mStrokeLineCap = Paint.Cap.BUTT; + Paint.Join mStrokeLineJoin = Paint.Join.MITER; float mStrokeMiterlimit = 4; private VNode[] mNode = null; @@ -1775,32 +1752,29 @@ public class VectorDrawable extends Drawable { return returnPath; } - private static int rgbInterpolate(float t, int color1, int color2) { - int ret; - if (color1 == color2) { - return color2; - } - if (color1 == 0) { - return color2; - } - if (color2 == 0) { - return color1; + private static int rgbInterpolate(float fraction, int startColor, int endColor) { + if (startColor == endColor) { + return startColor; + } else if (startColor == 0) { + return endColor; + } else if (endColor == 0) { + return startColor; } - float t1 = 1 - t; - ret = 0xFF & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t))); - color1 >>= 8; - color2 >>= 8; + final int startA = (startColor >> 24) & 0xff; + final int startR = (startColor >> 16) & 0xff; + final int startG = (startColor >> 8) & 0xff; + final int startB = startColor & 0xff; - ret |= 0xFF00 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 8); - color1 >>= 8; - color2 >>= 8; - ret |= 0xFF0000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 16); - color1 >>= 8; - color2 >>= 8; - ret |= 0xFF000000 & (((int) ((color1 & 0xFF) * t1 + (color2 & 0xFF) * t)) << 24); + final int endA = (endColor >> 24) & 0xff; + final int endR = (endColor >> 16) & 0xff; + final int endG = (endColor >> 8) & 0xff; + final int endB = endColor & 0xff; - return ret; + return ((startA + (int)(fraction * (endA - startA))) << 24) | + ((startR + (int)(fraction * (endR - startR))) << 16) | + ((startG + (int)(fraction * (endG - startG))) << 8) | + ((startB + (int)(fraction * (endB - startB)))); } public boolean isVisible(int[] state) { @@ -1852,27 +1826,25 @@ public class VectorDrawable extends Drawable { } } - private void nodeListToPath(VNode[] node, Path path) { - float[] current = new float[4]; - for (int i = 0; i < node.length; i++) { - addCommand(path, current, node[i].mType, node[i].mParams); - } - } - public static void createPath(VNode[] node, Path path) { float[] current = new float[4]; + char previousCommand = 'm'; for (int i = 0; i < node.length; i++) { - addCommand(path, current, node[i].mType, node[i].mParams); + addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); + previousCommand = node[i].mType; } } - private static void addCommand(Path path, float[] current, char cmd, float[] val) { + private static void addCommand(Path path, float[] current, + char previousCmd, char cmd, float[] val) { int incr = 2; float currentX = current[0]; float currentY = current[1]; float ctrlPointX = current[2]; float ctrlPointY = current[3]; + float reflectiveCtrlPointX; + float reflectiveCtrlPointY; switch (cmd) { case 'z': @@ -1952,12 +1924,8 @@ public class VectorDrawable extends Drawable { currentY = val[k + 0]; break; case 'c': // curveto - Draws a cubic Bézier curve (relative) - path.rCubicTo(val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3], - val[k + 4], - val[k + 5]); + path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], + val[k + 4], val[k + 5]); ctrlPointX = currentX + val[k + 2]; ctrlPointY = currentY + val[k + 3]; @@ -1966,20 +1934,22 @@ public class VectorDrawable extends Drawable { break; case 'C': // curveto - Draws a cubic Bézier curve - path.cubicTo(val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3], - val[k + 4], - val[k + 5]); + path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], + val[k + 4], val[k + 5]); currentX = val[k + 4]; currentY = val[k + 5]; ctrlPointX = val[k + 2]; ctrlPointY = val[k + 3]; - break; case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) - path.rCubicTo(currentX - ctrlPointX, currentY - ctrlPointY, + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'c' || previousCmd == 's' + || previousCmd == 'C' || previousCmd == 'S') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, val[k + 0], val[k + 1], val[k + 2], val[k + 3]); @@ -1989,47 +1959,63 @@ public class VectorDrawable extends Drawable { currentY += val[k + 3]; break; case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) - path.cubicTo(2 * currentX - ctrlPointX, - 2 * currentY - ctrlPointY, - val[k + 0], - val[k + 1], - val[k + 2], - val[k + 3]); - currentX = val[k + 2]; - currentY = val[k + 3]; + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'c' || previousCmd == 's' + || previousCmd == 'C' || previousCmd == 'S') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, + val[k + 0], val[k + 1], val[k + 2], val[k + 3]); ctrlPointX = val[k + 0]; ctrlPointY = val[k + 1]; + currentX = val[k + 2]; + currentY = val[k + 3]; break; case 'q': // Draws a quadratic Bézier (relative) path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); + ctrlPointX = currentX + val[k + 0]; + ctrlPointY = currentY + val[k + 1]; currentX += val[k + 2]; currentY += val[k + 3]; - ctrlPointX = val[k + 0]; - ctrlPointY = val[k + 1]; break; case 'Q': // Draws a quadratic Bézier path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); - currentX = val[k + 2]; - currentY = val[k + 3]; ctrlPointX = val[k + 0]; ctrlPointY = val[k + 1]; + currentX = val[k + 2]; + currentY = val[k + 3]; break; case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) - path.rQuadTo(currentX - ctrlPointX, currentY - ctrlPointY, + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'q' || previousCmd == 't' + || previousCmd == 'Q' || previousCmd == 'T') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, val[k + 0], val[k + 1]); - ctrlPointX = ctrlPointX + currentX; - ctrlPointY = ctrlPointY + currentY; + ctrlPointX = reflectiveCtrlPointX; + ctrlPointY = reflectiveCtrlPointY; currentX += val[k + 0]; currentY += val[k + 1]; - break; case 'T': // Draws a quadratic Bézier curve (reflective control point) - path.quadTo(currentX * 2 - ctrlPointX, currentY * 2 - ctrlPointY, + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'q' || previousCmd == 't' + || previousCmd == 'Q' || previousCmd == 'T') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, val[k + 0], val[k + 1]); + ctrlPointX = reflectiveCtrlPointX; + ctrlPointY = reflectiveCtrlPointY; currentX = val[k + 0]; - currentY = val[k + 1]; // TODO: Check this logic - ctrlPointX = -(val[k + 0] - currentX); - ctrlPointY = -(val[k + 1] - currentY); + currentY = val[k + 1]; break; case 'a': // Draws an elliptical arc // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) @@ -2047,7 +2033,6 @@ public class VectorDrawable extends Drawable { currentY += val[k + 6]; ctrlPointX = currentX; ctrlPointY = currentY; - break; case 'A': // Draws an elliptical arc drawArc(path, @@ -2066,6 +2051,7 @@ public class VectorDrawable extends Drawable { ctrlPointY = currentY; break; } + previousCmd = cmd; } current[0] = currentX; current[1] = currentY; diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index ce711b6..8b23955 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -41,6 +41,7 @@ DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* rendere DeferredLayerUpdater::~DeferredLayerUpdater() { SkSafeUnref(mColorFilter); + setTransform(0); if (mLayer) { mCaches.resourceCache.decrementRefcount(mLayer); } @@ -62,7 +63,7 @@ void DeferredLayerUpdater::setDisplayList(RenderNode* displayList, } } -bool DeferredLayerUpdater::apply() { +bool DeferredLayerUpdater::apply(bool* hasFunctors) { bool success = true; // These properties are applied the same to both layer types mLayer->setColorFilter(mColorFilter); @@ -73,7 +74,11 @@ bool DeferredLayerUpdater::apply() { success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight); } mLayer->setBlend(mBlend); - mDisplayList->updateProperties(); + TreeInfo info = {0}; + mDisplayList->prepareTree(info); + if (info.hasFunctors) { + *hasFunctors = true; + } mLayer->updateDeferred(mDisplayList.get(), mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom); mDirtyRect.setEmpty(); diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index ce08c2d..2cc9229 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -77,7 +77,7 @@ public: ANDROID_API void setPaint(const SkPaint* paint); - ANDROID_API bool apply(); + ANDROID_API bool apply(bool* hasFunctors); ANDROID_API Layer* backingLayer() { return mLayer; diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index a84aa6b..140a07a 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -192,7 +192,9 @@ status_t DisplayListRenderer::drawDisplayList(RenderNode* displayList, flags, *currentTransform()); addDrawOp(op); mDisplayListData->addChild(op); - if (displayList->isProjectionReceiver()) { + + if (displayList->stagingProperties().isProjectionReceiver()) { + // use staging property, since recording on UI thread mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1; } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 9dbcd36..f37487f 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1901,7 +1901,6 @@ status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty, // will be performed by the display list itself if (displayList && displayList->isRenderable()) { // compute 3d ordering - displayList->updateProperties(); displayList->computeOrdering(); if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { status = startFrame(); diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 5010076..823ae7b 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -49,7 +49,12 @@ void RenderNode::outputLogBuffer(int fd) { fflush(file); } -RenderNode::RenderNode() : mDestroyed(false), mNeedsPropertiesSync(false), mDisplayListData(0) { +RenderNode::RenderNode() + : mDestroyed(false) + , mNeedsPropertiesSync(false) + , mNeedsDisplayListDataSync(false) + , mDisplayListData(0) + , mStagingDisplayListData(0) { } RenderNode::~RenderNode() { @@ -57,13 +62,15 @@ RenderNode::~RenderNode() { mDestroyed = true; delete mDisplayListData; + delete mStagingDisplayListData; } -void RenderNode::setData(DisplayListData* data) { - delete mDisplayListData; - mDisplayListData = data; - if (mDisplayListData) { - Caches::getInstance().registerFunctors(mDisplayListData->functorCount); +void RenderNode::setStagingDisplayList(DisplayListData* data) { + mNeedsDisplayListDataSync = true; + delete mStagingDisplayListData; + mStagingDisplayListData = data; + if (mStagingDisplayListData) { + Caches::getInstance().registerFunctors(mStagingDisplayListData->functorCount); } } @@ -86,35 +93,45 @@ void RenderNode::output(uint32_t level) { ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string()); } -void RenderNode::updateProperties() { +void RenderNode::prepareTree(TreeInfo& info) { + ATRACE_CALL(); + + prepareTreeImpl(info); +} + +void RenderNode::prepareTreeImpl(TreeInfo& info) { + pushStagingChanges(info); + prepareSubTree(info, mDisplayListData); +} + +void RenderNode::pushStagingChanges(TreeInfo& info) { if (mNeedsPropertiesSync) { mNeedsPropertiesSync = false; mProperties = mStagingProperties; } - - if (mDisplayListData) { - for (size_t i = 0; i < mDisplayListData->children().size(); i++) { - RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList; - childNode->updateProperties(); - } + if (mNeedsDisplayListDataSync) { + mNeedsDisplayListDataSync = false; + // Do a push pass on the old tree to handle freeing DisplayListData + // that are no longer used + TreeInfo oldTreeInfo = {0}; + prepareSubTree(oldTreeInfo, mDisplayListData); + // TODO: The damage for the old tree should be accounted for + delete mDisplayListData; + mDisplayListData = mStagingDisplayListData; + mStagingDisplayListData = 0; } } -bool RenderNode::hasFunctors() { - if (!mDisplayListData) return false; - - if (mDisplayListData->functorCount) { - return true; - } - - for (size_t i = 0; i < mDisplayListData->children().size(); i++) { - RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList; - if (childNode->hasFunctors()) { - return true; +void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) { + if (subtree) { + if (!info.hasFunctors) { + info.hasFunctors = subtree->functorCount; + } + for (size_t i = 0; i < subtree->children().size(); i++) { + RenderNode* childNode = subtree->children()[i]->mDisplayList; + childNode->prepareTreeImpl(info); } } - - return false; } /* diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index fd0fabc..7853701 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -65,6 +65,11 @@ class SaveOp; class RestoreToCountOp; class DrawDisplayListOp; +struct TreeInfo { + bool hasFunctors; + // TODO: Damage calculations? Flag to skip staging pushes for RT animations? +}; + /** * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties. * @@ -89,7 +94,7 @@ public: ANDROID_API static void outputLogBuffer(int fd); - ANDROID_API void setData(DisplayListData* newData); + ANDROID_API void setStagingDisplayList(DisplayListData* newData); void computeOrdering(); @@ -105,6 +110,10 @@ public: return mDisplayListData && mDisplayListData->hasDrawOps; } + const char* getName() const { + return mName.string(); + } + void setName(const char* name) { if (name) { char* lastPeriod = strrchr(name, '.'); @@ -129,10 +138,6 @@ public: return mStagingProperties; } - bool isProjectionReceiver() { - return properties().isProjectionReceiver(); - } - int getWidth() { return properties().getWidth(); } @@ -141,10 +146,7 @@ public: return properties().getHeight(); } - ANDROID_API void updateProperties(); - - // Returns true if this RenderNode or any of its children have functors - bool hasFunctors(); + ANDROID_API void prepareTree(TreeInfo& info); private: typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair; @@ -203,6 +205,10 @@ private: const char* mText; }; + void prepareTreeImpl(TreeInfo& info); + void pushStagingChanges(TreeInfo& info); + void prepareSubTree(TreeInfo& info, DisplayListData* subtree); + String8 mName; bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed @@ -210,7 +216,9 @@ private: RenderProperties mProperties; RenderProperties mStagingProperties; + bool mNeedsDisplayListDataSync; DisplayListData* mDisplayListData; + DisplayListData* mStagingDisplayListData; /** * Draw time state - these properties are only set and used during rendering diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index c231f6f..3638184 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -313,14 +313,11 @@ CanvasContext::CanvasContext(bool translucent) , mDirtyRegionsEnabled(false) , mOpaque(!translucent) , mCanvas(0) - , mHaveNewSurface(false) - , mInvokeFunctorsPending(false) - , mInvokeFunctorsTask(this) { + , mHaveNewSurface(false) { mGlobalContext = GlobalContext::get(); } CanvasContext::~CanvasContext() { - removeFunctorsTask(); destroyCanvas(); } @@ -347,6 +344,7 @@ void CanvasContext::setSurface(EGLNativeWindowType window) { if (mEglSurface != EGL_NO_SURFACE) { mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface); + mGlobalContext->makeCurrent(mEglSurface); mHaveNewSurface = true; } } @@ -356,14 +354,15 @@ void CanvasContext::swapBuffers() { mHaveNewSurface = false; } -void CanvasContext::makeCurrent() { +void CanvasContext::requireSurface() { + LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, + "requireSurface() called but no surface set!"); mGlobalContext->makeCurrent(mEglSurface); } bool CanvasContext::initialize(EGLNativeWindowType window) { if (mCanvas) return false; setSurface(window); - makeCurrent(); mCanvas = new OpenGLRenderer(); mCanvas->initProperties(); return true; @@ -371,7 +370,11 @@ bool CanvasContext::initialize(EGLNativeWindowType window) { void CanvasContext::updateSurface(EGLNativeWindowType window) { setSurface(window); - makeCurrent(); +} + +void CanvasContext::pauseSurface(EGLNativeWindowType window) { + // TODO: For now we just need a fence, in the future suspend any animations + // and such to prevent from trying to render into this surface } void CanvasContext::setup(int width, int height) { @@ -379,15 +382,13 @@ void CanvasContext::setup(int width, int height) { mCanvas->setViewport(width, height); } -void CanvasContext::setDisplayListData(RenderNode* displayList, DisplayListData* newData) { - displayList->setData(newData); -} - -void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) { +void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, + bool* hasFunctors) { + LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!"); mGlobalContext->makeCurrent(mEglSurface); for (size_t i = 0; i < layerUpdaters->size(); i++) { DeferredLayerUpdater* update = layerUpdaters->itemAt(i); - LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!"); + LOG_ALWAYS_FATAL_IF(!update->apply(hasFunctors), "Failed to update layer!"); if (update->backingLayer()->deferredUpdateScheduled) { mCanvas->pushLayerUpdate(update->backingLayer()); } @@ -428,60 +429,23 @@ void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { } } -void InvokeFunctorsTask::run() { - mContext->invokeFunctors(); -} - -void CanvasContext::attachFunctor(Functor* functor) { - if (!mCanvas) return; - - mCanvas->attachFunctor(functor); - removeFunctorsTask(); - queueFunctorsTask(0); -} - -void CanvasContext::detachFunctor(Functor* functor) { - if (!mCanvas) return; - - mCanvas->detachFunctor(functor); -} - void CanvasContext::invokeFunctor(Functor* functor) { + ATRACE_CALL(); DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; if (mGlobalContext->hasContext()) { requireGlContext(); mode = DrawGlInfo::kModeProcess; } - (*functor)(mode, NULL); -} - -void CanvasContext::invokeFunctors() { - mInvokeFunctorsPending = false; - - if (!mCanvas) return; - - makeCurrent(); - Rect dirty; - mCanvas->invokeFunctors(dirty); -} - -void CanvasContext::removeFunctorsTask() { - if (!mInvokeFunctorsPending) return; - - mInvokeFunctorsPending = false; - mRenderThread.remove(&mInvokeFunctorsTask); -} - -void CanvasContext::queueFunctorsTask(int delayMs) { - if (mInvokeFunctorsPending) return; - - mInvokeFunctorsPending = true; - mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs); + // TODO: Remove the dummy info in the future + DrawGlInfo dummyInfo; + memset(&dummyInfo, 0, sizeof(DrawGlInfo)); + (*functor)(mode, &dummyInfo); } bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { requireGlContext(); - layer->apply(); + bool hasFunctors; + layer->apply(&hasFunctors); return LayerRenderer::copyLayer(layer->backingLayer(), bitmap); } @@ -491,12 +455,12 @@ void CanvasContext::runWithGlContext(RenderTask* task) { } Layer* CanvasContext::createRenderLayer(int width, int height) { - requireGlContext(); + requireSurface(); return LayerRenderer::createRenderLayer(width, height); } Layer* CanvasContext::createTextureLayer() { - requireGlContext(); + requireSurface(); return LayerRenderer::createTextureLayer(); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 6f1c37f..dcb5957 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -43,17 +43,6 @@ class GlobalContext; class CanvasContext; class RenderThread; -class InvokeFunctorsTask : public RenderTask { -public: - InvokeFunctorsTask(CanvasContext* context) - : mContext(context) {} - - virtual void run(); - -private: - CanvasContext* mContext; -}; - // This per-renderer class manages the bridge between the global EGL context // and the render surface. class CanvasContext { @@ -63,16 +52,14 @@ public: bool initialize(EGLNativeWindowType window); void updateSurface(EGLNativeWindowType window); + void pauseSurface(EGLNativeWindowType window); void setup(int width, int height); - void setDisplayListData(RenderNode* displayList, DisplayListData* newData); - void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters); + void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, bool* hasFunctors); void drawDisplayList(RenderNode* displayList, Rect* dirty); void destroyCanvas(); bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); - void attachFunctor(Functor* functor); - void detachFunctor(Functor* functor); void invokeFunctor(Functor* functor); void runWithGlContext(RenderTask* task); @@ -83,12 +70,7 @@ public: private: void setSurface(EGLNativeWindowType window); void swapBuffers(); - void makeCurrent(); - - friend class InvokeFunctorsTask; - void invokeFunctors(); - void removeFunctorsTask(); - void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY); + void requireSurface(); void requireGlContext(); @@ -100,10 +82,6 @@ private: bool mOpaque; OpenGLRenderer* mCanvas; bool mHaveNewSurface; - - bool mInvokeFunctorsPending; - InvokeFunctorsTask mInvokeFunctorsTask; - }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 7b509a2..cf6c8db 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -30,19 +30,7 @@ namespace android { namespace uirenderer { namespace renderthread { -SetDisplayListData::SetDisplayListData() : mNewData(0) {} - -SetDisplayListData::SetDisplayListData(RenderNode* node, DisplayListData* newData) - : mTargetNode(node), mNewData(newData) { -} - -SetDisplayListData::~SetDisplayListData() {} - -void SetDisplayListData::apply() const { - mTargetNode->setData(mNewData); -} - -DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) { +DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) { } DrawFrameTask::~DrawFrameTask() { @@ -52,13 +40,6 @@ void DrawFrameTask::setContext(CanvasContext* context) { mContext = context; } -void DrawFrameTask::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) { - LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setDisplayListData with!"); - - SetDisplayListData setter(renderNode, newData); - mDisplayListDataUpdates.push(setter); -} - void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) { LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!"); @@ -88,23 +69,14 @@ void DrawFrameTask::drawFrame(RenderThread* renderThread) { LOG_ALWAYS_FATAL_IF(!mRenderNode.get(), "Cannot drawFrame with no render node!"); LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); - postAndWait(renderThread, MODE_FULL); + postAndWait(renderThread); // Reset the single-frame data mDirty.setEmpty(); mRenderNode = 0; } -void DrawFrameTask::flushStateChanges(RenderThread* renderThread) { - LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); - - postAndWait(renderThread, MODE_STATE_ONLY); -} - -void DrawFrameTask::postAndWait(RenderThread* renderThread, TaskMode mode) { - LOG_ALWAYS_FATAL_IF(mode == MODE_INVALID, "That's not a real mode, silly!"); - - mTaskMode = mode; +void DrawFrameTask::postAndWait(RenderThread* renderThread) { AutoMutex _lock(mLock); renderThread->queue(this); mSignal.wait(mLock); @@ -113,21 +85,14 @@ void DrawFrameTask::postAndWait(RenderThread* renderThread, TaskMode mode) { void DrawFrameTask::run() { ATRACE_NAME("DrawFrame"); - syncFrameState(); - - if (mTaskMode == MODE_STATE_ONLY) { - unblockUiThread(); - return; - } + // canUnblockUiThread is temporary until WebView has a solution for syncing frame state + bool canUnblockUiThread = syncFrameState(); // Grab a copy of everything we need Rect dirtyCopy(mDirty); sp<RenderNode> renderNode = mRenderNode; CanvasContext* context = mContext; - // This is temporary until WebView has a solution for syncing frame state - bool canUnblockUiThread = !requiresSynchronousDraw(renderNode.get()); - // From this point on anything in "this" is *UNSAFE TO ACCESS* if (canUnblockUiThread) { unblockUiThread(); @@ -140,21 +105,17 @@ void DrawFrameTask::run() { } } -void DrawFrameTask::syncFrameState() { +bool DrawFrameTask::syncFrameState() { ATRACE_CALL(); - for (size_t i = 0; i < mDisplayListDataUpdates.size(); i++) { - const SetDisplayListData& setter = mDisplayListDataUpdates[i]; - setter.apply(); - } - mDisplayListDataUpdates.clear(); + bool hasFunctors = false; + mContext->processLayerUpdates(&mLayers, &hasFunctors); - mContext->processLayerUpdates(&mLayers); + TreeInfo info = {0}; + mRenderNode->prepareTree(info); + hasFunctors |= info.hasFunctors; - // If we don't have an mRenderNode this is a state flush only - if (mRenderNode.get()) { - mRenderNode->updateProperties(); - } + return !hasFunctors; } void DrawFrameTask::unblockUiThread() { @@ -172,10 +133,6 @@ void DrawFrameTask::drawRenderNode(CanvasContext* context, RenderNode* renderNod context->drawDisplayList(renderNode, dirty); } -bool DrawFrameTask::requiresSynchronousDraw(RenderNode* renderNode) { - return renderNode->hasFunctors(); -} - } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 4e9b244..055d4cf 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -37,18 +37,6 @@ namespace renderthread { class CanvasContext; class RenderThread; -class SetDisplayListData { -public: - // This ctor exists for Vector's usage - SetDisplayListData(); - SetDisplayListData(RenderNode* node, DisplayListData* newData); - ~SetDisplayListData(); - void apply() const; -private: - sp<RenderNode> mTargetNode; - DisplayListData* mNewData; -}; - /* * This is a special Super Task. It is re-used multiple times by RenderProxy, * and contains state (such as layer updaters & new DisplayListDatas) that is @@ -62,33 +50,21 @@ public: void setContext(CanvasContext* context); - void setDisplayListData(RenderNode* renderNode, DisplayListData* newData); void addLayer(DeferredLayerUpdater* layer); void removeLayer(DeferredLayerUpdater* layer); void setRenderNode(RenderNode* renderNode); void setDirty(int left, int top, int right, int bottom); void drawFrame(RenderThread* renderThread); - void flushStateChanges(RenderThread* renderThread); virtual void run(); private: - enum TaskMode { - MODE_INVALID, - MODE_FULL, - MODE_STATE_ONLY, - }; - - void postAndWait(RenderThread* renderThread, TaskMode mode); - void syncFrameState(); + void postAndWait(RenderThread* renderThread); + bool syncFrameState(); void unblockUiThread(); static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty); - // This checks to see if there are any drawGlFunctors which would require - // a synchronous drawRenderNode() - static bool requiresSynchronousDraw(RenderNode* renderNode); - Mutex mLock; Condition mSignal; @@ -97,10 +73,8 @@ private: /********************************************* * Single frame data *********************************************/ - TaskMode mTaskMode; sp<RenderNode> mRenderNode; Rect mDirty; - Vector<SetDisplayListData> mDisplayListDataUpdates; /********************************************* * Multi frame data diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index e817e61..b233ae9 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -75,9 +75,6 @@ CREATE_BRIDGE1(destroyContext, CanvasContext* context) { void RenderProxy::destroyContext() { if (mContext) { - // Flush any pending changes to ensure all garbage is destroyed - mDrawFrameTask.flushStateChanges(&mRenderThread); - SETUP_TASK(destroyContext); args->context = mContext; mContext = 0; @@ -92,10 +89,10 @@ CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) { return (void*) args->context->initialize(args->window); } -bool RenderProxy::initialize(EGLNativeWindowType window) { +bool RenderProxy::initialize(const sp<ANativeWindow>& window) { SETUP_TASK(initialize); args->context = mContext; - args->window = window; + args->window = window.get(); return (bool) postAndWait(task); } @@ -104,11 +101,23 @@ CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window return NULL; } -void RenderProxy::updateSurface(EGLNativeWindowType window) { +void RenderProxy::updateSurface(const sp<ANativeWindow>& window) { SETUP_TASK(updateSurface); args->context = mContext; - args->window = window; - post(task); + args->window = window.get(); + postAndWait(task); +} + +CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) { + args->context->pauseSurface(args->window); + return NULL; +} + +void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) { + SETUP_TASK(pauseSurface); + args->context = mContext; + args->window = window.get(); + postAndWait(task); } CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) { @@ -124,10 +133,6 @@ void RenderProxy::setup(int width, int height) { post(task); } -void RenderProxy::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) { - mDrawFrameTask.setDisplayListData(renderNode, newData); -} - void RenderProxy::drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { mDrawFrameTask.setRenderNode(displayList); @@ -141,45 +146,18 @@ CREATE_BRIDGE1(destroyCanvas, CanvasContext* context) { } void RenderProxy::destroyCanvas() { - // If the canvas is being destroyed we won't be drawing again anytime soon - // So flush any pending state changes to allow for resource cleanup. - mDrawFrameTask.flushStateChanges(&mRenderThread); - SETUP_TASK(destroyCanvas); args->context = mContext; post(task); } -CREATE_BRIDGE2(attachFunctor, CanvasContext* context, Functor* functor) { - args->context->attachFunctor(args->functor); - return NULL; -} - -void RenderProxy::attachFunctor(Functor* functor) { - SETUP_TASK(attachFunctor); - args->context = mContext; - args->functor = functor; - post(task); -} - -CREATE_BRIDGE2(detachFunctor, CanvasContext* context, Functor* functor) { - args->context->detachFunctor(args->functor); - return NULL; -} - -void RenderProxy::detachFunctor(Functor* functor) { - SETUP_TASK(detachFunctor); - args->context = mContext; - args->functor = functor; - post(task); -} - CREATE_BRIDGE2(invokeFunctor, CanvasContext* context, Functor* functor) { args->context->invokeFunctor(args->functor); return NULL; } void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) { + ATRACE_CALL(); SETUP_TASK(invokeFunctor); args->context = mContext; args->functor = functor; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index c50da79..3eb8ed8 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -59,16 +59,14 @@ public: ANDROID_API RenderProxy(bool translucent); ANDROID_API virtual ~RenderProxy(); - ANDROID_API bool initialize(EGLNativeWindowType window); - ANDROID_API void updateSurface(EGLNativeWindowType window); + ANDROID_API bool initialize(const sp<ANativeWindow>& window); + ANDROID_API void updateSurface(const sp<ANativeWindow>& window); + ANDROID_API void pauseSurface(const sp<ANativeWindow>& window); ANDROID_API void setup(int width, int height); - ANDROID_API void setDisplayListData(RenderNode* renderNode, DisplayListData* newData); ANDROID_API void drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); ANDROID_API void destroyCanvas(); - ANDROID_API void attachFunctor(Functor* functor); - ANDROID_API void detachFunctor(Functor* functor); ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion); ANDROID_API void runWithGlContext(RenderTask* task); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java index 26498ca..edfa36a 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java @@ -552,29 +552,72 @@ public class CameraMetadataTest extends junit.framework.TestCase { }; int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats"); - // Write - mMetadata.set(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, availableFormats); + Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS; - byte[] availableFormatValues = mMetadata.readValues(availableFormatTag); + validateArrayMetadataReadWriteOverride(formatKey, availableFormats, + expectedIntValues, availableFormatTag); - ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder()); + // + // android.scaler.availableStreamConfigurations (int x n x 4 array) + // + final int OUTPUT = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT; + int[] availableStreamConfigs = new int[] { + 0x20, 3280, 2464, OUTPUT, // RAW16 + 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888 + 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888 + 0x100, 3264, 2448, OUTPUT, // ImageFormat.JPEG + 0x100, 3200, 2400, OUTPUT, // ImageFormat.JPEG + 0x100, 2592, 1944, OUTPUT, // ImageFormat.JPEG + 0x100, 2048, 1536, OUTPUT, // ImageFormat.JPEG + 0x100, 1920, 1080, OUTPUT // ImageFormat.JPEG + }; + int[] expectedAvailableStreamConfigs = new int[] { + 0x20, 3280, 2464, OUTPUT, // RAW16 + 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888 + 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888 + 0x21, 3264, 2448, OUTPUT, // BLOB + 0x21, 3200, 2400, OUTPUT, // BLOB + 0x21, 2592, 1944, OUTPUT, // BLOB + 0x21, 2048, 1536, OUTPUT, // BLOB + 0x21, 1920, 1080, OUTPUT // BLOB + }; + int availableStreamConfigTag = + CameraMetadataNative.getTag("android.scaler.availableStreamConfigurations"); - assertEquals(expectedIntValues.length * 4, availableFormatValues.length); - for (int i = 0; i < expectedIntValues.length; ++i) { - assertEquals(expectedIntValues[i], bf.getInt()); - } - // Read - byte[] availableFormatsAsByteArray = new byte[expectedIntValues.length * 4]; - ByteBuffer availableFormatsByteBuffer = - ByteBuffer.wrap(availableFormatsAsByteArray).order(ByteOrder.nativeOrder()); - for (int value : expectedIntValues) { - availableFormatsByteBuffer.putInt(value); - } - mMetadata.writeValues(availableFormatTag, availableFormatsAsByteArray); + Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS; + validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs, + expectedAvailableStreamConfigs, availableStreamConfigTag); - int[] resultFormats = mMetadata.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS); - assertNotNull("result available formats shouldn't be null", resultFormats); - assertArrayEquals(availableFormats, resultFormats); + // + // android.scaler.availableMinFrameDurations (int x n x 4 array) + + // + long[] availableMinDurations = new long[] { + 0x20, 3280, 2464, 33333336, // RAW16 + 0x23, 3264, 2448, 33333336, // YCbCr_420_888 + 0x23, 3200, 2400, 33333336, // YCbCr_420_888 + 0x100, 3264, 2448, 33333336, // ImageFormat.JPEG + 0x100, 3200, 2400, 33333336, // ImageFormat.JPEG + 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG + 0x100, 2048, 1536, 33333336, // ImageFormat.JPEG + 0x100, 1920, 1080, 33333336 // ImageFormat.JPEG + }; + long[] expectedAvailableMinDurations = new long[] { + 0x20, 3280, 2464, 33333336, // RAW16 + 0x23, 3264, 2448, 33333336, // YCbCr_420_888 + 0x23, 3200, 2400, 33333336, // YCbCr_420_888 + 0x21, 3264, 2448, 33333336, // BLOB + 0x21, 3200, 2400, 33333336, // BLOB + 0x21, 2592, 1944, 33333336, // BLOB + 0x21, 2048, 1536, 33333336, // BLOB + 0x21, 1920, 1080, 33333336 // BLOB + }; + int availableMinDurationsTag = + CameraMetadataNative.getTag("android.scaler.availableMinFrameDurations"); + + Key<long[]> durationKey = CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS; + validateArrayMetadataReadWriteOverride(durationKey, availableMinDurations, + expectedAvailableMinDurations, availableMinDurationsTag); // // android.statistics.faces (Face x n array) @@ -639,4 +682,59 @@ public class CameraMetadataTest extends junit.framework.TestCase { } } + + /** + * Validate metadata array tag read/write override. + * + * <p>Only support long and int array for now, can be easily extend to support other + * primitive arrays.</p> + */ + private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues, + T readValues, int tag) { + Class<T> type = key.getType(); + if (!type.isArray()) { + throw new IllegalArgumentException("This function expects an key with array type"); + } else if (type != int[].class && type != long[].class) { + throw new IllegalArgumentException("This function expects long or int array values"); + } + + // Write + mMetadata.set(key, writeValues); + + byte[] readOutValues = mMetadata.readValues(tag); + + ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder()); + + int readValuesLength = Array.getLength(readValues); + int readValuesNumBytes = readValuesLength * 4; + if (type == long[].class) { + readValuesNumBytes = readValuesLength * 8; + } + + assertEquals(readValuesNumBytes, readOutValues.length); + for (int i = 0; i < readValuesLength; ++i) { + if (type == int[].class) { + assertEquals(Array.getInt(readValues, i), bf.getInt()); + } else if (type == long[].class) { + assertEquals(Array.getLong(readValues, i), bf.getLong()); + } + } + + // Read + byte[] readOutValuesAsByteArray = new byte[readValuesNumBytes]; + ByteBuffer readOutValuesByteBuffer = + ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder()); + for (int i = 0; i < readValuesLength; ++i) { + if (type == int[].class) { + readOutValuesByteBuffer.putInt(Array.getInt(readValues, i)); + } else if (type == long[].class) { + readOutValuesByteBuffer.putLong(Array.getLong(readValues, i)); + } + } + mMetadata.writeValues(tag, readOutValuesAsByteArray); + + T result = mMetadata.get(key); + assertNotNull(key.getName() + " result shouldn't be null", result); + assertArrayEquals(writeValues, result); + } } diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index f68d1a9..48ef9db 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -30,6 +30,7 @@ import android.content.pm.PackageParser; import android.content.res.ObbInfo; import android.content.res.ObbScanner; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.os.Environment.UserEnvironment; import android.os.FileUtils; @@ -341,11 +342,13 @@ public class DefaultContainerService extends IntentService { // The .apk file String codePath = packageURI.getPath(); File codeFile = new File(codePath); + NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codePath); + final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); // Calculate size of container needed to hold base APK. final int sizeMb; try { - sizeMb = calculateContainerSize(codeFile, isForwardLocked); + sizeMb = calculateContainerSize(handle, codeFile, abi, isForwardLocked); } catch (IOException e) { Slog.w(TAG, "Problem when trying to copy " + codeFile.getPath()); return null; @@ -408,7 +411,14 @@ public class DefaultContainerService extends IntentService { final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); if (sharedLibraryDir.mkdir()) { - int ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(codeFile, sharedLibraryDir); + int ret = PackageManager.INSTALL_SUCCEEDED; + if (abi >= 0) { + ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, + sharedLibraryDir, Build.SUPPORTED_ABIS[abi]); + } else if (abi != PackageManager.NO_NATIVE_LIBRARIES) { + ret = abi; + } + if (ret != PackageManager.INSTALL_SUCCEEDED) { Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath()); PackageHelper.destroySdDir(newCid); @@ -822,6 +832,17 @@ public class DefaultContainerService extends IntentService { return availSdMb > sizeMb; } + private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException { + NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(apkFile); + final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); + + try { + return calculateContainerSize(handle, apkFile, abi, forwardLocked); + } finally { + handle.close(); + } + } + /** * Calculate the container size for an APK. Takes into account the * @@ -829,7 +850,8 @@ public class DefaultContainerService extends IntentService { * @return size in megabytes (2^20 bytes) * @throws IOException when there is a problem reading the file */ - private int calculateContainerSize(File apkFile, boolean forwardLocked) throws IOException { + private int calculateContainerSize(NativeLibraryHelper.ApkHandle apkHandle, + File apkFile, int abiIndex, boolean forwardLocked) throws IOException { // Calculate size of container needed to hold base APK. long sizeBytes = apkFile.length(); if (sizeBytes == 0 && !apkFile.exists()) { @@ -838,7 +860,10 @@ public class DefaultContainerService extends IntentService { // Check all the native files that need to be copied and add that to the // container size. - sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkFile); + if (abiIndex >= 0) { + sizeBytes += NativeLibraryHelper.sumNativeBinariesLI(apkHandle, + Build.SUPPORTED_ABIS[abiIndex]); + } if (forwardLocked) { sizeBytes += PackageHelper.extractPublicFiles(apkFile.getPath(), null); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 19286c8..e1c17cb 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -87,6 +87,8 @@ <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.BLUETOOTH_STACK" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> + <uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" /> + <uses-permission android:name="android.permission.RENDER_STATS" /> <application android:label="@string/app_label"> <provider diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml index 96da21f..8297878 100644 --- a/packages/SystemUI/res/layout/recents_task_view.xml +++ b/packages/SystemUI/res/layout/recents_task_view.xml @@ -43,7 +43,11 @@ android:textSize="24sp" android:textColor="#ffffffff" android:text="@string/recents_empty_message" - android:fontFamily="sans-serif-thin" /> + android:fontFamily="sans-serif-thin" + android:singleLine="true" + android:maxLines="2" + android:ellipsize="marquee" + android:fadingEdge="horizontal" /> <ImageView android:id="@+id/activity_icon" android:layout_width="@dimen/recents_task_view_activity_icon_size" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 77944c8..672c1d0 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -112,5 +112,7 @@ <integer name="recents_filter_animate_current_views_min_duration">175</integer> <!-- The min animation duration for animating views that are newly visible. --> <integer name="recents_filter_animate_new_views_min_duration">125</integer> + <!-- The min animation duration for animating views that are newly visible. --> + <integer name="recents_animate_task_bar_enter_duration">200</integer> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ce05639..ad10545 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -526,4 +526,12 @@ <string name="description_direction_up">Slide up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] --> <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string> + + <!-- Zen mode: Summary notification content title. [CHAR LIMIT=NONE] --> + <plurals name="zen_mode_notification_title"> + <item quantity="one">Notification hidden</item> + <item quantity="other">%d notifications hidden</item> + </plurals> + <!-- Zen mode: Summary notification content text. [CHAR LIMIT=NONE] --> + <string name="zen_mode_notification_text">Touch to show</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 8543b97..4fb90cb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -44,6 +44,7 @@ import android.view.View; import android.view.WindowManager; import com.android.systemui.R; +import java.util.Iterator; import java.util.List; /** A proxy implementation for the recents component */ @@ -57,8 +58,11 @@ public class AlternateRecentsComponent { Resources res = mContext.getResources(); float statusBarHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); - mFirstTaskRect = (Rect) msg.getData().getParcelable("taskRect"); - mFirstTaskRect.offset(0, (int) statusBarHeight); + Bundle replyData = msg.getData().getParcelable(KEY_CONFIGURATION_DATA); + mSingleCountFirstTaskRect = replyData.getParcelable(KEY_SINGLE_TASK_STACK_RECT); + mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight); + mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT); + mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight); } } } @@ -89,12 +93,20 @@ public class AlternateRecentsComponent { } } - final static int MSG_UPDATE_FOR_CONFIGURATION = 0; - final static int MSG_UPDATE_TASK_THUMBNAIL = 1; - final static int MSG_PRELOAD_TASKS = 2; - final static int MSG_CANCEL_PRELOAD_TASKS = 3; - final static int MSG_CLOSE_RECENTS = 4; - final static int MSG_TOGGLE_RECENTS = 5; + final public static int MSG_UPDATE_FOR_CONFIGURATION = 0; + final public static int MSG_UPDATE_TASK_THUMBNAIL = 1; + final public static int MSG_PRELOAD_TASKS = 2; + final public static int MSG_CANCEL_PRELOAD_TASKS = 3; + final public static int MSG_CLOSE_RECENTS = 4; + final public static int MSG_TOGGLE_RECENTS = 5; + + final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail"; + final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration"; + final public static String KEY_WINDOW_RECT = "recents.windowRect"; + final public static String KEY_SYSTEM_INSETS = "recents.systemInsets"; + final public static String KEY_SINGLE_TASK_STACK_RECT = "recents.singleCountTaskRect"; + final public static String KEY_MULTIPLE_TASK_STACK_RECT = "recents.multipleCountTaskRect"; + final static int sMinToggleDelay = 425; @@ -114,7 +126,8 @@ public class AlternateRecentsComponent { RecentsServiceConnection mConnection = new RecentsServiceConnection(); View mStatusBarView; - Rect mFirstTaskRect = new Rect(); + Rect mSingleCountFirstTaskRect = new Rect(); + Rect mMultipleCountFirstTaskRect = new Rect(); long mLastToggleTime; public AlternateRecentsComponent(Context context) { @@ -190,8 +203,8 @@ public class AlternateRecentsComponent { // Try and update the recents configuration try { Bundle data = new Bundle(); - data.putParcelable("windowRect", rect); - data.putParcelable("systemInsets", new Rect(0, statusBarHeight, 0, 0)); + data.putParcelable(KEY_WINDOW_RECT, rect); + data.putParcelable(KEY_SYSTEM_INSETS, new Rect(0, statusBarHeight, 0, 0)); Message msg = Message.obtain(null, MSG_UPDATE_FOR_CONFIGURATION, 0, 0); msg.setData(data); msg.replyTo = mMessenger; @@ -221,26 +234,29 @@ public class AlternateRecentsComponent { return null; } - Bitmap thumbnail = ssp.getTaskThumbnail(t.persistentId); - return thumbnail; + return ssp.getTaskThumbnail(t.persistentId); } return null; } - /** Returns whether there is a first task */ - boolean hasFirstTask() { + /** Returns whether there is are multiple recents tasks */ + boolean hasMultipleRecentsTask() { + // NOTE: Currently there's no method to get the number of non-home tasks, so we have to + // compute this ourselves SystemServicesProxy ssp = mSystemServicesProxy; - List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1, + List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier()); - for (ActivityManager.RecentTaskInfo t : tasks) { + Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator(); + while (iter.hasNext()) { + ActivityManager.RecentTaskInfo t = iter.next(); + // Skip tasks in the home stack if (ssp.isInHomeStack(t.persistentId)) { + iter.remove(); continue; } - - return true; } - return false; + return (tasks.size() > 1); } /** Converts from the device rotation to the degree */ @@ -287,8 +303,10 @@ public class AlternateRecentsComponent { // to launch the first task or dismiss itself SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1); + boolean isTopTaskHome = false; if (!tasks.isEmpty()) { - ComponentName topActivity = tasks.get(0).topActivity; + ActivityManager.RunningTaskInfo topTask = tasks.get(0); + ComponentName topActivity = topTask.topActivity; // Check if the front most activity is recents if (topActivity.getPackageName().equals(sRecentsPackage) && @@ -311,16 +329,30 @@ public class AlternateRecentsComponent { mLastToggleTime = System.currentTimeMillis(); return; } + + // Determine whether the top task is currently home + isTopTaskHome = ssp.isInHomeStack(topTask.id); } // Otherwise, Recents is not the front-most activity and we should animate into it - Rect taskRect = mFirstTaskRect; - if (taskRect != null && taskRect.width() > 0 && taskRect.height() > 0 && hasFirstTask()) { + boolean hasMultipleTasks = hasMultipleRecentsTask(); + Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect; + if (!isTopTaskHome && taskRect != null && taskRect.width() > 0 && taskRect.height() > 0) { // Loading from thumbnail Bitmap thumbnail; Bitmap firstThumbnail = loadFirstTaskThumbnail(); - if (firstThumbnail == null) { - // Load the thumbnail from the screenshot + if (firstThumbnail != null) {// Create the thumbnail + thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(), + Bitmap.Config.ARGB_8888); + int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight()); + Canvas c = new Canvas(thumbnail); + c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size), + new Rect(0, 0, taskRect.width(), taskRect.height()), null); + c.setBitmap(null); + // Recycle the old thumbnail + firstThumbnail.recycle(); + } else { + // Load the thumbnail from the screenshot if can't get one from the system WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); Bitmap screenshot = takeScreenshot(display); @@ -328,35 +360,24 @@ public class AlternateRecentsComponent { int size = Math.min(screenshot.getWidth(), screenshot.getHeight()); int statusBarHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); - thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(), + thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(thumbnail); c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size), - new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null); + new Rect(0, 0, taskRect.width(), taskRect.height()), null); c.setBitmap(null); - // Recycle the old screenshot + // Recycle the temporary screenshot screenshot.recycle(); - } else { - // Create the thumbnail - thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(), - Bitmap.Config.ARGB_8888); - int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight()); - Canvas c = new Canvas(thumbnail); - c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size), - new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null); - c.setBitmap(null); - // Recycle the old thumbnail - firstThumbnail.recycle(); } ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, - thumbnail, mFirstTaskRect.left, mFirstTaskRect.top, null); - startAlternateRecentsActivity(opts); + thumbnail, taskRect.left, taskRect.top, null); + startAlternateRecentsActivity(opts, true); } else { ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_launcher_enter, R.anim.recents_from_launcher_exit); - startAlternateRecentsActivity(opts); + startAlternateRecentsActivity(opts, false); } Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, @@ -365,11 +386,12 @@ public class AlternateRecentsComponent { } /** Starts the recents activity */ - void startAlternateRecentsActivity(ActivityOptions opts) { + void startAlternateRecentsActivity(ActivityOptions opts, boolean animatingWithThumbnail) { Intent intent = new Intent(sToggleRecentsAction); intent.setClassName(sRecentsPackage, sRecentsActivity); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail); if (opts != null) { mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle( UserHandle.USER_CURRENT)); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 86f188e..cde17f5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -72,8 +72,6 @@ public class Constants { public static class Window { // The dark background dim is set behind the empty recents view public static final float DarkBackgroundDim = 0.5f; - // The background dim is set behind the card stack - public static final float BackgroundDim = 0.35f; } public static class RecentsTaskLoader { @@ -98,11 +96,8 @@ public class Constants { } public static class TaskView { - public static final boolean AnimateFrontTaskIconOnEnterRecents = true; - public static final boolean AnimateFrontTaskIconOnLeavingRecents = true; - - public static final boolean UseRoundedCorners = false; - public static final float RoundedCornerRadiusDps = 3; + public static final boolean AnimateFrontTaskBarOnEnterRecents = true; + public static final boolean AnimateFrontTaskBarOnLeavingRecents = true; } } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index dd75921..f61c28c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -43,6 +43,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView boolean mVisible; boolean mTaskLaunched; + // Broadcast receiver to handle messages from our RecentsService BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -63,8 +64,21 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } }; + // Broadcast receiver to handle messages from the system + BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + finish(); + } + }; + /** Updates the set of recent tasks */ - void updateRecentsTasks() { + void updateRecentsTasks(Intent launchIntent) { + // Update the configuration based on the launch intent + RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra( + AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false); + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount); ArrayList<TaskStack> stacks = root.getStacks(); @@ -111,12 +125,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView RecentsTaskLoader.initialize(this); RecentsConfiguration.reinitialize(this); - // Set the background dim - WindowManager.LayoutParams wlp = getWindow().getAttributes(); - wlp.dimAmount = Constants.Values.Window.BackgroundDim; - getWindow().setAttributes(wlp); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); - // Create the view hierarchy mRecentsView = new RecentsView(this); mRecentsView.setCallbacks(this); @@ -134,7 +142,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView setContentView(mContainerView); // Update the recent tasks - updateRecentsTasks(); + updateRecentsTasks(getIntent()); } @Override @@ -154,7 +162,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView RecentsConfiguration.reinitialize(this); // Update the recent tasks - updateRecentsTasks(); + updateRecentsTasks(intent); } @Override @@ -170,22 +178,44 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "", Console.AnsiRed); super.onResume(); + } + + @Override + public void onAttachedToWindow() { + Console.log(Constants.DebugFlags.App.SystemUIHandshake, + "[RecentsActivity|onAttachedToWindow]", "", + Console.AnsiRed); + super.onAttachedToWindow(); // Register the broadcast receiver to handle messages from our service IntentFilter filter = new IntentFilter(); filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY); filter.addAction(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY); registerReceiver(mServiceBroadcastReceiver, filter); + + // Register the broadcast receiver to handle messages when the screen is turned off + filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(mScreenOffReceiver, filter); } @Override - protected void onPause() { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "", + public void onDetachedFromWindow() { + Console.log(Constants.DebugFlags.App.SystemUIHandshake, + "[RecentsActivity|onDetachedFromWindow]", "", Console.AnsiRed); - super.onPause(); + super.onDetachedFromWindow(); // Unregister any broadcast receivers we have registered unregisterReceiver(mServiceBroadcastReceiver); + unregisterReceiver(mScreenOffReceiver); + } + + @Override + protected void onPause() { + Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "", + Console.AnsiRed); + super.onPause(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 4a0de0b..21460bb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -17,6 +17,7 @@ package com.android.systemui.recents; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.util.DisplayMetrics; @@ -38,6 +39,9 @@ public class RecentsConfiguration { public int filteringCurrentViewsMinAnimDuration; public int filteringNewViewsMinAnimDuration; + public int taskBarEnterAnimDuration; + + public boolean launchedWithThumbnailAnimation; /** Private constructor */ private RecentsConfiguration() {} @@ -62,6 +66,12 @@ public class RecentsConfiguration { DisplayMetrics dm = res.getDisplayMetrics(); mDisplayMetrics = dm; + boolean isLandscape = res.getConfiguration().orientation == + Configuration.ORIENTATION_LANDSCAPE; + Console.log(Constants.DebugFlags.UI.MeasureAndLayout, + "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait", + Console.AnsiGreen); + displayRect.set(0, 0, dm.widthPixels, dm.heightPixels); animationPxMovementPerSecond = res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second); @@ -69,6 +79,8 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_filter_animate_current_views_min_duration); filteringNewViewsMinAnimDuration = res.getInteger(R.integer.recents_filter_animate_new_views_min_duration); + taskBarEnterAnimDuration = + res.getInteger(R.integer.recents_animate_task_bar_enter_duration); } public void updateSystemInsets(Rect insets) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java index 22363bb..f78a999 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -26,6 +26,7 @@ import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.TaskStackView; import com.android.systemui.recents.views.TaskViewTransform; @@ -50,36 +51,51 @@ class SystemUIMessageHandler extends Handler { Context context = mContext.get(); if (context == null) return; - if (msg.what == RecentsService.MSG_UPDATE_RECENTS_FOR_CONFIGURATION) { + if (msg.what == AlternateRecentsComponent.MSG_UPDATE_FOR_CONFIGURATION) { RecentsTaskLoader.initialize(context); RecentsConfiguration.reinitialize(context); try { Bundle data = msg.getData(); - Rect windowRect = (Rect) data.getParcelable("windowRect"); - Rect systemInsets = (Rect) data.getParcelable("systemInsets"); + Rect windowRect = data.getParcelable(AlternateRecentsComponent.KEY_WINDOW_RECT); + Rect systemInsets = data.getParcelable(AlternateRecentsComponent.KEY_SYSTEM_INSETS); // Create a dummy task stack & compute the rect for the thumbnail to animate to TaskStack stack = new TaskStack(context); TaskStackView tsv = new TaskStackView(context, stack); - // Since the nav bar height is already accounted for in the windowRect, don't pass - // in a bottom inset + Bundle replyData = new Bundle(); + TaskViewTransform transform; + + // Calculate the target task rect for when there is one task + // NOTE: Since the nav bar height is already accounted for in the windowRect, don't + // pass in a bottom inset + stack.addTask(new Task()); tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0); tsv.boundScroll(); - TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll()); - Rect taskRect = new Rect(transform.rect); + transform = tsv.getStackTransform(0, tsv.getStackScroll()); + replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT, + new Rect(transform.rect)); - data.putParcelable("taskRect", taskRect); + // Also calculate the target task rect when there are multiple tasks + stack.addTask(new Task()); + tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0); + tsv.setStackScrollRaw(Integer.MAX_VALUE); + tsv.boundScroll(); + transform = tsv.getStackTransform(1, tsv.getStackScroll()); + replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT, + new Rect(transform.rect)); + + data.putParcelable(AlternateRecentsComponent.KEY_CONFIGURATION_DATA, replyData); Message reply = Message.obtain(null, - RecentsService.MSG_UPDATE_RECENTS_FOR_CONFIGURATION, 0, 0); + AlternateRecentsComponent.MSG_UPDATE_FOR_CONFIGURATION, 0, 0); reply.setData(data); msg.replyTo.send(reply); } catch (RemoteException re) { re.printStackTrace(); } - } else if (msg.what == RecentsService.MSG_CLOSE_RECENTS) { + } else if (msg.what == AlternateRecentsComponent.MSG_CLOSE_RECENTS) { // Do nothing - } else if (msg.what == RecentsService.MSG_TOGGLE_RECENTS) { + } else if (msg.what == AlternateRecentsComponent.MSG_TOGGLE_RECENTS) { // Send a broadcast to toggle recents Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY); intent.setPackage(context.getPackageName()); @@ -99,11 +115,6 @@ public class RecentsService extends Service { final static String ACTION_FINISH_RECENTS_ACTIVITY = "action_finish_recents_activity"; final static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity"; - // XXX: This should be getting the message from recents definition - final static int MSG_UPDATE_RECENTS_FOR_CONFIGURATION = 0; - final static int MSG_CLOSE_RECENTS = 4; - final static int MSG_TOGGLE_RECENTS = 5; - Messenger mSystemUIMessenger = new Messenger(new SystemUIMessageHandler(this)); @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index d661f287..3c34e90 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; @@ -213,6 +212,7 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoader|loadThumbnail]", thumbnail); + thumbnail.setHasAlpha(false); loadThumbnail = thumbnail; mThumbnailCache.put(t.key, thumbnail); } else { @@ -331,13 +331,9 @@ public class RecentsTaskLoader { // Create the default assets Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + icon.eraseColor(0x00000000); mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(); - c.setBitmap(icon); - c.drawColor(0x00000000); - c.setBitmap(mDefaultThumbnail); - c.drawColor(0x00000000); - c.setBitmap(null); + mDefaultThumbnail.eraseColor(0x00000000); mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon); Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|defaultBitmaps]", @@ -362,18 +358,9 @@ public class RecentsTaskLoader { return mSystemServicesProxy; } - /** Reload the set of recent tasks */ - SpaceNode reload(Context context, int preloadCount) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]"); - Resources res = context.getResources(); - ArrayList<Task> tasksToForceLoad = new ArrayList<Task>(); - TaskStack stack = new TaskStack(context); - SpaceNode root = new SpaceNode(context); - root.setStack(stack); - + private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) { long t1 = System.currentTimeMillis(); - // Get the recent tasks SystemServicesProxy ssp = mSystemServicesProxy; List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier()); @@ -401,6 +388,24 @@ public class RecentsTaskLoader { } } + return tasks; + } + + /** Reload the set of recent tasks */ + SpaceNode reload(Context context, int preloadCount) { + long t1 = System.currentTimeMillis(); + + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]"); + Resources res = context.getResources(); + ArrayList<Task> tasksToForceLoad = new ArrayList<Task>(); + TaskStack stack = new TaskStack(context); + SpaceNode root = new SpaceNode(context); + root.setStack(stack); + + // Get the recent tasks + SystemServicesProxy ssp = mSystemServicesProxy; + List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context); + // Add each task to the task stack t1 = System.currentTimeMillis(); int taskCount = tasks.size(); @@ -454,6 +459,7 @@ public class RecentsTaskLoader { "[RecentsTaskLoader|loadingTaskThumbnail]"); task.thumbnail = ssp.getTaskThumbnail(task.key.id); if (task.thumbnail != null) { + task.thumbnail.setHasAlpha(false); mThumbnailCache.put(task.key, task.thumbnail); } else { task.thumbnail = mDefaultThumbnail; diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index efcd948..505238d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java @@ -24,7 +24,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -52,9 +51,7 @@ public class SystemServicesProxy { if (Constants.DebugFlags.App.EnableSystemServicesProxy) { // Create a dummy icon mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(mDummyIcon); - c.drawColor(0xFF999999); - c.setBitmap(null); + mDummyIcon.eraseColor(0xFF999999); } } @@ -117,9 +114,7 @@ public class SystemServicesProxy { // If we are mocking, then just return a dummy thumbnail if (Constants.DebugFlags.App.EnableSystemServicesProxy) { Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(thumbnail); - c.drawColor(0xff333333); - c.setBitmap(null); + thumbnail.eraseColor(0xff333333); return thumbnail; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index a0ff3b7..189f358 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -69,6 +69,10 @@ public class Task { TaskCallbacks mCb; + public Task() { + // Only used by RecentsService for task rect calculations. + } + public Task(int id, boolean isActive, Intent intent, String activityTitle, Bitmap activityIcon, int userId) { this.key = new TaskKey(id, intent); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index a0e5b6a..21e2c1d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -43,7 +43,13 @@ class FilteredTaskList { ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks); mFilter = filter; updateFilteredTasks(); - return !prevFilteredTasks.equals(mFilteredTasks); + if (!prevFilteredTasks.equals(mFilteredTasks)) { + return true; + } else { + // If the tasks are exactly the same pre/post filter, then just reset it + mFilter = null; + return false; + } } /** Removes the task filter and returns the previous touch state */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 1ebe231..ec28379 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -108,6 +108,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); @@ -118,6 +119,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // We measure our stack views sans the status bar. It will handle the nav bar itself. RecentsConfiguration config = RecentsConfiguration.getInstance(); + int childWidth = width - config.systemInsets.right; int childHeight = height - config.systemInsets.top; // Measure each child @@ -125,7 +127,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { - child.measure(widthMeasureSpec, + child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode), MeasureSpec.makeMeasureSpec(childHeight, heightMode)); } } @@ -255,11 +257,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV | Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_TASK); try { + UserHandle taskUser = new UserHandle(task.userId); if (opts != null) { - getContext().startActivityAsUser(i, opts.toBundle(), - new UserHandle(task.userId)); + getContext().startActivityAsUser(i, opts.toBundle(), taskUser); } else { - getContext().startActivityAsUser(i, new UserHandle(task.userId)); + getContext().startActivityAsUser(i, taskUser); } } catch (ActivityNotFoundException anfe) { Console.logError(getContext(), "Could not start Activity"); @@ -275,7 +277,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Constants.DebugFlags.App.TimeRecentsLaunchKey, "onTaskLaunched"); // Launch the app right away if there is no task view, otherwise, animate the icon out first - if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskIconOnLeavingRecents) { + if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskBarOnLeavingRecents) { post(launchRunnable); } else { tv.animateOnLeavingRecents(launchRunnable); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index fa06764..728aaad 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -171,7 +171,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal transform.visible = false; } else { transform.rect.offset(0, transform.translationY); - Utilities.scaleRectAboutCenter(transform.rect, scale); + Utilities.scaleRectAboutCenter(transform.rect, transform.scale); transform.visible = Rect.intersects(mRect, transform.rect); } transform.t = t; @@ -388,8 +388,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int stackHeight = mStackRectSansPeek.height(); int maxScrollHeight = taskHeight + (int) ((numTasks - 1) * Constants.Values.TaskStackView.StackOverlapPct * taskHeight); - mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight; - mMaxScroll = maxScrollHeight - stackHeight; + + if (numTasks <= 1) { + // If there is only one task, then center the task in the stack rect (sans peek) + mMinScroll = mMaxScroll = -(stackHeight - taskHeight) / 2; + } else { + mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight; + mMaxScroll = maxScrollHeight - stackHeight; + } // Debug logging if (Constants.DebugFlags.UI.MeasureAndLayout) { @@ -479,8 +485,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Clip against the next view (if we aren't animating its alpha) nextTv = (TaskView) getChildAt(curIndex + 1); if (nextTv.getAlpha() == 1f) { - Rect curRect = tv.getClippingRect(mTmpRect, false); - Rect nextRect = nextTv.getClippingRect(mTmpRect2, true); + Rect curRect = tv.getClippingRect(mTmpRect); + Rect nextRect = nextTv.getClippingRect(mTmpRect2); RecentsConfiguration config = RecentsConfiguration.getInstance(); // The hit rects are relative to the task view, which needs to be offset by the // system bar height @@ -523,9 +529,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int minHeight = (int) (mStackRect.height() - (Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height())); int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height())); - int centerX = mStackRect.centerX(); - mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top, - centerX + size / 2, mStackRectSansPeek.top + size); + mTaskRect.set(mStackRect.left, mStackRectSansPeek.top, + mStackRect.right, mStackRectSansPeek.top + size); // Update the scroll bounds updateMinMaxScroll(false); @@ -558,8 +563,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal requestSynchronizeStackViewsWithModel(); synchronizeStackViewsWithModel(); - // Animate the icon of the first task view - if (Constants.Values.TaskView.AnimateFrontTaskIconOnEnterRecents) { + // Animate the task bar of the first task view + if (config.launchedWithThumbnailAnimation && + Constants.Values.TaskView.AnimateFrontTaskBarOnEnterRecents) { TaskView tv = (TaskView) getChildAt(getChildCount() - 1); if (tv != null) { tv.animateOnEnterRecents(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index e99fecb..a3056ec 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -20,9 +20,8 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; +import android.graphics.Outline; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; @@ -36,8 +35,6 @@ import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; -import java.util.Random; - /* A task view */ public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks { @@ -54,8 +51,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. TaskBarView mBarView; TaskViewCallbacks mCb; - Path mRoundedRectClipPath = new Path(); - public TaskView(Context context) { this(context, null); @@ -71,7 +66,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - setWillNotDraw(false); } @Override @@ -85,31 +79,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. } } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - // Update the rounded rect clip path - RecentsConfiguration config = RecentsConfiguration.getInstance(); - float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps); - mRoundedRectClipPath.reset(); - mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()), - radius, radius, Path.Direction.CW); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - int restoreCount = 0; - if (Constants.Values.TaskView.UseRoundedCorners) { - restoreCount = canvas.save(); - canvas.clipPath(mRoundedRectClipPath); - } - super.dispatchDraw(canvas); - if (Constants.Values.TaskView.UseRoundedCorners) { - canvas.restoreToCount(restoreCount); - } - } - /** Set callback */ void setCallbacks(TaskViewCallbacks cb) { mCb = cb; @@ -195,7 +164,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. .translationY(0) .setStartDelay(235) .setInterpolator(BakedBezierInterpolator.INSTANCE) - .setDuration(Utilities.calculateTranslationAnimationDuration(translate)) + .setDuration(config.taskBarEnterAnimDuration) .withLayer() .start(); } @@ -214,23 +183,21 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. .setInterpolator(BakedBezierInterpolator.INSTANCE) .setDuration(Utilities.calculateTranslationAnimationDuration(translate)) .withLayer() - .withEndAction(r) + .withEndAction(new Runnable() { + @Override + public void run() { + post(r); + } + }) .start(); } /** Returns the rect we want to clip (it may not be the full rect) */ - Rect getClippingRect(Rect outRect, boolean accountForRoundedRects) { + Rect getClippingRect(Rect outRect) { getHitRect(outRect); // XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster outRect.right = outRect.left + mThumbnailView.getRight(); outRect.bottom = outRect.top + mThumbnailView.getBottom(); - // We need to shrink the next rect by the rounded corners since those are draw on - // top of the current view - if (accountForRoundedRects) { - RecentsConfiguration config = RecentsConfiguration.getInstance(); - float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps); - outRect.inset((int) radius, (int) radius); - } return outRect; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 844b964..2f135ec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -109,9 +109,6 @@ public abstract class BaseStatusBar extends SystemUI implements public static final int EXPANDED_LEAVE_ALONE = -10000; public static final int EXPANDED_FULL_OPEN = -10001; - private static final String EXTRA_INTERCEPT = "android.intercept"; - private static final float INTERCEPTED_ALPHA = .2f; - protected CommandQueue mCommandQueue; protected IStatusBarService mBarService; protected H mHandler = createHandler(); @@ -141,7 +138,8 @@ public abstract class BaseStatusBar extends SystemUI implements protected IDreamManager mDreamManager; PowerManager mPowerManager; - protected int mRowHeight; + protected int mRowMinHeight; + protected int mRowMaxHeight; // public mode, private notifications, etc private boolean mLockscreenPublicMode = false; @@ -883,7 +881,7 @@ public abstract class BaseStatusBar extends SystemUI implements } } entry.row = row; - entry.row.setRowHeight(mRowHeight); + entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight); entry.content = content; entry.expanded = contentViewLocal; entry.expandedPublic = publicViewLocal; @@ -1049,7 +1047,6 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) { Log.d(TAG, "addNotificationViews: added at " + pos); } - updateInterceptedState(entry); updateExpansionStates(); updateNotificationIcons(); } @@ -1059,17 +1056,19 @@ public abstract class BaseStatusBar extends SystemUI implements } protected void updateExpansionStates() { + + // TODO: Handle user expansion better int N = mNotificationData.size(); for (int i = 0; i < N; i++) { NotificationData.Entry entry = mNotificationData.get(i); if (!entry.row.isUserLocked()) { if (i == (N-1)) { if (DEBUG) Log.d(TAG, "expanding top notification at " + i); - entry.row.setExpanded(true); + entry.row.setSystemExpanded(true); } else { if (!entry.row.isUserExpanded()) { if (DEBUG) Log.d(TAG, "collapsing notification at " + i); - entry.row.setExpanded(false); + entry.row.setSystemExpanded(false); } else { if (DEBUG) Log.d(TAG, "ignoring user-modified notification at " + i); } @@ -1082,32 +1081,10 @@ public abstract class BaseStatusBar extends SystemUI implements protected void setZenMode(int mode) { if (!isDeviceProvisioned()) return; - final boolean change = mZenMode != mode; mZenMode = mode; - final int N = mNotificationData.size(); - for (int i = 0; i < N; i++) { - final NotificationData.Entry entry = mNotificationData.get(i); - if (change && !shouldIntercept()) { - entry.notification.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false); - } - updateInterceptedState(entry); - } updateNotificationIcons(); } - private boolean shouldIntercept() { - return mZenMode != Settings.Global.ZEN_MODE_OFF; - } - - protected boolean shouldIntercept(Notification n) { - return shouldIntercept() && n.extras.getBoolean(EXTRA_INTERCEPT); - } - - private void updateInterceptedState(NotificationData.Entry entry) { - final boolean intercepted = shouldIntercept(entry.notification.getNotification()); - entry.row.findViewById(R.id.container).setAlpha(intercepted ? INTERCEPTED_ALPHA : 1); - } - protected abstract void haltTicker(); protected abstract void setAreThereNotifications(); protected abstract void updateNotificationIcons(); @@ -1244,13 +1221,14 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed")); if (DEBUG) Log.d(TAG, "order was " + (orderUnchanged ? "unchanged" : "changed")); if (DEBUG) Log.d(TAG, "notification is " + (isTopAnyway ? "top" : "not top")); - final boolean wasExpanded = oldEntry.row.isUserExpanded(); removeNotificationViews(key); addNotificationViews(key, notification); // will also replace the heads up - if (wasExpanded) { - final NotificationData.Entry newEntry = mNotificationData.findByKey(key); - newEntry.row.setExpanded(true); - newEntry.row.setUserExpanded(true); + final NotificationData.Entry newEntry = mNotificationData.findByKey(key); + final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion(); + if (userChangedExpansion) { + boolean userExpanded = oldEntry.row.isUserExpanded(); + newEntry.row.applyExpansionToLayout(userExpanded); + newEntry.row.setUserExpanded(userExpanded); } } @@ -1312,7 +1290,6 @@ public abstract class BaseStatusBar extends SystemUI implements } else { entry.content.setOnClickListener(null); } - updateInterceptedState(entry); } protected void notifyHeadsUpScreenOn(boolean screenOn) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index b3d8688..2daf619 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -22,30 +22,49 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import com.android.internal.widget.SizeAdaptiveLayout; import com.android.systemui.R; public class ExpandableNotificationRow extends FrameLayout { - private int mRowHeight; + private int mRowMinHeight; + private int mRowMaxHeight; - /** does this row contain layouts that can adapt to row expansion */ + /** Does this row contain layouts that can adapt to row expansion */ private boolean mExpandable; - /** has the user manually expanded this row */ + /** Has the user actively changed the expansion state of this row */ + private boolean mHasUserChangedExpansion; + /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */ private boolean mUserExpanded; - /** is the user touching this row */ + /** Is the user touching this row */ private boolean mUserLocked; - /** are we showing the "public" version */ + /** Are we showing the "public" version */ private boolean mShowingPublic; + /** + * Is this notification expanded by the system. The expansion state can be overridden by the + * user expansion. + */ + private boolean mIsSystemExpanded; + private SizeAdaptiveLayout mPublicLayout; + private SizeAdaptiveLayout mPrivateLayout; + private int mMaxExpandHeight; + private boolean mMaxHeightNeedsUpdate; + public ExpandableNotificationRow(Context context, AttributeSet attrs) { super(context, attrs); } - public int getRowHeight() { - return mRowHeight; + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic); + mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded); } - public void setRowHeight(int rowHeight) { - this.mRowHeight = rowHeight; + public void setHeightRange(int rowMinHeight, int rowMaxHeight) { + mRowMinHeight = rowMinHeight; + mRowMaxHeight = rowMaxHeight; + mMaxHeightNeedsUpdate = true; } public boolean isExpandable() { @@ -56,11 +75,24 @@ public class ExpandableNotificationRow extends FrameLayout { mExpandable = expandable; } + /** + * @return whether the user has changed the expansion state + */ + public boolean hasUserChangedExpansion() { + return mHasUserChangedExpansion; + } + public boolean isUserExpanded() { return mUserExpanded; } + /** + * Set this notification to be expanded by the user + * + * @param userExpanded whether the user wants this notification to be expanded + */ public void setUserExpanded(boolean userExpanded) { + mHasUserChangedExpansion = true; mUserExpanded = userExpanded; } @@ -72,25 +104,102 @@ public class ExpandableNotificationRow extends FrameLayout { mUserLocked = userLocked; } - public void setExpanded(boolean expand) { + /** + * @return has the system set this notification to be expanded + */ + public boolean isSystemExpanded() { + return mIsSystemExpanded; + } + + /** + * Set this notification to be expanded by the system. + * + * @param expand whether the system wants this notification to be expanded. + */ + public void setSystemExpanded(boolean expand) { + mIsSystemExpanded = expand; + applyExpansionToLayout(expand); + } + + /** + * Apply an expansion state to the layout. + * + * @param expand should the layout be in the expanded state + */ + public void applyExpansionToLayout(boolean expand) { ViewGroup.LayoutParams lp = getLayoutParams(); if (expand && mExpandable) { lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; } else { - lp.height = mRowHeight; + lp.height = mRowMinHeight; } setLayoutParams(lp); } + /** + * If {@link #isExpanded()} then this is the greatest possible height this view can + * get and otherwise it is {@link #mRowMinHeight}. + * + * @return the maximum allowed expansion height of this view. + */ + public int getMaximumAllowedExpandHeight() { + boolean inExpansionState = isExpanded(); + if (!inExpansionState) { + // not expanded, so we return the collapsed size + return mRowMinHeight; + } + + return mShowingPublic ? mRowMinHeight : getMaxExpandHeight(); + } + + + + private void updateMaxExpandHeight() { + ViewGroup.LayoutParams lp = getLayoutParams(); + int oldHeight = lp.height; + lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; + setLayoutParams(lp); + measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST)); + lp.height = oldHeight; + setLayoutParams(lp); + mMaxExpandHeight = getMeasuredHeight(); + } + + /** + * Check whether the view state is currently expanded. This is given by the system in {@link + * #setSystemExpanded(boolean)} and can be overridden by user expansion or + * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this + * view can differ from this state, if layout params are modified from outside. + * + * @return whether the view state is currently expanded. + */ + private boolean isExpanded() { + return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + mMaxHeightNeedsUpdate = true; + } + public void setShowingPublic(boolean show) { mShowingPublic = show; - final ViewGroup publicLayout = (ViewGroup) findViewById(R.id.expandedPublic); // bail out if no public version - if (publicLayout.getChildCount() == 0) return; + if (mPublicLayout.getChildCount() == 0) return; // TODO: animation? - publicLayout.setVisibility(show ? View.VISIBLE : View.GONE); - findViewById(R.id.expanded).setVisibility(show ? View.GONE : View.VISIBLE); + mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE); + mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE); + } + + public int getMaxExpandHeight() { + if (mMaxHeightNeedsUpdate) { + updateMaxExpandHeight(); + mMaxHeightNeedsUpdate = false; + } + return mMaxExpandHeight; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java new file mode 100644 index 0000000..d563968 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar; + +import android.app.Notification; +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.service.notification.StatusBarNotification; +import android.util.ArrayMap; +import android.view.View; + +import com.android.systemui.R; +import com.android.systemui.statusbar.NotificationData.Entry; +import com.android.systemui.statusbar.phone.PhoneStatusBar; + +public class InterceptedNotifications { + private static final String TAG = "InterceptedNotifications"; + private static final String EXTRA_INTERCEPT = "android.intercept"; + + private final Context mContext; + private final PhoneStatusBar mBar; + private final ArrayMap<IBinder, StatusBarNotification> mIntercepted + = new ArrayMap<IBinder, StatusBarNotification>(); + + private Binder mSynKey; + + public InterceptedNotifications(Context context, PhoneStatusBar bar) { + mContext = context; + mBar = bar; + } + + public void releaseIntercepted() { + final int n = mIntercepted.size(); + for (int i = 0; i < n; i++) { + final IBinder key = mIntercepted.keyAt(i); + final StatusBarNotification sbn = mIntercepted.valueAt(i); + sbn.getNotification().extras.putBoolean(EXTRA_INTERCEPT, false); + mBar.addNotification(key, sbn); + } + mIntercepted.clear(); + updateSyntheticNotification(); + } + + public boolean tryIntercept(IBinder key, StatusBarNotification notification) { + if (!notification.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) return false; + mIntercepted.put(key, notification); + updateSyntheticNotification(); + return true; + } + + public void remove(IBinder key) { + if (mIntercepted.remove(key) != null) { + updateSyntheticNotification(); + } + } + + public boolean isSyntheticEntry(Entry ent) { + return mSynKey != null && ent.key.equals(mSynKey); + } + + public void update(IBinder key, StatusBarNotification notification) { + if (mIntercepted.containsKey(key)) { + mIntercepted.put(key, notification); + } + } + + private void updateSyntheticNotification() { + if (mIntercepted.isEmpty()) { + if (mSynKey != null) { + mBar.removeNotification(mSynKey); + mSynKey = null; + } + return; + } + final Notification n = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.stat_sys_zen_limited) + .setContentTitle(mContext.getResources().getQuantityString( + R.plurals.zen_mode_notification_title, + mIntercepted.size(), mIntercepted.size())) + .setContentText(mContext.getString(R.string.zen_mode_notification_text)) + .setOngoing(true) + .build(); + final StatusBarNotification sbn = new StatusBarNotification(mContext.getPackageName(), + mContext.getBasePackageName(), + TAG.hashCode(), TAG, Process.myUid(), Process.myPid(), 0, n, + mBar.getCurrentUserHandle()); + if (mSynKey == null) { + mSynKey = new Binder(); + mBar.addNotification(mSynKey, sbn); + } else { + mBar.updateNotification(mSynKey, sbn); + } + final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey); + entry.content.setOnClickListener(mSynClickListener); + } + + private final View.OnClickListener mSynClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + releaseIntercepted(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 2d2f2f1..6f93bed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -139,6 +139,7 @@ public class NotificationPanelView extends PanelView { * @param expandedHeight the new expanded height */ private void updateNotificationStackHeight(float expandedHeight) { + mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f); float childOffset = getRelativeTop(mNotificationStackScroller) - mNotificationParent.getTranslationY(); int newStackHeight = (int) (expandedHeight - childOffset); @@ -168,4 +169,16 @@ public class NotificationPanelView extends PanelView { protected int getDesiredMeasureHeight() { return mMaxPanelHeight; } + + @Override + protected void onExpandingStarted() { + super.onExpandingStarted(); + mNotificationStackScroller.onExpansionStarted(); + } + + @Override + protected void onExpandingFinished() { + super.onExpandingFinished(); + mNotificationStackScroller.onExpansionStopped(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 20fb225..6922ca5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -216,6 +216,7 @@ public class PanelView extends FrameLayout { mTimeAnimator.end(); mRubberbanding = false; mClosing = false; + onExpandingFinished(); } } }; @@ -230,6 +231,12 @@ public class PanelView extends FrameLayout { mRubberbandingEnabled = enable; } + protected void onExpandingFinished() { + } + + protected void onExpandingStarted() { + } + private void runPeekAnimation() { if (DEBUG) logf("peek to height=%.1f", mPeekHeight); if (mTimeAnimator.isStarted()) { @@ -398,7 +405,7 @@ public class PanelView extends FrameLayout { initVelocityTracker(); trackMovement(event); mTimeAnimator.cancel(); // end any outstanding animations - mBar.onTrackingStarted(PanelView.this); + onTrackingStarted(); mInitialOffsetOnTouch = mExpandedHeight; if (mExpandedHeight == 0) { mJustPeeked = true; @@ -443,7 +450,7 @@ public class PanelView extends FrameLayout { mHandleView.setPressed(false); postInvalidate(); // catch the press state change } - mBar.onTrackingStopped(PanelView.this); + onTrackingStopped(); trackMovement(event); float vel = getCurrentVelocity(); @@ -458,6 +465,15 @@ public class PanelView extends FrameLayout { return true; } + protected void onTrackingStopped() { + mBar.onTrackingStopped(PanelView.this); + } + + protected void onTrackingStarted() { + mBar.onTrackingStarted(PanelView.this); + onExpandingStarted(); + } + private float getCurrentVelocity() { float vel = 0; float yVel = 0, xVel = 0; @@ -561,6 +577,7 @@ public class PanelView extends FrameLayout { mInitialOffsetOnTouch = mExpandedHeight; mInitialTouchY = y; mTracking = true; + onTrackingStarted(); return true; } } @@ -598,6 +615,8 @@ public class PanelView extends FrameLayout { if (always||mVel != 0) { animationTick(0); // begin the animation + } else { + onExpandingFinished(); } } @@ -770,6 +789,7 @@ public class PanelView extends FrameLayout { if (!isFullyCollapsed()) { mTimeAnimator.cancel(); mClosing = true; + onExpandingStarted(); // collapse() should never be a rubberband, even if an animation is already running mRubberbanding = false; fling(-mSelfCollapseVelocityPx, /*always=*/ true); @@ -780,6 +800,7 @@ public class PanelView extends FrameLayout { if (DEBUG) logf("expand: " + this); if (isFullyCollapsed()) { mBar.startOpeningPanel(this); + onExpandingStarted(); fling(mSelfExpandVelocityPx, /*always=*/ true); } else if (DEBUG) { if (DEBUG) logf("skipping expansion: is expanded"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 4730f2f..841f3ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -59,6 +59,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.Global; import android.service.notification.StatusBarNotification; import android.util.DisplayMetrics; import android.util.EventLog; @@ -89,11 +90,11 @@ import com.android.systemui.R; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.GestureRecorder; +import com.android.systemui.statusbar.InterceptedNotifications; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationData.Entry; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; - import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.DateView; @@ -101,7 +102,6 @@ import com.android.systemui.statusbar.policy.HeadsUpNotificationView; import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RotationLockController; - import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import java.io.FileDescriptor; @@ -347,6 +347,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { }}; private Runnable mOnFlipRunnable; + private InterceptedNotifications mIntercepted; public void setOnFlipRunnable(Runnable onFlipRunnable) { mOnFlipRunnable = onFlipRunnable; @@ -357,7 +358,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { super.setZenMode(mode); if (mModeIcon == null) return; if (!isDeviceProvisioned()) return; - mModeIcon.setVisibility(mode != Settings.Global.ZEN_MODE_OFF ? View.VISIBLE : View.GONE); + final boolean zen = mode != Settings.Global.ZEN_MODE_OFF; + mModeIcon.setVisibility(zen ? View.VISIBLE : View.GONE); + if (!zen) { + mIntercepted.releaseIntercepted(); + } } @Override @@ -365,7 +370,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); updateDisplaySize(); - + mIntercepted = new InterceptedNotifications(mContext, this); super.start(); // calls createAndAddWindows() addNavigationBar(); @@ -931,49 +936,54 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mStatusIcons.removeViewAt(viewIndex); } + public UserHandle getCurrentUserHandle() { + return new UserHandle(mCurrentUserId); + } + public void addNotification(IBinder key, StatusBarNotification notification) { if (DEBUG) Log.d(TAG, "addNotification score=" + notification.getScore()); Entry shadeEntry = createNotificationViews(key, notification); if (shadeEntry == null) { return; } - if (!shouldIntercept(notification.getNotification())) { - if (mUseHeadsUp && shouldInterrupt(notification)) { - if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); - Entry interruptionCandidate = new Entry(key, notification, null); - ViewGroup holder = mHeadsUpNotificationView.getHolder(); - if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { - mInterruptingNotificationTime = System.currentTimeMillis(); - mInterruptingNotificationEntry = interruptionCandidate; - shadeEntry.setInterruption(); + if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(key, notification)) { + return; + } + if (mUseHeadsUp && shouldInterrupt(notification)) { + if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); + Entry interruptionCandidate = new Entry(key, notification, null); + ViewGroup holder = mHeadsUpNotificationView.getHolder(); + if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { + mInterruptingNotificationTime = System.currentTimeMillis(); + mInterruptingNotificationEntry = interruptionCandidate; + shadeEntry.setInterruption(); - // 1. Populate mHeadsUpNotificationView - mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry); + // 1. Populate mHeadsUpNotificationView + mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry); - // 2. Animate mHeadsUpNotificationView in - mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); + // 2. Animate mHeadsUpNotificationView in + mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP); - // 3. Set alarm to age the notification off - resetHeadsUpDecayTimer(); - } - } else if (notification.getNotification().fullScreenIntent != null) { - // Stop screensaver if the notification has a full-screen intent. - // (like an incoming phone call) - awakenDreams(); + // 3. Set alarm to age the notification off + resetHeadsUpDecayTimer(); + } + } else if (notification.getNotification().fullScreenIntent != null) { + // Stop screensaver if the notification has a full-screen intent. + // (like an incoming phone call) + awakenDreams(); - // not immersive & a full-screen alert should be shown - if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); - try { - notification.getNotification().fullScreenIntent.send(); - } catch (PendingIntent.CanceledException e) { - } - } else { - // usual case: status bar visible & not immersive + // not immersive & a full-screen alert should be shown + if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); + try { + notification.getNotification().fullScreenIntent.send(); + } catch (PendingIntent.CanceledException e) { + } + } else { + // usual case: status bar visible & not immersive - // show the ticker if there isn't already a heads up - if (mInterruptingNotificationEntry == null) { - tick(null, notification, true); - } + // show the ticker if there isn't already a heads up + if (mInterruptingNotificationEntry == null) { + tick(null, notification, true); } } addNotificationViews(shadeEntry); @@ -991,6 +1001,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } + @Override + public void updateNotification(IBinder key, StatusBarNotification notification) { + super.updateNotification(key, notification); + mIntercepted.update(key, notification); + } + public void removeNotification(IBinder key) { StatusBarNotification old = removeNotificationViews(key); if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old); @@ -1012,7 +1028,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { animateCollapsePanels(); } } - + mIntercepted.remove(key); setAreThereNotifications(); } @@ -1129,7 +1145,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { // in "public" mode (atop a secure keyguard), secret notifs are totally hidden continue; } - if (shouldIntercept(ent.notification.getNotification())) { + if (mIntercepted.isSyntheticEntry(ent)) { continue; } toShow.add(ent.icon); @@ -2625,7 +2641,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay); - mRowHeight = res.getDimensionPixelSize(R.dimen.notification_row_min_height); + mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_row_min_height); + mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_row_max_height); if (false) Log.v(TAG, "updateResources"); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index 79932a7..2dba669 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -78,7 +78,7 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. } if (mHeadsUp != null) { - mHeadsUp.row.setExpanded(true); + mHeadsUp.row.setSystemExpanded(true); mHeadsUp.row.setShowingPublic(false); if (mContentHolder == null) { // too soon! diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index e2d6c5b..f31896a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -89,7 +89,7 @@ public class NotificationStackScrollLayout extends ViewGroup * The current State this Layout is in */ private final StackScrollState mCurrentStackScrollState = new StackScrollState(this); - + private OnChildLocationsChangedListener mListener; public NotificationStackScrollLayout(Context context) { @@ -336,7 +336,7 @@ public class NotificationStackScrollLayout extends ViewGroup continue; } float top = slidingChild.getTranslationY(); - float bottom = top + slidingChild.getMeasuredHeight(); + float bottom = top + slidingChild.getHeight(); int left = slidingChild.getLeft(); int right = slidingChild.getRight(); @@ -713,6 +713,13 @@ public class NotificationStackScrollLayout extends ViewGroup protected void onViewRemoved(View child) { super.onViewRemoved(child); mCurrentStackScrollState.removeViewStateForView(child); + mStackScrollAlgorithm.notifyChildrenChanged(this); + } + + @Override + protected void onViewAdded(View child) { + super.onViewAdded(child); + mStackScrollAlgorithm.notifyChildrenChanged(this); } private boolean onInterceptTouchEventScroll(MotionEvent ev) { @@ -858,6 +865,21 @@ public class NotificationStackScrollLayout extends ViewGroup return Math.max(getHeight() - mContentHeight, 0); } + public void onExpansionStarted() { + mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState); + } + + public void onExpansionStopped() { + mStackScrollAlgorithm.onExpansionStopped(); + } + + public void setIsExpanded(boolean isExpanded) { + mStackScrollAlgorithm.setIsExpanded(isExpanded); + if (!isExpanded) { + mOwnScrollY = 0; + } + } + /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index 4745f3b..5506a55 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -21,6 +21,7 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; import com.android.systemui.R; +import com.android.systemui.statusbar.ExpandableNotificationRow; /** * The Algorithm of the {@link com.android.systemui.statusbar.stack @@ -46,6 +47,11 @@ public class StackScrollAlgorithm { private float mLayoutHeight; private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState(); + private boolean mIsExpansionChanging; + private int mFirstChildMaxHeight; + private boolean mIsExpanded; + private View mFirstChildWhileExpanding; + private boolean mExpandedOnStart; public StackScrollAlgorithm(Context context) { initConstants(context); @@ -117,8 +123,11 @@ public class StackScrollAlgorithm { StackScrollAlgorithmState algorithmState) { float stackHeight = getLayoutHeight(); + // The starting position of the bottom stack peek + float bottomPeekStart = stackHeight - mBottomStackPeekSize; + // The position where the bottom stack starts. - float transitioningPositionStart = stackHeight - mCollapsedSize - mBottomStackPeekSize; + float transitioningPositionStart = bottomPeekStart - mCollapsedSize; // The y coordinate of the current child. float currentYPosition = 0.0f; @@ -151,8 +160,8 @@ public class StackScrollAlgorithm { // Case 2: // First element of regular scrollview comes next, so the position is just the // scrolling position - nextYPosition = Math.min(scrollOffset, transitioningPositionStart); - childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING; + nextYPosition = updateStateForFirstScrollingChild(transitioningPositionStart, + childViewState, scrollOffset); } else if (nextYPosition >= transitioningPositionStart) { if (currentYPosition >= transitioningPositionStart) { // Case 3: @@ -186,6 +195,32 @@ public class StackScrollAlgorithm { } } + /** + * Update the state for the first child which is in the regular scrolling area. + * + * @param transitioningPositionStart the transition starting position of the bottom stack + * @param childViewState the view state of the child + * @param scrollOffset the position in the regular scroll view after this child + * @return the next child position + */ + private float updateStateForFirstScrollingChild(float transitioningPositionStart, + StackScrollState.ViewState childViewState, float scrollOffset) { + childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING; + if (scrollOffset < transitioningPositionStart) { + return scrollOffset; + } else { + return transitioningPositionStart; + } + } + + private int getMaxAllowedChildHeight(View child) { + if (child instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + return row.getMaximumAllowedExpandHeight(); + } + return child.getHeight(); + } + private float updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState, float stackHeight, float transitioningPositionStart, float currentYPosition, StackScrollState.ViewState childViewState, int childHeight, float nextYPosition) { @@ -335,7 +370,17 @@ public class StackScrollAlgorithm { } } else { algorithmState.lastTopStackIndex = i; - + if (i == 0) { + + // The starting position of the bottom stack peek + float bottomPeekStart = getLayoutHeight() - mBottomStackPeekSize; + // Collapse and expand the first child while the shade is being expanded + float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding + ? mFirstChildMaxHeight + : childHeight; + childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight), + mCollapsedSize); + } // We are already past the stack so we can end the loop break; } @@ -381,6 +426,47 @@ public class StackScrollAlgorithm { this.mLayoutHeight = layoutHeight; } + public void onExpansionStarted(StackScrollState currentState) { + mIsExpansionChanging = true; + mExpandedOnStart = mIsExpanded; + ViewGroup hostView = currentState.getHostView(); + updateFirstChildHeightWhileExpanding(hostView); + } + + private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) { + if (hostView.getChildCount() > 0) { + mFirstChildWhileExpanding = hostView.getChildAt(0); + if (mExpandedOnStart) { + + // We are collapsing the shade, so the first child can get as most as high as the + // current height. + mFirstChildMaxHeight = mFirstChildWhileExpanding.getHeight(); + } else { + + // We are expanding the shade, expand it to its full height. + mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding); + } + } else { + mFirstChildWhileExpanding = null; + mFirstChildMaxHeight = 0; + } + } + + public void onExpansionStopped() { + mIsExpansionChanging = false; + mFirstChildWhileExpanding = null; + } + + public void setIsExpanded(boolean isExpanded) { + this.mIsExpanded = isExpanded; + } + + public void notifyChildrenChanged(ViewGroup hostView) { + if (mIsExpansionChanging) { + updateFirstChildHeightWhileExpanding(hostView); + } + } + class StackScrollAlgorithmState { /** diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 35f873e..53ac063 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -132,6 +132,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED = "temporaryEnableAccessibilityStateUntilKeyguardRemoved"; + private static final String GET_WINDOW_TOKEN = "getWindowToken"; + private static final ComponentName sFakeAccessibilityServiceComponentName = new ComponentName("foo.bar", "FakeService"); @@ -360,6 +362,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { }, UserHandle.ALL, intentFilter, null, null); } + @Override public int addClient(IAccessibilityManagerClient client, int userId) { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy @@ -388,6 +391,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy @@ -412,6 +416,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return (OWN_PROCESS_ID != Binder.getCallingPid()); } + @Override public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy @@ -430,6 +435,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId) { List<AccessibilityServiceInfo> result = null; @@ -463,6 +469,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return result; } + @Override public void interrupt(int userId) { CopyOnWriteArrayList<Service> services; synchronized (mLock) { @@ -485,6 +492,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override public int addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection, int userId) throws RemoteException { synchronized (mLock) { @@ -521,6 +529,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override public void removeAccessibilityInteractionConnection(IWindow window) { synchronized (mLock) { mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( @@ -570,6 +579,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return -1; } + @Override public void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo) { @@ -612,6 +622,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { synchronized (mLock) { UserState userState = getCurrentUserStateLocked(); @@ -630,6 +641,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override public void temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled) { mSecurityPolicy.enforceCallingPermission( @@ -662,6 +674,29 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + @Override + public IBinder getWindowToken(int windowId) { + mSecurityPolicy.enforceCallingPermission( + Manifest.permission.RETRIEVE_WINDOW_TOKEN, + GET_WINDOW_TOKEN); + synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked( + UserHandle.getCallingUserId()); + if (resolvedUserId != mCurrentUserId) { + return null; + } + if (mSecurityPolicy.findWindowById(windowId) == null) { + return null; + } + IBinder token = mGlobalWindowTokens.get(windowId); + if (token != null) { + return token; + } + return getCurrentUserStateLocked().mWindowTokens.get(windowId); + } + } + boolean onGesture(int gestureId) { synchronized (mLock) { boolean handled = notifyGestureLocked(gestureId, false); @@ -689,7 +724,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { * @param outBounds The output to which to write the focus bounds. * @return Whether accessibility focus was found and the bounds are populated. */ - // TODO: (multi-display) Make sure this works for multiple displays. + // TODO: (multi-display) Make sure this works for multiple displays. boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) { // Instead of keeping track of accessibility focus events per // window to be able to find the focus in the active window, @@ -3176,8 +3211,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { // The active window also determined events from which // windows are delivered. synchronized (mLock) { + mFocusedWindowId = getFocusedWindowId(); if (mWindowsForAccessibilityCallback == null - && windowId == getFocusedWindowId()) { + && windowId == mFocusedWindowId) { mActiveWindowId = windowId; } } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index b6e761c..7ec9b82 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -52,6 +52,7 @@ import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; import android.os.storage.IObbActionListener; import android.os.storage.OnObbStateChangeListener; +import android.os.storage.StorageManager; import android.os.storage.StorageResultCode; import android.os.storage.StorageVolume; import android.text.TextUtils; @@ -2145,8 +2146,8 @@ class MountService extends IMountService.Stub } } - public int encryptStorage(String password) { - if (TextUtils.isEmpty(password)) { + public int encryptStorage(int type, String password) { + if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) { throw new IllegalArgumentException("password cannot be empty"); } @@ -2160,7 +2161,7 @@ class MountService extends IMountService.Stub } try { - mConnector.execute("cryptfs", "enablecrypto", "inplace", + mConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type], new SensitiveArg(toHex(password))); } catch (NativeDaemonConnectorException e) { // Encryption failed diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5bfb3fb..7607419 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2756,11 +2756,16 @@ public final class ActivityManagerService extends ActivityManagerNative debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; } + String requiredAbi = app.info.requiredCpuAbi; + if (requiredAbi == null) { + requiredAbi = Build.SUPPORTED_ABIS[0]; + } + // Start the process. It will either succeed and return a result containing // the PID of the new process, or else throw a RuntimeException. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, mountExternal, - app.info.targetSdkVersion, app.info.seinfo, null); + app.info.targetSdkVersion, app.info.seinfo, requiredAbi, null); BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics(); synchronized (bs) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ff90cae..747d0a7 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -60,8 +60,8 @@ import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; -import android.content.ServiceConnection; import android.content.IntentSender.SendIntentException; +import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ContainerEncryptionParams; @@ -74,14 +74,15 @@ import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; +import android.content.pm.ManifestDigest; import android.content.pm.PackageCleanItem; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageUserState; import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageStats; +import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; @@ -89,7 +90,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; -import android.content.pm.ManifestDigest; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; @@ -100,6 +100,7 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.os.Environment.UserEnvironment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; @@ -116,7 +117,6 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; -import android.os.Environment.UserEnvironment; import android.os.UserManager; import android.security.KeyStore; import android.security.SystemKeyStore; @@ -2054,6 +2054,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.dataDir = getDataPathForPackage(packageName, 0).getPath(); pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; + pkg.applicationInfo.requiredCpuAbi = ps.requiredCpuAbiString; } return generatePackageInfo(pkg, flags, userId); } @@ -3994,6 +3995,8 @@ public class PackageManagerService extends IPackageManager.Stub { codePath = pkg.mScanPath; // Set application objects path explicitly. setApplicationInfoPaths(pkg, codePath, resPath); + // Applications can run with the primary Cpu Abi unless otherwise is specified + pkg.applicationInfo.requiredCpuAbi = null; // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); @@ -4565,6 +4568,7 @@ public class PackageManagerService extends IPackageManager.Stub { // the PkgSetting exists already and doesn't have to be created. pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir, + pkg.applicationInfo.requiredCpuAbi, pkg.applicationInfo.flags, user, false); if (pkgSetting == null) { Slog.w(TAG, "Creating application package " + pkg.packageName + " failed"); @@ -4870,11 +4874,20 @@ public class PackageManagerService extends IPackageManager.Stub { } try { - if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) { + int copyRet = copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir); + if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { Slog.e(TAG, "Unable to copy native libraries"); mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; return null; } + + // We've successfully copied native libraries across, so we make a + // note of what ABI we're using + if (copyRet != PackageManager.NO_NATIVE_LIBRARIES) { + pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_ABIS[copyRet]; + } else { + pkg.applicationInfo.requiredCpuAbi = null; + } } catch (IOException e) { Slog.e(TAG, "Unable to copy native libraries", e); mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; @@ -5430,7 +5443,21 @@ public class PackageManagerService extends IPackageManager.Stub { * If this is an internal application or our nativeLibraryPath points to * the app-lib directory, unpack the libraries if necessary. */ - return NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir); + final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile); + try { + int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); + if (abi >= 0) { + int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, + nativeLibraryDir, Build.SUPPORTED_ABIS[abi]); + if (copyRet != PackageManager.INSTALL_SUCCEEDED) { + return copyRet; + } + } + + return abi; + } finally { + handle.close(); + } } private void killApplication(String pkgName, int appId, String reason) { @@ -8384,7 +8411,7 @@ public class PackageManagerService extends IPackageManager.Stub { } try { int copyRet = copyNativeLibrariesForInternalApp(codeFile, nativeLibraryFile); - if (copyRet != PackageManager.INSTALL_SUCCEEDED) { + if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { return copyRet; } } catch (IOException e) { @@ -11898,8 +11925,17 @@ public class PackageManagerService extends IPackageManager.Stub { final File newNativeDir = new File(newNativePath); if (!isForwardLocked(pkg) && !isExternal(pkg)) { - NativeLibraryHelper.copyNativeBinariesIfNeededLI( - new File(newCodePath), newNativeDir); + // NOTE: We do not report any errors from the APK scan and library + // copy at this point. + NativeLibraryHelper.ApkHandle handle = + new NativeLibraryHelper.ApkHandle(newCodePath); + final int abi = NativeLibraryHelper.findSupportedAbi( + handle, Build.SUPPORTED_ABIS); + if (abi >= 0) { + NativeLibraryHelper.copyNativeBinariesIfNeededLI( + handle, newNativeDir, Build.SUPPORTED_ABIS[abi]); + } + handle.close(); } final int[] users = sUserManager.getUserIds(); for (int user : users) { diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index b447861..15df3d2 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -30,8 +30,8 @@ final class PackageSetting extends PackageSettingBase { SharedUserSetting sharedUser; PackageSetting(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int pVersionCode, int pkgFlags) { - super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode, + String nativeLibraryPathString, String requiredCpuAbiString, int pVersionCode, int pkgFlags) { + super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode, pkgFlags); } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 2a5698b..c8af9d1 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -50,6 +50,7 @@ class PackageSettingBase extends GrantedPermissions { File resourcePath; String resourcePathString; String nativeLibraryPathString; + String requiredCpuAbiString; long timeStamp; long firstInstallTime; long lastUpdateTime; @@ -77,11 +78,11 @@ class PackageSettingBase extends GrantedPermissions { /* package name of the app that installed this package */ String installerPackageName; PackageSettingBase(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int pVersionCode, int pkgFlags) { + String nativeLibraryPathString, String requiredCpuAbiString, int pVersionCode, int pkgFlags) { super(pkgFlags); this.name = name; this.realName = realName; - init(codePath, resourcePath, nativeLibraryPathString, pVersionCode); + init(codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode); } /** @@ -98,6 +99,7 @@ class PackageSettingBase extends GrantedPermissions { resourcePath = base.resourcePath; resourcePathString = base.resourcePathString; nativeLibraryPathString = base.nativeLibraryPathString; + requiredCpuAbiString = base.requiredCpuAbiString; timeStamp = base.timeStamp; firstInstallTime = base.firstInstallTime; lastUpdateTime = base.lastUpdateTime; @@ -125,12 +127,13 @@ class PackageSettingBase extends GrantedPermissions { } void init(File codePath, File resourcePath, String nativeLibraryPathString, - int pVersionCode) { + String requiredCpuAbiString, int pVersionCode) { this.codePath = codePath; this.codePathString = codePath.toString(); this.resourcePath = resourcePath; this.resourcePathString = resourcePath.toString(); this.nativeLibraryPathString = nativeLibraryPathString; + this.requiredCpuAbiString = requiredCpuAbiString; this.versionCode = pVersionCode; } @@ -161,6 +164,7 @@ class PackageSettingBase extends GrantedPermissions { grantedPermissions = base.grantedPermissions; gids = base.gids; + requiredCpuAbiString = base.requiredCpuAbiString; timeStamp = base.timeStamp; firstInstallTime = base.firstInstallTime; lastUpdateTime = base.lastUpdateTime; diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java index c17cc46..36c3a34 100644 --- a/services/core/java/com/android/server/pm/PendingPackage.java +++ b/services/core/java/com/android/server/pm/PendingPackage.java @@ -22,8 +22,8 @@ final class PendingPackage extends PackageSettingBase { final int sharedId; PendingPackage(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) { - super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode, + String nativeLibraryPathString, String requiredCpuAbiString, int sharedId, int pVersionCode, int pkgFlags) { + super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode, pkgFlags); this.sharedId = sharedId; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index d1e34a1..80f716c 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -217,10 +217,10 @@ final class Settings { PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage, String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, - String nativeLibraryPathString, int pkgFlags, UserHandle user, boolean add) { + String nativeLibraryPathString, String requiredCpuAbiString, int pkgFlags, UserHandle user, boolean add) { final String name = pkg.packageName; PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath, - resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, + resourcePath, nativeLibraryPathString, requiredCpuAbiString, pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */); return p; } @@ -302,7 +302,7 @@ final class Settings { p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, - p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags); + p.nativeLibraryPathString, p.requiredCpuAbiString, p.appId, p.versionCode, p.pkgFlags); mDisabledSysPackages.remove(name); return ret; } @@ -316,7 +316,7 @@ final class Settings { } PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath, - String nativeLibraryPathString, int uid, int vc, int pkgFlags) { + String nativeLibraryPathString, String requiredCpuAbiString, int uid, int vc, int pkgFlags) { PackageSetting p = mPackages.get(name); if (p != null) { if (p.appId == uid) { @@ -326,7 +326,7 @@ final class Settings { "Adding duplicate package, keeping first: " + name); return null; } - p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, + p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags); p.appId = uid; if (addUserIdLPw(uid, p, name)) { @@ -395,10 +395,11 @@ final class Settings { private PackageSetting getPackageLPw(String name, PackageSetting origPackage, String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, - String nativeLibraryPathString, int vc, int pkgFlags, + String nativeLibraryPathString, String requiredCpuAbiString, int vc, int pkgFlags, UserHandle installUser, boolean add, boolean allowInstall) { PackageSetting p = mPackages.get(name); if (p != null) { + p.requiredCpuAbiString = requiredCpuAbiString; if (!p.codePath.equals(codePath)) { // Check to see if its a disabled system app if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { @@ -442,7 +443,7 @@ final class Settings { if (origPackage != null) { // We are consuming the data from an existing package. p = new PackageSetting(origPackage.name, name, codePath, resourcePath, - nativeLibraryPathString, vc, pkgFlags); + nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags); if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name + " is adopting original package " + origPackage.name); // Note that we will retain the new package's signature so @@ -459,7 +460,7 @@ final class Settings { p.setTimeStamp(codePath.lastModified()); } else { p = new PackageSetting(name, realName, codePath, resourcePath, - nativeLibraryPathString, vc, pkgFlags); + nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags); p.setTimeStamp(codePath.lastModified()); p.sharedUser = sharedUser; // If this is not a system app, it starts out stopped. @@ -585,6 +586,8 @@ final class Settings { && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) { p.nativeLibraryPathString = nativeLibraryPath; } + // Update the required Cpu Abi + p.requiredCpuAbiString = pkg.applicationInfo.requiredCpuAbi; // Update version code if needed if (pkg.mVersionCode != p.versionCode) { p.versionCode = pkg.mVersionCode; @@ -1551,6 +1554,9 @@ final class Settings { if (pkg.nativeLibraryPathString != null) { serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); } + if (pkg.requiredCpuAbiString != null) { + serializer.attribute(null, "requiredCpuAbi", pkg.requiredCpuAbiString); + } if (pkg.sharedUser == null) { serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { @@ -1593,6 +1599,9 @@ final class Settings { if (pkg.nativeLibraryPathString != null) { serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); } + if (pkg.requiredCpuAbiString != null) { + serializer.attribute(null, "requiredCpuAbi", pkg.requiredCpuAbiString); + } serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags)); serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp)); serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime)); @@ -1861,7 +1870,7 @@ final class Settings { if (idObj != null && idObj instanceof SharedUserSetting) { PackageSetting p = getPackageLPw(pp.name, null, pp.realName, (SharedUserSetting) idObj, pp.codePath, pp.resourcePath, - pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, + pp.nativeLibraryPathString, pp.requiredCpuAbiString, pp.versionCode, pp.pkgFlags, null, true /* add */, false /* allowInstall */); if (p == null) { PackageManagerService.reportSettingsProblem(Log.WARN, @@ -2281,6 +2290,8 @@ final class Settings { String codePathStr = parser.getAttributeValue(null, "codePath"); String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); + String requiredCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); + if (resourcePathStr == null) { resourcePathStr = codePathStr; } @@ -2300,7 +2311,7 @@ final class Settings { pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED; } PackageSetting ps = new PackageSetting(name, realName, codePathFile, - new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags); + new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, versionCode, pkgFlags); String timeStampStr = parser.getAttributeValue(null, "ft"); if (timeStampStr != null) { try { @@ -2367,6 +2378,7 @@ final class Settings { String codePathStr = null; String resourcePathStr = null; String nativeLibraryPathStr = null; + String requiredCpuAbiString = null; String systemStr = null; String installerPackageName = null; String uidError = null; @@ -2386,6 +2398,8 @@ final class Settings { codePathStr = parser.getAttributeValue(null, "codePath"); resourcePathStr = parser.getAttributeValue(null, "resourcePath"); nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); + requiredCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); + version = parser.getAttributeValue(null, "version"); if (version != null) { try { @@ -2462,7 +2476,7 @@ final class Settings { + parser.getPositionDescription()); } else if (userId > 0) { packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), - new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode, + new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, userId, versionCode, pkgFlags); if (PackageManagerService.DEBUG_SETTINGS) Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" @@ -2480,7 +2494,7 @@ final class Settings { userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; if (userId > 0) { packageSetting = new PendingPackage(name.intern(), realName, new File( - codePathStr), new File(resourcePathStr), nativeLibraryPathStr, userId, + codePathStr), new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, userId, versionCode, pkgFlags); packageSetting.setTimeStamp(timeStamp); packageSetting.firstInstallTime = firstInstallTime; @@ -2509,6 +2523,7 @@ final class Settings { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; packageSetting.nativeLibraryPathString = nativeLibraryPathStr; + packageSetting.requiredCpuAbiString = requiredCpuAbiString; // Handle legacy string here for single-user mode final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); if (enabledStr != null) { @@ -3008,6 +3023,7 @@ final class Settings { pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString); pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString); pw.print(prefix); pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); + pw.print(prefix); pw.print(" requiredCpuAbi="); pw.println(ps.requiredCpuAbiString); pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode); if (ps.pkg != null) { pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion); diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 972b088..79c4a50 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -151,8 +151,11 @@ public final class TvInputManagerService extends SystemService { private void removeUser(int userId) { synchronized (mLock) { + UserState userState = mUserStates.get(userId); + if (userState == null) { + return; + } // Release created sessions. - UserState userState = getUserStateLocked(userId); for (SessionState state : userState.sessionStateMap.values()) { if (state.session != null) { try { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b12ae4f..c24f53f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -24,6 +24,7 @@ import android.util.ArraySet; import android.util.TimeUtils; import android.view.IWindowId; +import android.view.WindowContentFrameStats; import com.android.internal.app.IBatteryStats; import com.android.internal.policy.PolicyManager; import com.android.internal.policy.impl.PhoneWindowManager; @@ -626,6 +627,8 @@ public class WindowManagerService extends IWindowManager.Stub private final PointerEventDispatcher mPointerEventDispatcher; + private WindowContentFrameStats mTempWindowRenderStats; + final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); @@ -10264,6 +10267,51 @@ public class WindowManagerService extends IWindowManager.Stub return mSafeMode; } + @Override + public boolean clearWindowContentFrameStats(IBinder token) { + if (!checkCallingPermission(Manifest.permission.FRAME_STATS, + "clearWindowContentFrameStats()")) { + throw new SecurityException("Requires FRAME_STATS permission"); + } + synchronized (mWindowMap) { + WindowState windowState = mWindowMap.get(token); + if (windowState == null) { + return false; + } + SurfaceControl surfaceControl = windowState.mWinAnimator.mSurfaceControl; + if (surfaceControl == null) { + return false; + } + return surfaceControl.clearContentFrameStats(); + } + } + + @Override + public WindowContentFrameStats getWindowContentFrameStats(IBinder token) { + if (!checkCallingPermission(Manifest.permission.FRAME_STATS, + "getWindowContentFrameStats()")) { + throw new SecurityException("Requires FRAME_STATS permission"); + } + synchronized (mWindowMap) { + WindowState windowState = mWindowMap.get(token); + if (windowState == null) { + return null; + } + SurfaceControl surfaceControl = windowState.mWinAnimator.mSurfaceControl; + if (surfaceControl == null) { + return null; + } + if (mTempWindowRenderStats == null) { + mTempWindowRenderStats = new WindowContentFrameStats(); + } + WindowContentFrameStats stats = mTempWindowRenderStats; + if (!surfaceControl.getContentFrameStats(stats)) { + return null; + } + return stats; + } + } + void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) { pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)"); mPolicy.dump(" ", pw, args); diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml index 6ca1aa7..bb2bebf 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml @@ -46,8 +46,8 @@ android:rotation="46.757" android:pivotX="162" android:pivotY="173.5" - android:fill="?attr/android:colorControlNormal" - android:stroke="?attr/android:colorControlNormal" + android:fill="?android:attr/colorControlNormal" + android:stroke="?android:attr/colorControlNormal" android:strokeWidth="3" android:strokeLineCap="round" android:strokeLineJoin="round" /> @@ -56,7 +56,7 @@ <path android:name="box3" android:pathData="m187,147l-1,55l-49,-1l2,-53l48,0z" - android:stroke="?attr/android:colorControlNormal" + android:stroke="?android:attr/colorControlNormal" android:strokeWidth="10" android:strokeLineCap="round" android:strokeLineJoin="round" /> @@ -65,7 +65,7 @@ <path android:name="box4" android:pathData="m248,74l0,164l-177,0l1,-165l173,-1l3,2z" - android:stroke="?attr/android:colorControlNormal" + android:stroke="?android:attr/colorControlNormal" android:strokeWidth="30" android:strokeLineCap="round" android:strokeLineJoin="round" /> diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 743a26c..1f2342a 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -23,22 +23,11 @@ import com.android.internal.view.IInputMethodClient; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; -import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; import android.util.DisplayMetrics; -import android.view.Display; -import android.view.Gravity; -import android.view.IApplicationToken; -import android.view.IInputFilter; -import android.view.IOnKeyguardExitResult; -import android.view.IRotationWatcher; -import android.view.IWindowManager; -import android.view.IWindowSession; - -import java.util.List; /** * Basic implementation of {@link IWindowManager} so that {@link Display} (and @@ -462,4 +451,16 @@ public class IWindowManagerImpl implements IWindowManager { // TODO Auto-generated method stub return false; } + + @Override + public boolean clearWindowContentRenderStats(IBinder token) { + // TODO Auto-generated method stub + return false; + } + + @Override + public WindowContentFrameStats getWindowContentRenderStats(IBinder token) { + // TODO Auto-generated method stub + return null; + } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java index 2ef3d5f..7c3ab6f 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java @@ -115,6 +115,7 @@ public class Main { "android.database.ContentObserver", // for Digital clock "com.android.i18n.phonenumbers.*", // for TextView with autolink attribute "android.app.DatePickerDialog", // b.android.com/28318 + "android.app.TimePickerDialog", // b.android.com/61515 }, excludeClasses, new String[] { |