diff options
422 files changed, 4113 insertions, 1413 deletions
@@ -186,6 +186,7 @@ LOCAL_SRC_FILES += \ core/java/android/nfc/INfcTag.aidl \ core/java/android/nfc/INfcCardEmulation.aidl \ core/java/android/nfc/INfcLockscreenDispatch.aidl \ + core/java/android/nfc/INfcUnlockHandler.aidl \ core/java/android/os/IBatteryPropertiesListener.aidl \ core/java/android/os/IBatteryPropertiesRegistrar.aidl \ core/java/android/os/ICancellationSignal.aidl \ diff --git a/api/current.txt b/api/current.txt index a3a99c7..56b0bf0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1123,6 +1123,7 @@ package android { field public static final int showDividers = 16843561; // 0x1010329 field public static final int showOnLockScreen = 16843721; // 0x10103c9 field public static final int showSilent = 16843259; // 0x10101fb + field public static final int showText = 16843952; // 0x10104b0 field public static final int showWeekNumber = 16843582; // 0x101033e field public static final int shownWeekCount = 16843585; // 0x1010341 field public static final int shrinkColumns = 16843082; // 0x101014a @@ -1434,8 +1435,12 @@ package android { field public static final int windowNoDisplay = 16843294; // 0x101021e field public static final int windowNoTitle = 16842838; // 0x1010056 field public static final int windowOverscan = 16843727; // 0x10103cf + field public static final int windowReenterTransition = 16843954; // 0x10104b2 + field public static final int windowReturnTransition = 16843953; // 0x10104b1 field public static final int windowSharedElementEnterTransition = 16843835; // 0x101043b field public static final int windowSharedElementExitTransition = 16843836; // 0x101043c + field public static final int windowSharedElementReenterTransition = 16843956; // 0x10104b4 + field public static final int windowSharedElementReturnTransition = 16843955; // 0x10104b3 field public static final int windowShowAnimation = 16842934; // 0x10100b6 field public static final int windowShowWallpaper = 16843410; // 0x1010292 field public static final int windowSoftInputMode = 16843307; // 0x101022b @@ -5219,6 +5224,7 @@ package android.app { field public static java.lang.String ACTION_EXIT_DESK_MODE; field public static final int DISABLE_CAR_MODE_GO_HOME = 1; // 0x1 field public static final int ENABLE_CAR_MODE_GO_CAR_HOME = 1; // 0x1 + field public static final int ENABLE_CAR_MODE_NO_WAKE_LOCK = 2; // 0x2 field public static final int MODE_NIGHT_AUTO = 0; // 0x0 field public static final int MODE_NIGHT_NO = 1; // 0x1 field public static final int MODE_NIGHT_YES = 2; // 0x2 @@ -8513,9 +8519,11 @@ package android.content.pm { method public android.graphics.Bitmap getAppIcon(); method public java.lang.CharSequence getAppLabel(); method public java.lang.String getAppPackageName(); + method public android.content.Intent getDetailsIntent(); method public java.lang.String getInstallerPackageName(); method public float getProgress(); method public int getSessionId(); + method public boolean isOpen(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } @@ -8529,7 +8537,6 @@ package android.content.pm { method public void setInstallLocation(int); method public void setOriginatingUri(android.net.Uri); method public void setReferrerUri(android.net.Uri); - method public void setSignatures(android.content.pm.Signature[]); method public void setSize(long); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; @@ -8645,6 +8652,8 @@ package android.content.pm { method public android.content.pm.PackageInstaller.Session openSession(int); method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback); + field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; + field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; } public static abstract class PackageInstaller.CommitCallback { @@ -8664,14 +8673,18 @@ package android.content.pm { method public void close(); method public void commit(android.content.pm.PackageInstaller.CommitCallback); method public void fsync(java.io.OutputStream) throws java.io.IOException; + method public java.lang.String[] list(); + method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException; method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException; method public void setProgress(float); } public static abstract class PackageInstaller.SessionCallback { ctor public PackageInstaller.SessionCallback(); + method public abstract void onClosed(int); method public abstract void onCreated(int); method public abstract void onFinished(int, boolean); + method public abstract void onOpened(int); method public abstract void onProgressChanged(int, float); } @@ -13276,6 +13289,11 @@ package android.hardware.location { field public static final int MONITOR_CURRENTLY_AVAILABLE = 0; // 0x0 field public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1; // 0x1 field public static final int MONITOR_UNSUPPORTED = 2; // 0x2 + field public static final int SOURCE_TECHNOLOGY_BLUETOOTH = 16; // 0x10 + field public static final int SOURCE_TECHNOLOGY_CELL = 8; // 0x8 + field public static final int SOURCE_TECHNOLOGY_GNSS = 1; // 0x1 + field public static final int SOURCE_TECHNOLOGY_SENSORS = 4; // 0x4 + field public static final int SOURCE_TECHNOLOGY_WIFI = 2; // 0x2 } public abstract class GeofenceHardwareCallback { @@ -13289,7 +13307,19 @@ package android.hardware.location { public abstract class GeofenceHardwareMonitorCallback { ctor public GeofenceHardwareMonitorCallback(); - method public void onMonitoringSystemChange(int, boolean, android.location.Location); + method public deprecated void onMonitoringSystemChange(int, boolean, android.location.Location); + method public void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent); + } + + public class GeofenceHardwareMonitorEvent implements android.os.Parcelable { + ctor public GeofenceHardwareMonitorEvent(int, int, int, android.location.Location); + method public int describeContents(); + method public android.location.Location getLocation(); + method public int getMonitoringStatus(); + method public int getMonitoringType(); + method public int getSourceTechnologies(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; } public final class GeofenceHardwareRequest { @@ -13301,10 +13331,12 @@ package android.hardware.location { method public int getMonitorTransitions(); method public int getNotificationResponsiveness(); method public double getRadius(); + method public int getSourceTechnologies(); method public int getUnknownTimer(); method public void setLastTransition(int); method public void setMonitorTransitions(int); method public void setNotificationResponsiveness(int); + method public void setSourceTechnologies(int); method public void setUnknownTimer(int); } @@ -17044,6 +17076,7 @@ package android.media.tv { method public void notifyContentAllowed(); method public void notifyContentBlocked(android.media.tv.TvContentRating); method public void notifyTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>); + method public void notifyTrackSelectionChanged(java.util.List<android.media.tv.TvTrackInfo>); method public void notifyVideoAvailable(); method public void notifyVideoUnavailable(int); method public android.view.View onCreateOverlayView(); @@ -17067,33 +17100,30 @@ package android.media.tv { } public final class TvTrackInfo implements android.os.Parcelable { - method public boolean containsKey(java.lang.String); method public int describeContents(); - method public boolean getBoolean(java.lang.String); - method public int getInt(java.lang.String); - method public java.lang.String getString(java.lang.String); + method public final int getAudioChannelCount(); + method public final int getAudioSampleRate(); + method public final android.os.Bundle getExtra(); + method public final java.lang.String getLanguage(); + method public final int getType(); + method public final int getVideoHeight(); + method public final int getVideoWidth(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count"; - field public static final java.lang.String KEY_HEIGHT = "height"; - field public static final java.lang.String KEY_IS_SELECTED = "is-selected"; - field public static final java.lang.String KEY_LANGUAGE = "language"; - field public static final java.lang.String KEY_SAMPLE_RATE = "sample-rate"; - field public static final java.lang.String KEY_TAG = "tag"; - field public static final java.lang.String KEY_TYPE = "type"; - field public static final java.lang.String KEY_WIDTH = "width"; - field public static final int VALUE_TYPE_AUDIO = 0; // 0x0 - field public static final int VALUE_TYPE_SUBTITLE = 2; // 0x2 - field public static final int VALUE_TYPE_VIDEO = 1; // 0x1 + field public static final int TYPE_AUDIO = 0; // 0x0 + field public static final int TYPE_SUBTITLE = 2; // 0x2 + field public static final int TYPE_VIDEO = 1; // 0x1 } public static final class TvTrackInfo.Builder { - ctor public TvTrackInfo.Builder(int, java.lang.String, boolean); - ctor public TvTrackInfo.Builder(android.media.tv.TvTrackInfo); + ctor public TvTrackInfo.Builder(int); method public android.media.tv.TvTrackInfo build(); - method public android.media.tv.TvTrackInfo.Builder putBoolean(java.lang.String, boolean); - method public android.media.tv.TvTrackInfo.Builder putInt(java.lang.String, int); - method public android.media.tv.TvTrackInfo.Builder putString(java.lang.String, java.lang.String); + method public final android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); + method public final android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); + method public final android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); + method public final android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String); + method public final android.media.tv.TvTrackInfo.Builder setVideoHeight(int); + method public final android.media.tv.TvTrackInfo.Builder setVideoWidth(int); } public class TvView extends android.view.ViewGroup { @@ -17101,6 +17131,7 @@ package android.media.tv { ctor public TvView(android.content.Context, android.util.AttributeSet); ctor public TvView(android.content.Context, android.util.AttributeSet, int); method public boolean dispatchUnhandledInputEvent(android.view.InputEvent); + method public java.util.List<android.media.tv.TvTrackInfo> getSelectedTracks(); method public java.util.List<android.media.tv.TvTrackInfo> getTracks(); method protected void onLayout(boolean, int, int, int, int); method public boolean onUnhandledInputEvent(android.view.InputEvent); @@ -17127,6 +17158,7 @@ package android.media.tv { method public void onContentBlocked(java.lang.String, android.media.tv.TvContentRating); method public void onError(java.lang.String, int); method public void onTrackInfoChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>); + method public void onTrackSelectionChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>); method public void onVideoAvailable(java.lang.String); method public void onVideoSizeChanged(java.lang.String, int, int); method public void onVideoUnavailable(java.lang.String, int); @@ -17453,10 +17485,15 @@ package android.net { method public java.net.URL getBoundURL(java.net.URL) throws java.net.MalformedURLException; method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException; method public javax.net.SocketFactory getSocketFactory(); + method public static void setNetworkBoundURLFactory(android.net.NetworkBoundURLFactory); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } + public abstract interface NetworkBoundURLFactory { + method public abstract java.net.URL getBoundURL(android.net.Network, java.net.URL) throws java.net.MalformedURLException; + } + public final class NetworkCapabilities implements android.os.Parcelable { ctor public NetworkCapabilities(android.net.NetworkCapabilities); method public int describeContents(); @@ -29216,6 +29253,20 @@ package android.telephony { field public static final int VOICEMAIL_NUMBER_MISSING = 40; // 0x28 } + public class IccOpenLogicalChannelResponse implements android.os.Parcelable { + method public int describeContents(); + method public int getChannel(); + method public byte[] getSelectResponse(); + method public int getStatus(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static int INVALID_CHANNEL; + field public static int MISSING_RESOURCE; + field public static int NO_ERROR; + field public static int NO_SUCH_ELEMENT; + field public static int UNKNOWN_ERROR; + } + public class MessagingConfigurationManager { method public boolean getCarrierConfigBoolean(java.lang.String, boolean); method public int getCarrierConfigInt(java.lang.String, int); @@ -29538,7 +29589,8 @@ package android.telephony { method public int hasCarrierPrivileges(); method public boolean hasIccCard(); method public boolean iccCloseLogicalChannel(int); - method public int iccOpenLogicalChannel(java.lang.String); + method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String); + method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String); method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String); method public boolean isNetworkRoaming(); method public boolean isSmsCapable(); @@ -35278,8 +35330,12 @@ package android.view { method protected final int getLocalFeatures(); method public android.media.session.MediaController getMediaController(); method public abstract int getNavigationBarColor(); + method public android.transition.Transition getReenterTransition(); + method public android.transition.Transition getReturnTransition(); method public android.transition.Transition getSharedElementEnterTransition(); method public android.transition.Transition getSharedElementExitTransition(); + method public android.transition.Transition getSharedElementReenterTransition(); + method public android.transition.Transition getSharedElementReturnTransition(); method public abstract int getStatusBarColor(); method public long getTransitionBackgroundFadeDuration(); method public android.transition.TransitionManager getTransitionManager(); @@ -35335,8 +35391,12 @@ package android.view { method public void setLogo(int); method public void setMediaController(android.media.session.MediaController); method public abstract void setNavigationBarColor(int); + method public void setReenterTransition(android.transition.Transition); + method public void setReturnTransition(android.transition.Transition); method public void setSharedElementEnterTransition(android.transition.Transition); method public void setSharedElementExitTransition(android.transition.Transition); + method public void setSharedElementReenterTransition(android.transition.Transition); + method public void setSharedElementReturnTransition(android.transition.Transition); method public void setSoftInputMode(int); method public abstract void setStatusBarColor(int); method public abstract void setTitle(java.lang.CharSequence); @@ -39379,6 +39439,7 @@ package android.widget { ctor public Switch(android.content.Context, android.util.AttributeSet); ctor public Switch(android.content.Context, android.util.AttributeSet, int); ctor public Switch(android.content.Context, android.util.AttributeSet, int, int); + method public boolean getShowText(); method public boolean getSplitTrack(); method public int getSwitchMinWidth(); method public int getSwitchPadding(); @@ -39388,6 +39449,7 @@ package android.widget { method public int getThumbTextPadding(); method public android.graphics.drawable.Drawable getTrackDrawable(); method public void onMeasure(int, int); + method public void setShowText(boolean); method public void setSplitTrack(boolean); method public void setSwitchMinWidth(int); method public void setSwitchPadding(int); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index bc16800..1f25dd0 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -59,7 +59,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.SizedInputStream; import libcore.io.IoUtils; -import libcore.io.Streams; import java.io.File; import java.io.FileDescriptor; @@ -1068,6 +1067,8 @@ public final class Pm { } } + final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId); + PackageInstaller.Session session = null; InputStream in = null; OutputStream out = null; @@ -1081,16 +1082,21 @@ public final class Pm { } out = session.openWrite(splitName, 0, sizeBytes); - final int n = Streams.copy(in, out); - session.fsync(out); + int total = 0; + byte[] buffer = new byte[65536]; + int c; + while ((c = in.read(buffer)) != -1) { + total += c; + out.write(buffer, 0, c); - final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId); - if (info.sizeBytes > 0) { - final float fraction = ((float) n / (float) info.sizeBytes); - session.addProgress(fraction); + if (info.sizeBytes > 0) { + final float fraction = ((float) c / (float) info.sizeBytes); + session.addProgress(fraction); + } } + session.fsync(out); - System.out.println("Success: streamed " + n + " bytes"); + System.out.println("Success: streamed " + total + " bytes"); } finally { IoUtils.closeQuietly(out); IoUtils.closeQuietly(in); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index f18507e..18ba8c4 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1624,7 +1624,7 @@ final class ApplicationPackageManager extends PackageManager { } Drawable dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo); if (dr == null) { - dr = getDefaultActivityIcon(); + dr = itemInfo.loadDefaultIcon(this); } return getUserManager().getBadgedDrawableForUser(dr, new UserHandle(mContext.getUserId())); diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index 1326064..b5d362d 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -256,7 +256,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { @Override protected Transition getViewsTransition() { if (mIsReturning) { - return getWindow().getExitTransition(); + return getWindow().getReenterTransition(); } else { return getWindow().getEnterTransition(); } @@ -264,7 +264,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { protected Transition getSharedElementTransition() { if (mIsReturning) { - return getWindow().getSharedElementExitTransition(); + return getWindow().getSharedElementReenterTransition(); } else { return getWindow().getSharedElementEnterTransition(); } diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index 2ce6018..b3fdcc7 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -395,7 +395,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { @Override protected Transition getViewsTransition() { if (mIsReturning) { - return getWindow().getEnterTransition(); + return getWindow().getReturnTransition(); } else { return getWindow().getExitTransition(); } @@ -403,7 +403,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { protected Transition getSharedElementTransition() { if (mIsReturning) { - return getWindow().getSharedElementEnterTransition(); + return getWindow().getSharedElementReturnTransition(); } else { return getWindow().getSharedElementExitTransition(); } diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 3967740..ec9960d 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -401,7 +401,7 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac /** * This flag is set in {@link #onStartCommand} if the Intent is a - * a retry because the original attempt never got to or returned from + * retry because the original attempt never got to or returned from * {@link #onStartCommand(Intent, int, int)}. */ public static final int START_FLAG_RETRY = 0x0002; diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index c6731c9..f79eb04 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -123,7 +123,18 @@ public class UiModeManager { * will switch to the car home activity even if we are already in car mode. */ public static final int ENABLE_CAR_MODE_GO_CAR_HOME = 0x0001; - + + /** + * Flag for use with {@link #enableCarMode(int)}: do not hold full wake lock + * while in car mode. By default, when this flag is not set, the system may hold + * a full wake lock to keep the screen turned on while in car mode. + * Setting this flag disables such behavior and the screen may be turned off if + * there is no other user activity and no other full wake lock held. + * Setting this flag can be relevant for a car dock application that does not require the + * screen kept on. + */ + public static final int ENABLE_CAR_MODE_NO_WAKE_LOCK = 0x0002; + /** * Force device into car mode, like it had been placed in the car dock. * This will cause the device to switch to the car home UI as part of diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 482ad6e..548a0c9 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -839,7 +839,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** * @hide */ - @Override protected Drawable loadDefaultIcon(PackageManager pm) { + @Override + public Drawable loadDefaultIcon(PackageManager pm) { if ((flags & FLAG_EXTERNAL_STORAGE) != 0 && isPackageUnavailable(pm)) { return Resources.getSystem().getDrawable( diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index 7e8f285..cc06b67 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -179,7 +179,8 @@ public class ComponentInfo extends PackageItemInfo { /** * @hide */ - @Override protected Drawable loadDefaultIcon(PackageManager pm) { + @Override + public Drawable loadDefaultIcon(PackageManager pm) { return applicationInfo.loadIcon(pm); } diff --git a/core/java/android/content/pm/IPackageInstallerCallback.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl index a31ae54..39ae1a0 100644 --- a/core/java/android/content/pm/IPackageInstallerCallback.aidl +++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl @@ -19,6 +19,8 @@ package android.content.pm; /** {@hide} */ oneway interface IPackageInstallerCallback { void onSessionCreated(int sessionId); + void onSessionOpened(int sessionId); void onSessionProgressChanged(int sessionId, float progress); + void onSessionClosed(int sessionId); void onSessionFinished(int sessionId, boolean success); } diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index 2fd7ddb..af0323f 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -24,7 +24,9 @@ interface IPackageInstallerSession { void setClientProgress(float progress); void addClientProgress(float progress); + String[] list(); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); + ParcelFileDescriptor openRead(String name); void close(); void commit(in IPackageInstallObserver2 observer); diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java index a9c574a..f263885 100644 --- a/core/java/android/content/pm/InstallSessionInfo.java +++ b/core/java/android/content/pm/InstallSessionInfo.java @@ -16,7 +16,9 @@ package android.content.pm; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Intent; import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; @@ -32,6 +34,8 @@ public class InstallSessionInfo implements Parcelable { public String installerPackageName; /** {@hide} */ public float progress; + /** {@hide} */ + public boolean open; /** {@hide} */ public int mode; @@ -53,6 +57,7 @@ public class InstallSessionInfo implements Parcelable { sessionId = source.readInt(); installerPackageName = source.readString(); progress = source.readFloat(); + open = source.readInt() != 0; mode = source.readInt(); sizeBytes = source.readLong(); @@ -88,6 +93,13 @@ public class InstallSessionInfo implements Parcelable { } /** + * Return if this session is currently open. + */ + public boolean isOpen() { + return open; + } + + /** * Return the package name this session is working with. May be {@code null} * if unknown. */ @@ -111,6 +123,23 @@ public class InstallSessionInfo implements Parcelable { return appLabel; } + /** + * Return an Intent that can be started to view details about this install + * session. This may surface actions such as pause, resume, or cancel. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard + * against this. + * + * @see PackageInstaller#ACTION_SESSION_DETAILS + */ + public @Nullable Intent getDetailsIntent() { + final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS); + intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); + intent.setPackage(installerPackageName); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; + } + @Override public int describeContents() { return 0; @@ -121,6 +150,7 @@ public class InstallSessionInfo implements Parcelable { dest.writeInt(sessionId); dest.writeString(installerPackageName); dest.writeFloat(progress); + dest.writeInt(open ? 1 : 0); dest.writeInt(mode); dest.writeLong(sizeBytes); diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java index 3de9863..1716e39 100644 --- a/core/java/android/content/pm/InstallSessionParams.java +++ b/core/java/android/content/pm/InstallSessionParams.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.Nullable; +import android.app.ActivityManager; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; @@ -30,6 +31,9 @@ import com.android.internal.util.IndentingPrintWriter; */ public class InstallSessionParams implements Parcelable { + /** {@hide} */ + public static final int MODE_INVALID = -1; + /** * Mode for an install session whose staged APKs should fully replace any * existing APKs for the target app. @@ -48,21 +52,19 @@ public class InstallSessionParams implements Parcelable { public static final int MODE_INHERIT_EXISTING = 2; /** {@hide} */ - public int mode; + public int mode = MODE_INVALID; /** {@hide} */ public int installFlags; /** {@hide} */ public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY; /** {@hide} */ - public Signature[] signatures; - /** {@hide} */ public long sizeBytes = -1; /** {@hide} */ public String appPackageName; /** {@hide} */ public Bitmap appIcon; /** {@hide} */ - public CharSequence appLabel; + public String appLabel; /** {@hide} */ public Uri originatingUri; /** {@hide} */ @@ -86,7 +88,6 @@ public class InstallSessionParams implements Parcelable { mode = source.readInt(); installFlags = source.readInt(); installLocation = source.readInt(); - signatures = (Signature[]) source.readParcelableArray(null); sizeBytes = source.readLong(); appPackageName = source.readString(); appIcon = source.readParcelable(null); @@ -106,16 +107,13 @@ public class InstallSessionParams implements Parcelable { } /** - * Optionally provide a set of certificates for the app being installed. - * <p> - * If the APKs staged in the session aren't consistent with these - * signatures, the install will fail. Regardless of this value, all APKs in - * the app must have the same signing certificates. - * - * @see PackageInfo#signatures + * @deprecated use {@link PackageInstaller.Session#openRead(String)} to + * calculate message digest instead. + * @hide */ + @Deprecated public void setSignatures(@Nullable Signature[] signatures) { - this.signatures = signatures; + throw new UnsupportedOperationException(); } /** @@ -146,7 +144,8 @@ public class InstallSessionParams implements Parcelable { /** * Optionally set an icon representing the app being installed. This should - * be at least {@link android.R.dimen#app_icon_size} in both dimensions. + * be roughly {@link ActivityManager#getLauncherLargeIconSize()} in both + * dimensions. */ public void setAppIcon(@Nullable Bitmap appIcon) { this.appIcon = appIcon; @@ -156,7 +155,7 @@ public class InstallSessionParams implements Parcelable { * Optionally set a label representing the app being installed. */ public void setAppLabel(@Nullable CharSequence appLabel) { - this.appLabel = appLabel; + this.appLabel = (appLabel != null) ? appLabel.toString() : null; } /** @@ -184,7 +183,6 @@ public class InstallSessionParams implements Parcelable { pw.printPair("mode", mode); pw.printHexPair("installFlags", installFlags); pw.printPair("installLocation", installLocation); - pw.printPair("signatures", (signatures != null)); pw.printPair("sizeBytes", sizeBytes); pw.printPair("appPackageName", appPackageName); pw.printPair("appIcon", (appIcon != null)); @@ -205,11 +203,10 @@ public class InstallSessionParams implements Parcelable { dest.writeInt(mode); dest.writeInt(installFlags); dest.writeInt(installLocation); - dest.writeParcelableArray(signatures, flags); dest.writeLong(sizeBytes); dest.writeString(appPackageName); dest.writeParcelable(appIcon, flags); - dest.writeString(appLabel != null ? appLabel.toString() : null); + dest.writeString(appLabel); dest.writeParcelable(originatingUri, flags); dest.writeParcelable(referrerUri, flags); dest.writeString(abiOverride); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index a114bb8..8af827e 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -18,9 +18,10 @@ package android.content.pm; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.app.PackageInstallObserver; import android.app.PackageUninstallObserver; -import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.FileBridge; import android.os.Handler; @@ -32,7 +33,9 @@ import android.util.ExceptionUtils; import java.io.Closeable; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import java.security.MessageDigest; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -63,6 +66,27 @@ import java.util.List; * </ul> */ public class PackageInstaller { + /** + * Activity Action: Show details about a particular install session. This + * may surface actions such as pause, resume, or cancel. + * <p> + * This should always be scoped to the installer package that owns the + * session. Clients should use {@link InstallSessionInfo#getDetailsIntent()} + * to build this intent correctly. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard + * against this. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; + + /** + * An integer session ID. + * + * @see #ACTION_SESSION_DETAILS + */ + public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; + private final PackageManager mPm; private final IPackageInstaller mInstaller; private final int mUserId; @@ -180,14 +204,32 @@ public class PackageInstaller { /** * Events for observing session lifecycle. + * <p> + * A typical session lifecycle looks like this: + * <ul> + * <li>An installer creates a session to indicate pending app delivery. All + * install details are available at this point. + * <li>The installer opens the session to deliver APK data. Note that a + * session may be opened and closed multiple times as network connectivity + * changes. The installer may deliver periodic progress updates. + * <li>The installer commits or abandons the session, resulting in the + * session being finished. + * </ul> */ public static abstract class SessionCallback { /** - * New session has been created. + * New session has been created. Details about the session can be + * obtained from {@link PackageInstaller#getSessionInfo(int)}. */ public abstract void onCreated(int sessionId); /** + * Session has been opened. A session is usually opened when the + * installer is actively writing data. + */ + public abstract void onOpened(int sessionId); + + /** * Progress for given session has been updated. * <p> * Note that this progress may not directly correspond to the value @@ -198,6 +240,11 @@ public class PackageInstaller { public abstract void onProgressChanged(int sessionId, float progress); /** + * Session has been closed. + */ + public abstract void onClosed(int sessionId); + + /** * Session has completely finished, either with success or failure. */ public abstract void onFinished(int sessionId, boolean success); @@ -207,8 +254,10 @@ public class PackageInstaller { private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements Handler.Callback { private static final int MSG_SESSION_CREATED = 1; - private static final int MSG_SESSION_PROGRESS_CHANGED = 2; - private static final int MSG_SESSION_FINISHED = 3; + private static final int MSG_SESSION_OPENED = 2; + private static final int MSG_SESSION_PROGRESS_CHANGED = 3; + private static final int MSG_SESSION_CLOSED = 4; + private static final int MSG_SESSION_FINISHED = 5; final SessionCallback mCallback; final Handler mHandler; @@ -224,9 +273,15 @@ public class PackageInstaller { case MSG_SESSION_CREATED: mCallback.onCreated(msg.arg1); return true; + case MSG_SESSION_OPENED: + mCallback.onOpened(msg.arg1); + return true; case MSG_SESSION_PROGRESS_CHANGED: mCallback.onProgressChanged(msg.arg1, (float) msg.obj); return true; + case MSG_SESSION_CLOSED: + mCallback.onClosed(msg.arg1); + return true; case MSG_SESSION_FINISHED: mCallback.onFinished(msg.arg1, msg.arg2 != 0); return true; @@ -240,12 +295,22 @@ public class PackageInstaller { } @Override + public void onSessionOpened(int sessionId) { + mHandler.obtainMessage(MSG_SESSION_OPENED, sessionId, 0).sendToTarget(); + } + + @Override public void onSessionProgressChanged(int sessionId, float progress) { mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress) .sendToTarget(); } @Override + public void onSessionClosed(int sessionId) { + mHandler.obtainMessage(MSG_SESSION_CLOSED, sessionId, 0).sendToTarget(); + } + + @Override public void onSessionFinished(int sessionId, boolean success) { mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0) .sendToTarget(); @@ -373,7 +438,7 @@ public class PackageInstaller { ExceptionUtils.maybeUnwrapIOException(e); throw e; } catch (RemoteException e) { - throw new IOException(e); + throw e.rethrowAsRuntimeException(); } } @@ -391,6 +456,40 @@ public class PackageInstaller { } /** + * List all APK names contained in this session. + * <p> + * This returns all names which have been previously written through + * {@link #openWrite(String, long, long)} as part of this session. + */ + public @NonNull String[] list() { + try { + return mSession.list(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Open a stream to read an APK file from the session. + * <p> + * This is only valid for names which have been previously written + * through {@link #openWrite(String, long, long)} as part of this + * session. For example, this stream may be used to calculate a + * {@link MessageDigest} of a written APK before committing. + */ + public @NonNull InputStream openRead(@NonNull String name) throws IOException { + try { + final ParcelFileDescriptor pfd = mSession.openRead(name); + return new ParcelFileDescriptor.AutoCloseInputStream(pfd); + } catch (RuntimeException e) { + ExceptionUtils.maybeUnwrapIOException(e); + throw e; + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** * Attempt to commit everything staged in this session. This may require * user intervention, and so it may not happen immediately. The final * result of the commit will be reported through the given callback. diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index 4b5bdda..cacdf8e 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -187,7 +187,7 @@ public class PackageItemInfo { * * @hide */ - protected Drawable loadDefaultIcon(PackageManager pm) { + public Drawable loadDefaultIcon(PackageManager pm) { return pm.getDefaultActivityIcon(); } diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java index af58a8a..307e466 100644 --- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java +++ b/core/java/android/hardware/camera2/legacy/CaptureCollector.java @@ -236,6 +236,11 @@ public class CaptureCollector { Log.d(TAG, "queueRequest for request " + holder.getRequestId() + " - " + mInFlight + " requests remain in flight."); } + + if (!(h.needsJpeg || h.needsPreview)) { + throw new IllegalStateException("Request must target at least one output surface!"); + } + if (h.needsJpeg) { // Wait for all current requests to finish before queueing jpeg. while (mInFlight > 0) { @@ -259,9 +264,6 @@ public class CaptureCollector { mInFlightPreviews++; } - if (!(h.needsJpeg || h.needsPreview)) { - throw new IllegalStateException("Request must target at least one output surface!"); - } mInFlight++; return true; diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java index 633bada..986f9a8 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java @@ -27,6 +27,7 @@ import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.params.MeteringRectangle; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationDuration; import android.hardware.camera2.utils.ArrayUtils; @@ -78,6 +79,8 @@ public class LegacyMetadataMapper { private static final long APPROXIMATE_SENSOR_AREA_PX = (1 << 23); // 8 megapixels private static final long APPROXIMATE_JPEG_ENCODE_TIME_MS = 600; // 600 milliseconds + static final int UNKNOWN_MODE = -1; + /* * Development hijinks: Lie about not supporting certain capabilities * @@ -458,7 +461,22 @@ public class LegacyMetadataMapper { m.set(CONTROL_MAX_REGIONS, maxRegions); - // TODO rest of control fields + /* + * android.control.availableEffects + */ + List<String> effectModes = p.getSupportedColorEffects(); + int[] supportedEffectModes = (effectModes == null) ? new int[0] : + ArrayUtils.convertStringListToIntArray(effectModes, sLegacyEffectMode, + sEffectModes); + m.set(CONTROL_AVAILABLE_EFFECTS, supportedEffectModes); + + /* + * android.control.availableSceneModes + */ + List<String> sceneModes = p.getSupportedSceneModes(); + int[] supportedSceneModes = (sceneModes == null) ? new int[0] : + ArrayUtils.convertStringListToIntArray(sceneModes, sLegacySceneModes, sSceneModes); + m.set(CONTROL_AVAILABLE_SCENE_MODES, supportedSceneModes); } private static void mapLens(CameraMetadataNative m, Camera.Parameters p) { @@ -472,6 +490,9 @@ public class LegacyMetadataMapper { */ m.set(LENS_INFO_MINIMUM_FOCUS_DISTANCE, LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS); } + + float[] focalLengths = new float[] { p.getFocalLength() }; + m.set(LENS_INFO_AVAILABLE_FOCAL_LENGTHS, focalLengths); } private static void mapFlash(CameraMetadataNative m, Camera.Parameters p) { @@ -680,6 +701,106 @@ public class LegacyMetadataMapper { } } + private final static String[] sLegacySceneModes = { + Parameters.SCENE_MODE_AUTO, + Parameters.SCENE_MODE_ACTION, + Parameters.SCENE_MODE_PORTRAIT, + Parameters.SCENE_MODE_LANDSCAPE, + Parameters.SCENE_MODE_NIGHT, + Parameters.SCENE_MODE_NIGHT_PORTRAIT, + Parameters.SCENE_MODE_THEATRE, + Parameters.SCENE_MODE_BEACH, + Parameters.SCENE_MODE_SNOW, + Parameters.SCENE_MODE_SUNSET, + Parameters.SCENE_MODE_STEADYPHOTO, + Parameters.SCENE_MODE_FIREWORKS, + Parameters.SCENE_MODE_SPORTS, + Parameters.SCENE_MODE_PARTY, + Parameters.SCENE_MODE_CANDLELIGHT, + Parameters.SCENE_MODE_BARCODE, + }; + + private final static int[] sSceneModes = { + CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED, + CameraCharacteristics.CONTROL_SCENE_MODE_ACTION, + CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT, + CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE, + CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT, + CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT, + CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE, + CameraCharacteristics.CONTROL_SCENE_MODE_BEACH, + CameraCharacteristics.CONTROL_SCENE_MODE_SNOW, + CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET, + CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO, + CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS, + CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS, + CameraCharacteristics.CONTROL_SCENE_MODE_PARTY, + CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT, + CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE, + }; + + static int convertSceneModeFromLegacy(String mode) { + if (mode == null) { + return CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED; + } + int index = ArrayUtils.getArrayIndex(sLegacySceneModes, mode); + if (index < 0) { + return UNKNOWN_MODE; + } + return sSceneModes[index]; + } + + static String convertSceneModeToLegacy(int mode) { + int index = ArrayUtils.getArrayIndex(sSceneModes, mode); + if (index < 0) { + return null; + } + return sLegacySceneModes[index]; + } + + private final static String[] sLegacyEffectMode = { + Parameters.EFFECT_NONE, + Parameters.EFFECT_MONO, + Parameters.EFFECT_NEGATIVE, + Parameters.EFFECT_SOLARIZE, + Parameters.EFFECT_SEPIA, + Parameters.EFFECT_POSTERIZE, + Parameters.EFFECT_WHITEBOARD, + Parameters.EFFECT_BLACKBOARD, + Parameters.EFFECT_AQUA, + }; + + private final static int[] sEffectModes = { + CameraCharacteristics.CONTROL_EFFECT_MODE_OFF, + CameraCharacteristics.CONTROL_EFFECT_MODE_MONO, + CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE, + CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE, + CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA, + CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE, + CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD, + CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD, + CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA, + }; + + static int convertEffectModeFromLegacy(String mode) { + if (mode == null) { + return CameraCharacteristics.CONTROL_EFFECT_MODE_OFF; + } + int index = ArrayUtils.getArrayIndex(sLegacyEffectMode, mode); + if (index < 0) { + return UNKNOWN_MODE; + } + return sEffectModes[index]; + } + + static String convertEffectModeToLegacy(int mode) { + int index = ArrayUtils.getArrayIndex(sEffectModes, mode); + if (index < 0) { + return null; + } + return sLegacyEffectMode[index]; + } + /** * Convert the ae antibanding mode from api1 into api2. * @@ -760,6 +881,16 @@ public class LegacyMetadataMapper { LegacyRequestMapper.convertRequestMetadata(request); } + private static final int[] sAllowedTemplates = { + CameraDevice.TEMPLATE_PREVIEW, + CameraDevice.TEMPLATE_STILL_CAPTURE, + CameraDevice.TEMPLATE_RECORD, + // Disallowed templates in legacy mode: + // CameraDevice.TEMPLATE_VIDEO_SNAPSHOT, + // CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG, + // CameraDevice.TEMPLATE_MANUAL + }; + /** * Create a request template * @@ -774,7 +905,7 @@ public class LegacyMetadataMapper { */ public static CameraMetadataNative createRequestTemplate( CameraCharacteristics c, int templateId) { - if (templateId < 0 || templateId > CameraDevice.TEMPLATE_MANUAL) { + if (!ArrayUtils.contains(sAllowedTemplates, templateId)) { throw new IllegalArgumentException("templateId out of range"); } @@ -786,16 +917,58 @@ public class LegacyMetadataMapper { * to create our own templates in the framework */ + /* + * control.* + */ + if (LIE_ABOUT_AWB) { m.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO); } else { throw new AssertionError("Valid control.awbMode not implemented yet"); } + // control.aeAntibandingMode + m.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, CONTROL_AE_ANTIBANDING_MODE_AUTO); + + // control.aeExposureCompensation + m.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0); + + // control.aeLock + m.set(CaptureRequest.CONTROL_AE_LOCK, false); + + // control.aePrecaptureTrigger + m.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); + + // control.afTrigger + m.set(CaptureRequest.CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE); + + // control.awbMode + m.set(CaptureRequest.CONTROL_AWB_MODE, CONTROL_AWB_MODE_AUTO); + + // control.awbLock + m.set(CaptureRequest.CONTROL_AWB_LOCK, false); + + // control.aeRegions, control.awbRegions, control.afRegions + { + Rect activeArray = c.get(SENSOR_INFO_ACTIVE_ARRAY_SIZE); + MeteringRectangle[] activeRegions = new MeteringRectangle[] { + new MeteringRectangle(/*x*/0, /*y*/0, /*width*/activeArray.width() - 1, + /*height*/activeArray.height() - 1,/*weight*/1)}; + m.set(CaptureRequest.CONTROL_AE_REGIONS, activeRegions); + m.set(CaptureRequest.CONTROL_AWB_REGIONS, activeRegions); + m.set(CaptureRequest.CONTROL_AF_REGIONS, activeRegions); + } + + // control.captureIntent + m.set(CaptureRequest.CONTROL_CAPTURE_INTENT, templateId); + // control.aeMode m.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON); // AE is always unconditionally available in API1 devices + // control.mode + m.set(CaptureRequest.CONTROL_MODE, CONTROL_MODE_AUTO); + // control.afMode { Float minimumFocusDistance = c.get(LENS_INFO_MINIMUM_FOCUS_DISTANCE); @@ -808,11 +981,65 @@ public class LegacyMetadataMapper { } else { // If a minimum focus distance is reported; the camera must have AF afMode = CameraMetadata.CONTROL_AF_MODE_AUTO; + + if (templateId == CameraDevice.TEMPLATE_RECORD || + templateId == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) { + if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES), + CONTROL_AF_MODE_CONTINUOUS_VIDEO)) { + afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO; + } + } else if (templateId == CameraDevice.TEMPLATE_PREVIEW || + templateId == CameraDevice.TEMPLATE_STILL_CAPTURE) { + if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES), + CONTROL_AF_MODE_CONTINUOUS_PICTURE)) { + afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE; + } + } } m.set(CaptureRequest.CONTROL_AF_MODE, afMode); } + { + // control.aeTargetFpsRange + Range<Integer>[] availableFpsRange = c. + get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); + + // Pick FPS range with highest max value, tiebreak on higher min value + Range<Integer> bestRange = availableFpsRange[0]; + for (Range<Integer> r : availableFpsRange) { + if (bestRange.getUpper() < r.getUpper()) { + bestRange = r; + } else if (bestRange.getUpper() == r.getUpper() && + bestRange.getLower() < r.getLower()) { + bestRange = r; + } + } + m.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestRange); + } + + /* + * statistics.* + */ + + // statistics.faceDetectMode + m.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF); + + /* + * flash.* + */ + + // flash.mode + m.set(CaptureRequest.FLASH_MODE, FLASH_MODE_OFF); + + /* + * lens.* + */ + + // lens.focalLength + m.set(CaptureRequest.LENS_FOCAL_LENGTH, + c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0]); + // TODO: map other request template values return m; } diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java index fbfc39f..dfec9008 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java @@ -108,7 +108,12 @@ public class LegacyRequestMapper { { // aeRegions { + // Use aeRegions if available, fall back to using awbRegions if present MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS); + if (request.get(CONTROL_AWB_REGIONS) != null) { + Log.w(TAG, "convertRequestMetadata - control.awbRegions setting is not " + + "supported, ignoring value"); + } int maxNumMeteringAreas = params.getMaxNumMeteringAreas(); List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy( activeArray, zoomData, aeRegions, maxNumMeteringAreas, @@ -238,6 +243,57 @@ public class LegacyRequestMapper { + infinityFocusSupported + ", only 0.0f is supported"); } } + + // control.sceneMode, control.mode + { + // TODO: Map FACE_PRIORITY scene mode to face detection. + + if (params.getSupportedSceneModes() != null) { + int controlMode = ParamsUtils.getOrDefault(request, CONTROL_MODE, + /*defaultValue*/CONTROL_MODE_AUTO); + String modeToSet; + switch (controlMode) { + case CONTROL_MODE_USE_SCENE_MODE: { + int sceneMode = ParamsUtils.getOrDefault(request, CONTROL_SCENE_MODE, + /*defaultValue*/CONTROL_SCENE_MODE_DISABLED); + String legacySceneMode = LegacyMetadataMapper. + convertSceneModeToLegacy(sceneMode); + if (legacySceneMode != null) { + modeToSet = legacySceneMode; + } else { + modeToSet = Parameters.SCENE_MODE_AUTO; + Log.w(TAG, "Skipping unknown requested scene mode: " + sceneMode); + } + break; + } + case CONTROL_MODE_AUTO: { + modeToSet = Parameters.SCENE_MODE_AUTO; + break; + } + default: { + Log.w(TAG, "Control mode " + controlMode + + " is unsupported, defaulting to AUTO"); + modeToSet = Parameters.SCENE_MODE_AUTO; + } + } + params.setSceneMode(modeToSet); + } + } + + // control.effectMode + { + if (params.getSupportedColorEffects() != null) { + int effectMode = ParamsUtils.getOrDefault(request, CONTROL_EFFECT_MODE, + /*defaultValue*/CONTROL_EFFECT_MODE_OFF); + String legacyEffectMode = LegacyMetadataMapper.convertEffectModeToLegacy(effectMode); + if (legacyEffectMode != null) { + params.setColorEffect(legacyEffectMode); + } else { + params.setColorEffect(Parameters.EFFECT_NONE); + Log.w(TAG, "Skipping unknown requested effect mode: " + effectMode); + } + } + } } private static List<Camera.Area> convertMeteringRegionsToLegacy( diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java index 07852b9..6da5dd0 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java @@ -28,6 +28,7 @@ import android.hardware.camera2.legacy.ParameterUtils.WeightedRectangle; import android.hardware.camera2.legacy.ParameterUtils.ZoomData; import android.hardware.camera2.params.MeteringRectangle; import android.hardware.camera2.utils.ListUtils; +import android.hardware.camera2.utils.ParamsUtils; import android.util.Log; import android.util.Size; @@ -153,6 +154,51 @@ public class LegacyResultMapper { request.get(CaptureRequest.CONTROL_AWB_MODE)); } + + /* + * control.mode + */ + { + int controlMode = ParamsUtils.getOrDefault(request, CaptureRequest.CONTROL_MODE, + CONTROL_MODE_AUTO); + if (controlMode == CaptureResult.CONTROL_MODE_USE_SCENE_MODE) { + result.set(CONTROL_MODE, CONTROL_MODE_USE_SCENE_MODE); + } else { + result.set(CONTROL_MODE, CONTROL_MODE_AUTO); + } + } + + /* + * control.sceneMode + */ + { + String legacySceneMode = params.getSceneMode(); + int mode = LegacyMetadataMapper.convertSceneModeFromLegacy(legacySceneMode); + if (mode != LegacyMetadataMapper.UNKNOWN_MODE) { + result.set(CaptureResult.CONTROL_SCENE_MODE, mode); + } else { + Log.w(TAG, "Unknown scene mode " + legacySceneMode + + " returned by camera HAL, setting to disabled."); + result.set(CaptureResult.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED); + } + } + + + /* + * control.effectMode + */ + { + String legacyEffectMode = params.getColorEffect(); + int mode = LegacyMetadataMapper.convertEffectModeFromLegacy(legacyEffectMode); + if (mode != LegacyMetadataMapper.UNKNOWN_MODE) { + result.set(CaptureResult.CONTROL_EFFECT_MODE, mode); + } else { + Log.w(TAG, "Unknown effect mode " + legacyEffectMode + + " returned by camera HAL, setting to off."); + result.set(CaptureResult.CONTROL_EFFECT_MODE, CONTROL_EFFECT_MODE_OFF); + } + } + /* * flash */ diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index 0687264..3f24b2c 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -329,6 +329,9 @@ public class SurfaceTextureRenderer { mSurfaces.clear(); mConversionSurfaces.clear(); mPBufferPixels = null; + if (mSurfaceTexture != null) { + mSurfaceTexture.release(); + } mSurfaceTexture = null; } diff --git a/core/java/android/hardware/camera2/utils/ArrayUtils.java b/core/java/android/hardware/camera2/utils/ArrayUtils.java index 24c85d0..ae97079 100644 --- a/core/java/android/hardware/camera2/utils/ArrayUtils.java +++ b/core/java/android/hardware/camera2/utils/ArrayUtils.java @@ -47,6 +47,19 @@ public class ArrayUtils { return -1; } + /** Return the index of {@code needle} in the {@code array}, or else {@code -1} */ + public static int getArrayIndex(int[] array, int needle) { + if (array == null) { + return -1; + } + for (int i = 0; i < array.length; ++i) { + if (array[i] == needle) { + return i; + } + } + return -1; + } + /** * Create an {@code int[]} from the {@code List<>} by using {@code convertFrom} and * {@code convertTo} as a one-to-one map (via the index). @@ -143,6 +156,17 @@ public class ArrayUtils { return arr; } + /** + * Returns true if the given {@code array} contains the given element. + * + * @param array {@code array} to check for {@code elem} + * @param elem {@code elem} to test for + * @return {@code true} if the given element is contained + */ + public static boolean contains(int[] array, int elem) { + return getArrayIndex(array, elem) != -1; + } + private ArrayUtils() { throw new AssertionError(); } diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java index 2d7b7e1..2d82cba 100644 --- a/core/java/android/hardware/location/GeofenceHardware.java +++ b/core/java/android/hardware/location/GeofenceHardware.java @@ -16,6 +16,7 @@ package android.hardware.location; import android.location.Location; +import android.os.Build; import android.os.RemoteException; import java.lang.ref.WeakReference; @@ -60,19 +61,19 @@ public final class GeofenceHardware { public static final int MONITORING_TYPE_FUSED_HARDWARE = 1; /** - * Constant to indiciate that the monitoring system is currently + * Constant to indicate that the monitoring system is currently * available for monitoring geofences. */ public static final int MONITOR_CURRENTLY_AVAILABLE = 0; /** - * Constant to indiciate that the monitoring system is currently + * Constant to indicate that the monitoring system is currently * unavailable for monitoring geofences. */ public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1; /** - * Constant to indiciate that the monitoring system is unsupported + * Constant to indicate that the monitoring system is unsupported * for hardware geofence monitoring. */ public static final int MONITOR_UNSUPPORTED = 2; @@ -129,6 +130,33 @@ public final class GeofenceHardware { */ public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6; + // the following values must match the definitions in fused_location.h + + /** + * The constant used to indicate that the monitoring system supports GNSS. + */ + public static final int SOURCE_TECHNOLOGY_GNSS = (1<<0); + + /** + * The constant used to indicate that the monitoring system supports WiFi. + */ + public static final int SOURCE_TECHNOLOGY_WIFI = (1<<1); + + /** + * The constant used to indicate that the monitoring system supports Sensors. + */ + public static final int SOURCE_TECHNOLOGY_SENSORS = (1<<2); + + /** + * The constant used to indicate that the monitoring system supports Cell. + */ + public static final int SOURCE_TECHNOLOGY_CELL = (1<<3); + + /** + * The constant used to indicate that the monitoring system supports Bluetooth. + */ + public static final int SOURCE_TECHNOLOGY_BLUETOOTH = (1<<4); + private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper> mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>(); private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper> @@ -238,13 +266,9 @@ public final class GeofenceHardware { geofenceRequest, GeofenceHardwareCallback callback) { try { if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) { - return mService.addCircularFence(geofenceId, monitoringType, - geofenceRequest.getLatitude(), - geofenceRequest.getLongitude(), geofenceRequest.getRadius(), - geofenceRequest.getLastTransition(), - geofenceRequest.getMonitorTransitions(), - geofenceRequest.getNotificationResponsiveness(), - geofenceRequest.getUnknownTimer(), + return mService.addCircularFence( + monitoringType, + new GeofenceHardwareRequestParcelable(geofenceId, geofenceRequest), getCallbackWrapper(callback)); } else { throw new IllegalArgumentException("Geofence Request type not supported"); @@ -452,10 +476,21 @@ public final class GeofenceHardware { mCallback = new WeakReference<GeofenceHardwareMonitorCallback>(c); } - public void onMonitoringSystemChange(int monitoringType, boolean available, - Location location) { + public void onMonitoringSystemChange(GeofenceHardwareMonitorEvent event) { GeofenceHardwareMonitorCallback c = mCallback.get(); - if (c != null) c.onMonitoringSystemChange(monitoringType, available, location); + if (c == null) return; + + // report the legacy event first, so older clients are not broken + c.onMonitoringSystemChange( + event.getMonitoringType(), + event.getMonitoringStatus() == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE, + event.getLocation()); + + // and only call the updated callback on on L and above, this complies with the + // documentation of GeofenceHardwareMonitorCallback + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.L) { + c.onMonitoringSystemChange(event); + } } } diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java index 6b61690..5c7a8da 100644 --- a/core/java/android/hardware/location/GeofenceHardwareImpl.java +++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java @@ -139,8 +139,8 @@ public final class GeofenceHardwareImpl { private void updateFusedHardwareAvailability() { boolean fusedSupported; try { - fusedSupported = mFusedService.isSupported(); - } catch(RemoteException e) { + fusedSupported = (mFusedService != null ? mFusedService.isSupported() : false); + } catch (RemoteException e) { Log.e(TAG, "RemoteException calling LocationManagerService"); fusedSupported = false; } @@ -210,18 +210,20 @@ public final class GeofenceHardwareImpl { } } - public boolean addCircularFence(int geofenceId, int monitoringType, double latitude, - double longitude, double radius, int lastTransition,int monitorTransitions, - int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) { + public boolean addCircularFence( + int monitoringType, + GeofenceHardwareRequestParcelable request, + IGeofenceHardwareCallback callback) { + int geofenceId = request.getId(); + // This API is not thread safe. Operations on the same geofence need to be serialized // by upper layers if (DEBUG) { - Log.d(TAG, "addCircularFence: GeofenceId: " + geofenceId + " Latitude: " + latitude + - " Longitude: " + longitude + " Radius: " + radius + " LastTransition: " - + lastTransition + " MonitorTransition: " + monitorTransitions + - " NotificationResponsiveness: " + notificationResponsivenes + - " UnKnown Timer: " + unknownTimer + " MonitoringType: " + monitoringType); - + String message = String.format( + "addCircularFence: monitoringType=%d, %s", + monitoringType, + request); + Log.d(TAG, message); } boolean result; @@ -237,9 +239,15 @@ public final class GeofenceHardwareImpl { case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE: if (mGpsService == null) return false; try { - result = mGpsService.addCircularHardwareGeofence(geofenceId, latitude, - longitude, radius, lastTransition, monitorTransitions, - notificationResponsivenes, unknownTimer); + result = mGpsService.addCircularHardwareGeofence( + request.getId(), + request.getLatitude(), + request.getLongitude(), + request.getRadius(), + request.getLastTransition(), + request.getMonitorTransitions(), + request.getNotificationResponsiveness(), + request.getUnknownTimer()); } catch (RemoteException e) { Log.e(TAG, "AddGeofence: Remote Exception calling LocationManagerService"); result = false; @@ -249,20 +257,9 @@ public final class GeofenceHardwareImpl { if(mFusedService == null) { return false; } - GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence( - latitude, - longitude, - radius); - request.setUnknownTimer(unknownTimer); - request.setNotificationResponsiveness(notificationResponsivenes); - request.setMonitorTransitions(monitorTransitions); - request.setLastTransition(lastTransition); - - GeofenceHardwareRequestParcelable parcelableRequest = - new GeofenceHardwareRequestParcelable(geofenceId, request); try { mFusedService.addGeofences( - new GeofenceHardwareRequestParcelable[] { parcelableRequest }); + new GeofenceHardwareRequestParcelable[] { request }); result = true; } catch(RemoteException e) { Log.e(TAG, "AddGeofence: RemoteException calling LocationManagerService"); @@ -471,12 +468,14 @@ public final class GeofenceHardwareImpl { int monitoringStatus, Location location, int source) { - // TODO: use the source if needed in the future setMonitorAvailability(monitoringType, monitoringStatus); acquireWakeLock(); - Message message = mCallbacksHandler.obtainMessage(GEOFENCE_STATUS, location); - message.arg1 = monitoringStatus; - message.arg2 = monitoringType; + GeofenceHardwareMonitorEvent event = new GeofenceHardwareMonitorEvent( + monitoringType, + monitoringStatus, + source, + location); + Message message = mCallbacksHandler.obtainMessage(GEOFENCE_STATUS, event); message.sendToTarget(); } @@ -644,20 +643,17 @@ public final class GeofenceHardwareImpl { switch (msg.what) { case GEOFENCE_STATUS: - Location location = (Location) msg.obj; - int val = msg.arg1; - monitoringType = msg.arg2; - boolean available; - available = (val == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE ? - true : false); - callbackList = mCallbacks[monitoringType]; + GeofenceHardwareMonitorEvent event = (GeofenceHardwareMonitorEvent) msg.obj; + callbackList = mCallbacks[event.getMonitoringType()]; if (callbackList != null) { - if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available); + if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: " + event); - for (IGeofenceHardwareMonitorCallback c: callbackList) { + for (IGeofenceHardwareMonitorCallback c : callbackList) { try { - c.onMonitoringSystemChange(monitoringType, available, location); - } catch (RemoteException e) {} + c.onMonitoringSystemChange(event); + } catch (RemoteException e) { + Log.d(TAG, "Error reporting onMonitoringSystemChange.", e); + } } } releaseWakeLock(); diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java index b8e927e..f927027 100644 --- a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java +++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java @@ -19,19 +19,39 @@ package android.hardware.location; import android.location.Location; /** - * The callback class associated with the status change of hardware montiors + * The callback class associated with the status change of hardware monitors * in {@link GeofenceHardware} */ public abstract class GeofenceHardwareMonitorCallback { /** * The callback called when the state of a monitoring system changes. * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a - * monitoring system + * monitoring system. + * + * @deprecated use {@link #onMonitoringSystemChange(GeofenceHardwareMonitorEvent)} instead. + * NOTE: this API is will remain to be called on Android API 21 and above for backwards + * compatibility. But clients must stop implementing it when updating their code. * * @param monitoringType The type of the monitoring system. - * @param available Indicates whether the system is currenty available or not. + * @param available Indicates whether the system is currently available or not. * @param location The last known location according to the monitoring system. */ + @Deprecated public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) { } + + /** + * The callback called when the sate of a monitoring system changes. + * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a monitoring system. + * {@link GeofenceHardware#MONITOR_CURRENTLY_AVAILABLE} is an example of a monitoring status. + * {@link GeofenceHardware#SOURCE_TECHNOLOGY_GNSS} is an example of a source. + * + * This callback must be used instead of + * {@link #onMonitoringSystemChange(int, boolean, android.location.Location)}. + * + * NOTE: this API is only called on Android API 21 and above. + * + * @param event An object representing the monitoring system change event. + */ + public void onMonitoringSystemChange(GeofenceHardwareMonitorEvent event) {} } diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.aidl b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.aidl new file mode 100644 index 0000000..008953e --- /dev/null +++ b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.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.hardware.location; + +parcelable GeofenceHardwareMonitorEvent;
\ No newline at end of file diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java new file mode 100644 index 0000000..9c460d2 --- /dev/null +++ b/core/java/android/hardware/location/GeofenceHardwareMonitorEvent.java @@ -0,0 +1,116 @@ +/* + * 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.location; + +import android.location.Location; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class that represents an event for each change in the state of a monitoring system. + */ +public class GeofenceHardwareMonitorEvent implements Parcelable { + private final int mMonitoringType; + private final int mMonitoringStatus; + private final int mSourceTechnologies; + private final Location mLocation; + + public GeofenceHardwareMonitorEvent( + int monitoringType, + int monitoringStatus, + int sourceTechnologies, + Location location) { + mMonitoringType = monitoringType; + mMonitoringStatus = monitoringStatus; + mSourceTechnologies = sourceTechnologies; + mLocation = location; + } + + /** + * Returns the type of the monitoring system that has a change on its state. + */ + public int getMonitoringType() { + return mMonitoringType; + } + + /** + * Returns the new status associated with the monitoring system. + */ + public int getMonitoringStatus() { + return mMonitoringStatus; + } + + /** + * Returns the source technologies that the status is associated to. + */ + public int getSourceTechnologies() { + return mSourceTechnologies; + } + + /** + * Returns the last known location according to the monitoring system. + */ + public Location getLocation() { + return mLocation; + } + + public static final Creator<GeofenceHardwareMonitorEvent> CREATOR = + new Creator<GeofenceHardwareMonitorEvent>() { + @Override + public GeofenceHardwareMonitorEvent createFromParcel(Parcel source) { + ClassLoader classLoader = GeofenceHardwareMonitorEvent.class.getClassLoader(); + int monitoringType = source.readInt(); + int monitoringStatus = source.readInt(); + int sourceTechnologies = source.readInt(); + Location location = source.readParcelable(classLoader); + + return new GeofenceHardwareMonitorEvent( + monitoringType, + monitoringStatus, + sourceTechnologies, + location); + } + + @Override + public GeofenceHardwareMonitorEvent[] newArray(int size) { + return new GeofenceHardwareMonitorEvent[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mMonitoringType); + parcel.writeInt(mMonitoringStatus); + parcel.writeInt(mSourceTechnologies); + parcel.writeParcelable(mLocation, flags); + } + + @Override + public String toString() { + return String.format( + "GeofenceHardwareMonitorEvent: type=%d, status=%d, sources=%d, location=%s", + mMonitoringType, + mMonitoringStatus, + mSourceTechnologies, + mLocation); + } +} diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java index 796d7f8..887c4ad 100644 --- a/core/java/android/hardware/location/GeofenceHardwareRequest.java +++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java @@ -33,6 +33,7 @@ public final class GeofenceHardwareRequest { private int mMonitorTransitions = GeofenceHardware.GEOFENCE_UNCERTAIN | GeofenceHardware.GEOFENCE_ENTERED | GeofenceHardware.GEOFENCE_EXITED; private int mNotificationResponsiveness = 5000; // 5 secs + private int mSourceTechnologies = GeofenceHardware.SOURCE_TECHNOLOGY_GNSS; private void setCircularGeofence(double latitude, double longitude, double radius) { mLatitude = latitude; @@ -102,6 +103,28 @@ public final class GeofenceHardwareRequest { } /** + * Set the source technologies to use while tracking the geofence. + * The value is the bit-wise of one or several source fields defined in + * {@link GeofenceHardware}. + * + * @param sourceTechnologies The set of source technologies to use. + */ + public void setSourceTechnologies(int sourceTechnologies) { + int sourceTechnologiesAll = GeofenceHardware.SOURCE_TECHNOLOGY_GNSS + | GeofenceHardware.SOURCE_TECHNOLOGY_WIFI + | GeofenceHardware.SOURCE_TECHNOLOGY_SENSORS + | GeofenceHardware.SOURCE_TECHNOLOGY_CELL + | GeofenceHardware.SOURCE_TECHNOLOGY_BLUETOOTH; + + int sanitizedSourceTechnologies = (sourceTechnologies & sourceTechnologiesAll); + if (sanitizedSourceTechnologies == 0) { + throw new IllegalArgumentException("At least one valid source technology must be set."); + } + + mSourceTechnologies = sanitizedSourceTechnologies; + } + + /** * Returns the latitude of this geofence. */ public double getLatitude() { @@ -150,6 +173,13 @@ public final class GeofenceHardwareRequest { return mLastTransition; } + /** + * Returns the source technologies to track this geofence. + */ + public int getSourceTechnologies() { + return mSourceTechnologies; + } + int getType() { return mType; } diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java index 40e7fc4..d3311f5 100644 --- a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java +++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java @@ -98,9 +98,43 @@ public final class GeofenceHardwareRequestParcelable implements Parcelable { } /** + * Returns the source technologies to track this geofence. + */ + int getSourceTechnologies() { + return mRequest.getSourceTechnologies(); + } + + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("id="); + builder.append(mId); + builder.append(", type="); + builder.append(mRequest.getType()); + builder.append(", latitude="); + builder.append(mRequest.getLatitude()); + builder.append(", longitude="); + builder.append(mRequest.getLongitude()); + builder.append(", radius="); + builder.append(mRequest.getRadius()); + builder.append(", lastTransition="); + builder.append(mRequest.getLastTransition()); + builder.append(", unknownTimer="); + builder.append(mRequest.getUnknownTimer()); + builder.append(", monitorTransitions="); + builder.append(mRequest.getMonitorTransitions()); + builder.append(", notificationResponsiveness="); + builder.append(mRequest.getNotificationResponsiveness()); + builder.append(", sourceTechnologies="); + builder.append(mRequest.getSourceTechnologies()); + return builder.toString(); + } + + /** * Method definitions to support Parcelable operations. */ - public static final Parcelable.Creator<GeofenceHardwareRequestParcelable> CREATOR = + public static final Parcelable.Creator<GeofenceHardwareRequestParcelable> CREATOR = new Parcelable.Creator<GeofenceHardwareRequestParcelable>() { @Override public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) { @@ -120,7 +154,8 @@ public final class GeofenceHardwareRequestParcelable implements Parcelable { request.setMonitorTransitions(parcel.readInt()); request.setUnknownTimer(parcel.readInt()); request.setNotificationResponsiveness(parcel.readInt()); - + request.setSourceTechnologies(parcel.readInt()); + int id = parcel.readInt(); return new GeofenceHardwareRequestParcelable(id, request); } @@ -146,6 +181,7 @@ public final class GeofenceHardwareRequestParcelable implements Parcelable { parcel.writeInt(getMonitorTransitions()); parcel.writeInt(getUnknownTimer()); parcel.writeInt(getNotificationResponsiveness()); + parcel.writeInt(getSourceTechnologies()); parcel.writeInt(getId()); } } diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java index fb238bd..4816c5f 100644 --- a/core/java/android/hardware/location/GeofenceHardwareService.java +++ b/core/java/android/hardware/location/GeofenceHardwareService.java @@ -86,15 +86,14 @@ public class GeofenceHardwareService extends Service { return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType); } - public boolean addCircularFence(int id, int monitoringType, double lat, double longitude, - double radius, int lastTransition, int monitorTransitions, int - notificationResponsiveness, int unknownTimer, IGeofenceHardwareCallback callback) { + public boolean addCircularFence( + int monitoringType, + GeofenceHardwareRequestParcelable request, + IGeofenceHardwareCallback callback) { mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, "Location Hardware permission not granted to access hardware geofence"); checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType); - return mGeofenceHardwareImpl.addCircularFence(id, monitoringType, lat, longitude, - radius, lastTransition, monitorTransitions, notificationResponsiveness, - unknownTimer, callback); + return mGeofenceHardwareImpl.addCircularFence(monitoringType, request, callback); } public boolean removeGeofence(int id, int monitoringType) { diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl index 8900166..0e840c4 100644 --- a/core/java/android/hardware/location/IGeofenceHardware.aidl +++ b/core/java/android/hardware/location/IGeofenceHardware.aidl @@ -18,6 +18,7 @@ package android.hardware.location; import android.location.IFusedGeofenceHardware; import android.location.IGpsGeofenceHardware; +import android.hardware.location.GeofenceHardwareRequestParcelable; import android.hardware.location.IGeofenceHardwareCallback; import android.hardware.location.IGeofenceHardwareMonitorCallback; @@ -27,9 +28,10 @@ interface IGeofenceHardware { void setFusedGeofenceHardware(in IFusedGeofenceHardware service); int[] getMonitoringTypes(); int getStatusOfMonitoringType(int monitoringType); - boolean addCircularFence(int id, int monitoringType, double lat, double longitude, - double radius, int lastTransition, int monitorTransitions, - int notificationResponsiveness, int unknownTimer,in IGeofenceHardwareCallback callback); + boolean addCircularFence( + int monitoringType, + in GeofenceHardwareRequestParcelable request, + in IGeofenceHardwareCallback callback); boolean removeGeofence(int id, int monitoringType); boolean pauseGeofence(int id, int monitoringType); boolean resumeGeofence(int id, int monitoringType, int monitorTransitions); diff --git a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl index 0b6e04b..811ecd0 100644 --- a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl +++ b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl @@ -16,9 +16,10 @@ package android.hardware.location; +import android.hardware.location.GeofenceHardwareMonitorEvent; import android.location.Location; /** @hide */ oneway interface IGeofenceHardwareMonitorCallback { - void onMonitoringSystemChange(int monitoringType, boolean available, in Location location); + void onMonitoringSystemChange(in GeofenceHardwareMonitorEvent event); } diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 5e3decd..0de3f26 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -16,6 +16,7 @@ package android.net; +import android.net.NetworkBoundURLFactory; import android.net.NetworkUtils; import android.os.Parcelable; import android.os.Parcel; @@ -29,6 +30,8 @@ import java.net.SocketAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.net.URL; +import java.net.URLStreamHandler; +import java.util.concurrent.atomic.AtomicReference; import javax.net.SocketFactory; import com.android.okhttp.HostResolver; @@ -52,8 +55,8 @@ public class Network implements Parcelable { // Objects used to perform per-network operations such as getSocketFactory // and getBoundURL, and a lock to protect access to them. - private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; - private OkHttpClient mOkHttpClient = null; + private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; + private volatile OkHttpClient mOkHttpClient = null; private Object mLock = new Object(); /** @@ -174,36 +177,83 @@ public class Network implements Parcelable { * {@code Network}. */ public SocketFactory getSocketFactory() { - synchronized (mLock) { - if (mNetworkBoundSocketFactory == null) { - mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + if (mNetworkBoundSocketFactory == null) { + synchronized (mLock) { + if (mNetworkBoundSocketFactory == null) { + mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + } } } return mNetworkBoundSocketFactory; } + /** The default NetworkBoundURLFactory, used if setNetworkBoundURLFactory is never called. */ + private static final NetworkBoundURLFactory DEFAULT_URL_FACTORY = new NetworkBoundURLFactory() { + public URL getBoundURL(final Network network, URL url) throws MalformedURLException { + if (network.mOkHttpClient == null) { + synchronized (network.mLock) { + if (network.mOkHttpClient == null) { + HostResolver hostResolver = new HostResolver() { + @Override + public InetAddress[] getAllByName(String host) + throws UnknownHostException { + return network.getAllByName(host); + } + }; + network.mOkHttpClient = new OkHttpClient() + .setSocketFactory(network.getSocketFactory()) + .setHostResolver(hostResolver); + } + } + } + + String protocol = url.getProtocol(); + URLStreamHandler handler = network.mOkHttpClient.createURLStreamHandler(protocol); + if (handler == null) { + // OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if + // passed another protocol. + throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol); + } + return new URL(url, "", handler); + } + }; + + private static AtomicReference<NetworkBoundURLFactory> sNetworkBoundURLFactory = + new AtomicReference <NetworkBoundURLFactory>(DEFAULT_URL_FACTORY); + /** - * Returns a {@link URL} based on the given URL but bound to this {@code Network}. - * Note that if this {@code Network} ever disconnects, this factory and any URL object it - * produced in the past or future will cease to work. + * Returns a {@link URL} based on the given URL but bound to this {@code Network}, + * such that opening the URL will send all network traffic on this Network. + * + * Note that if this {@code Network} ever disconnects, any URL object generated by this method + * in the past or future will cease to work. + * + * The returned URL may have a {@link URLStreamHandler} explicitly set, which may not be the + * handler generated by the factory set with {@link java.net.URL#setURLStreamHandlerFactory}. To + * affect the {@code URLStreamHandler}s of URLs returned by this method, call + * {@link #setNetworkBoundURLFactory}. + * + * Because the returned URLs may have an explicit {@code URLStreamHandler} set, using them as a + * context when constructing other URLs and explicitly specifying a {@code URLStreamHandler} may + * result in URLs that are no longer bound to the same {@code Network}. + * + * The default implementation only supports {@code HTTP} and {@code HTTPS} URLs. * * @return a {@link URL} bound to this {@code Network}. */ public URL getBoundURL(URL url) throws MalformedURLException { - synchronized (mLock) { - if (mOkHttpClient == null) { - HostResolver hostResolver = new HostResolver() { - @Override - public InetAddress[] getAllByName(String host) throws UnknownHostException { - return Network.this.getAllByName(host); - } - }; - mOkHttpClient = new OkHttpClient() - .setSocketFactory(getSocketFactory()) - .setHostResolver(hostResolver); - } + return sNetworkBoundURLFactory.get().getBoundURL(this, url); + } + + /** + * Sets the {@link NetworkBoundURLFactory} to be used by future {@link #getBoundURL} calls. + * If {@code null}, clears any factory that was previously specified. + */ + public static void setNetworkBoundURLFactory(NetworkBoundURLFactory factory) { + if (factory == null) { + factory = DEFAULT_URL_FACTORY; } - return new URL(url, "", mOkHttpClient.createURLStreamHandler(url.getProtocol())); + sNetworkBoundURLFactory.set(factory); } // implement the Parcelable interface diff --git a/core/java/android/net/NetworkBoundURLFactory.java b/core/java/android/net/NetworkBoundURLFactory.java new file mode 100644 index 0000000..356100e --- /dev/null +++ b/core/java/android/net/NetworkBoundURLFactory.java @@ -0,0 +1,35 @@ +/* + * 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.net; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * An interface that describes a factory for network-specific {@link URL} objects. + */ +public interface NetworkBoundURLFactory { + /** + * Returns a {@link URL} based on the given URL but bound to the specified {@code Network}, + * such that opening the URL will send all network traffic on the specified Network. + * + * @return a {@link URL} bound to this {@code Network}. + * @throws MalformedURLException if the URL was not valid, or this factory cannot handle the + * specified URL (e.g., if it does not support the protocol of the URL). + */ + public URL getBoundURL(Network network, URL url) throws MalformedURLException; +} diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 541b700..ee4d45e 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -27,6 +27,7 @@ import android.nfc.INfcAdapterExtras; import android.nfc.INfcTag; import android.nfc.INfcCardEmulation; import android.nfc.INfcLockscreenDispatch; +import android.nfc.INfcUnlockHandler; import android.os.Bundle; /** @@ -57,4 +58,6 @@ interface INfcAdapter void setP2pModes(int initatorModes, int targetModes); void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch, in int[] techList); + void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList); + void removeNfcUnlockHandler(IBinder b); } diff --git a/core/java/android/nfc/INfcUnlockHandler.aidl b/core/java/android/nfc/INfcUnlockHandler.aidl new file mode 100644 index 0000000..e1cace9 --- /dev/null +++ b/core/java/android/nfc/INfcUnlockHandler.aidl @@ -0,0 +1,12 @@ +package android.nfc; + +import android.nfc.Tag; + +/** + * @hide + */ +interface INfcUnlockHandler { + + boolean onUnlockAttempted(in Tag tag); + +} diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index b0397d5..dde2cf1 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -20,6 +20,7 @@ import java.util.HashMap; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.app.Activity; import android.app.ActivityThread; import android.app.OnActivityPausedListener; @@ -29,7 +30,6 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.net.Uri; -import android.nfc.BeamShareData; import android.nfc.tech.MifareClassic; import android.nfc.tech.Ndef; import android.nfc.tech.NfcA; @@ -261,6 +261,7 @@ public final class NfcAdapter { public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence"; /** @hide */ + @SystemApi public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1; /** @hide */ @@ -310,6 +311,8 @@ public final class NfcAdapter { final NfcActivityManager mNfcActivityManager; final Context mContext; + final HashMap<NfcUnlockHandler, IBinder> mNfcUnlockHandlers; + final Object mLock; /** * A callback to be invoked when the system finds a tag while the foreground activity is @@ -392,6 +395,22 @@ public final class NfcAdapter { /** + * A callback to be invoked when an application has registered as a + * handler to unlock the device given an NFC tag at the lockscreen. + * @hide + */ + @SystemApi + public interface NfcUnlockHandler { + /** + * Called at the lock screen to attempt to unlock the device with the given tag. + * @param tag the detected tag, to be used to unlock the device + * @return true if the device was successfully unlocked + */ + public boolean onUnlockAttempted(Tag tag); + } + + + /** * Helper to check if this device has FEATURE_NFC, but without using * a context. * Equivalent to @@ -523,6 +542,8 @@ public final class NfcAdapter { NfcAdapter(Context context) { mContext = context; mNfcActivityManager = new NfcActivityManager(this); + mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, IBinder>(); + mLock = new Object(); } /** @@ -652,6 +673,7 @@ public final class NfcAdapter { * * @hide */ + @SystemApi public boolean enable() { try { return sService.enable(); @@ -679,7 +701,7 @@ public final class NfcAdapter { * * @hide */ - + @SystemApi public boolean disable() { try { return sService.disable(true); @@ -932,6 +954,7 @@ public final class NfcAdapter { /** * @hide */ + @SystemApi public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) { if (activity == null) { throw new NullPointerException("activity cannot be null"); @@ -1359,6 +1382,7 @@ public final class NfcAdapter { * <p>This API is for the Settings application. * @hide */ + @SystemApi public boolean enableNdefPush() { try { return sService.enableNdefPush(); @@ -1373,6 +1397,7 @@ public final class NfcAdapter { * <p>This API is for the Settings application. * @hide */ + @SystemApi public boolean disableNdefPush() { try { return sService.disableNdefPush(); @@ -1451,7 +1476,50 @@ public final class NfcAdapter { public boolean onTagDetected(Tag tag) throws RemoteException { return lockscreenDispatch.onTagDetected(tag); } - }, Tag.techListFromStrings(techList)); + }, Tag.getTechCodesFromStrings(techList)); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return false; + } catch (IllegalArgumentException e) { + Log.e(TAG, "Unable to register LockscreenDispatch", e); + return false; + } + + return true; + } + + /** + * Registers a new NFC unlock handler with the NFC service. + * + * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted + * NFC device. The handler should return true if it successfully authenticates the user and + * unlocks the keyguard. + * + * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for + * at the lockscreen. Polling for less tag technologies reduces latency, and so it is + * strongly recommended to only provide the Tag technologies that the handler is expected to + * receive. + * + * @hide + */ + @SystemApi + public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler, + String[] tagTechnologies) { + try { + INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() { + @Override + public boolean onUnlockAttempted(Tag tag) throws RemoteException { + return unlockHandler.onUnlockAttempted(tag); + } + }; + + synchronized (mLock) { + if (mNfcUnlockHandlers.containsKey(unlockHandler)) { + return true; + } + sService.addNfcUnlockHandler(iHandler, Tag.getTechCodesFromStrings(tagTechnologies)); + mNfcUnlockHandlers.put(unlockHandler, iHandler.asBinder()); + } } catch (RemoteException e) { attemptDeadServiceRecovery(e); return false; @@ -1464,6 +1532,29 @@ public final class NfcAdapter { } /** + * Removes a previously registered unlock handler. Also removes the tag technologies + * associated with the removed unlock handler. + * + * @hide + */ + @SystemApi + public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) { + try { + synchronized (mLock) { + if (mNfcUnlockHandlers.containsKey(unlockHandler)) { + sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler)); + mNfcUnlockHandlers.remove(unlockHandler); + } + + return true; + } + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return false; + } + } + + /** * @hide */ public INfcAdapterExtras getNfcAdapterExtrasInterface() { diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index 43be702..154d5a1 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -196,7 +196,7 @@ public final class Tag implements Parcelable { return strings; } - static int[] techListFromStrings(String[] techStringList) throws IllegalArgumentException { + static int[] getTechCodesFromStrings(String[] techStringList) throws IllegalArgumentException { if (techStringList == null) { throw new IllegalArgumentException("List cannot be null"); } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index afac239..c3ac012 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -61,6 +61,12 @@ public class Process { public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary"; /** + * Defines the root UID. + * @hide + */ + public static final int ROOT_UID = 0; + + /** * Defines the UID/GID under which system code runs. */ public static final int SYSTEM_UID = 1000; diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index d385131..13f93a7 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -625,8 +625,9 @@ public class UserManager { Settings.Secure.putStringForUser(context.getContentResolver(), Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); try { - mService.setUserRestrictions( - mService.getDefaultGuestRestrictions(), guest.id); + Bundle guestRestrictions = mService.getDefaultGuestRestrictions(); + guestRestrictions.putBoolean(DISALLOW_SMS, true); + mService.setUserRestrictions(guestRestrictions, guest.id); } catch (RemoteException re) { Log.w(TAG, "Could not update guest restrictions"); } diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 1d1aafb..3502b52 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -1750,7 +1750,7 @@ public class TextUtils { */ public static int getLayoutDirectionFromLocale(Locale locale) { if (locale != null && !locale.equals(Locale.ROOT)) { - final String scriptSubtag = ICU.getScript(ICU.addLikelySubtags(locale.toString())); + final String scriptSubtag = ICU.addLikelySubtags(locale).getScript(); if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale); if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) || diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index af2016c..79dbb49 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -43,7 +43,7 @@ import android.view.ViewGroup; */ public abstract class Visibility extends Transition { - private static final String PROPNAME_VISIBILITY = "android:visibility:visibility"; + static final String PROPNAME_VISIBILITY = "android:visibility:visibility"; private static final String PROPNAME_PARENT = "android:visibility:parent"; private static final String PROPNAME_SCREEN_LOCATION = "android:visibility:screenLocation"; diff --git a/core/java/android/transition/VisibilityPropagation.java b/core/java/android/transition/VisibilityPropagation.java index 0326d47..183e036 100644 --- a/core/java/android/transition/VisibilityPropagation.java +++ b/core/java/android/transition/VisibilityPropagation.java @@ -42,7 +42,11 @@ public abstract class VisibilityPropagation extends TransitionPropagation { @Override public void captureValues(TransitionValues values) { View view = values.view; - values.values.put(PROPNAME_VISIBILITY, view.getVisibility()); + Integer visibility = (Integer) values.values.get(Visibility.PROPNAME_VISIBILITY); + if (visibility == null) { + visibility = view.getVisibility(); + } + values.values.put(PROPNAME_VISIBILITY, visibility); int[] loc = new int[2]; view.getLocationOnScreen(loc); loc[0] += Math.round(view.getTranslationX()); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 5157c41..83767cb 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -150,10 +150,9 @@ interface IWindowManager void setStrictModeVisualIndicatorPreference(String enabled); /** - * Update the windowmanagers cached value of - * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled(null, userId)} + * Set whether screen capture is disabled for all windows of a specific user */ - void updateScreenCaptureDisabled(int userId); + void setScreenCaptureDisabled(int userId, boolean disabled); // These can only be called with the SET_ORIENTATION permission. /** diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index c169d35..e7b3152 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1425,6 +1425,21 @@ public abstract class Window { public void setEnterTransition(Transition transition) {} /** + * Sets the Transition that will be used to move Views out of the scene when the Window is + * preparing to close, for example after a call to + * {@link android.app.Activity#finishAfterTransition()}. The exiting + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null, + * entering Views will remain unaffected. If nothing is set, the default will be to + * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}. + * @param transition The Transition to use to move Views out of the Scene when the Window + * is preparing to close. + */ + public void setReturnTransition(Transition transition) {} + + /** * Sets the Transition that will be used to move Views out of the scene when starting a * new Activity. The exiting Views will be those that are regular Views or ViewGroups that * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend @@ -1437,6 +1452,20 @@ public abstract class Window { public void setExitTransition(Transition transition) {} /** + * Sets the Transition that will be used to move Views in to the scene when returning from + * a previously-started Activity. The entering Views will be those that are regular Views + * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions + * will extend {@link android.transition.Visibility} as exiting is governed by changing + * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, + * the views will remain unaffected. If nothing is set, the default will be to use the same + * transition as {@link #setExitTransition(android.transition.Transition)}. + * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * @param transition The Transition to use to move Views into the scene when reentering from a + * previously-started Activity. + */ + public void setReenterTransition(Transition transition) {} + + /** * Returns the transition used to move Views into the initial scene. The entering * Views will be those that are regular Views or ViewGroups that have * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend @@ -1449,6 +1478,19 @@ public abstract class Window { public Transition getEnterTransition() { return null; } /** + * Returns he Transition that will be used to move Views out of the scene when the Window is + * preparing to close, for example after a call to + * {@link android.app.Activity#finishAfterTransition()}. The exiting + * Views will be those that are regular Views or ViewGroups that have + * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend + * {@link android.transition.Visibility} as entering is governed by changing visibility from + * {@link View#VISIBLE} to {@link View#INVISIBLE}. + * @return The Transition to use to move Views out of the Scene when the Window + * is preparing to close. + */ + public Transition getReturnTransition() { return null; } + + /** * Returns the Transition that will be used to move Views out of the scene when starting a * new Activity. The exiting Views will be those that are regular Views or ViewGroups that * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend @@ -1461,6 +1503,18 @@ public abstract class Window { public Transition getExitTransition() { return null; } /** + * Returns the Transition that will be used to move Views in to the scene when returning from + * a previously-started Activity. The entering Views will be those that are regular Views + * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions + * will extend {@link android.transition.Visibility} as exiting is governed by changing + * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. + * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * @return The Transition to use to move Views into the scene when reentering from a + * previously-started Activity. + */ + public Transition getReenterTransition() { return null; } + + /** * Sets the Transition that will be used for shared elements transferred into the content * Scene. Typical Transitions will affect size and location, such as * {@link android.transition.ChangeBounds}. A null @@ -1472,6 +1526,19 @@ public abstract class Window { public void setSharedElementEnterTransition(Transition transition) {} /** + * Sets the Transition that will be used for shared elements transferred back to a + * calling Activity. Typical Transitions will affect size and location, such as + * {@link android.transition.ChangeBounds}. A null + * value will cause transferred shared elements to blink to the final position. + * If no value is set, the default will be to use the same value as + * {@link #setSharedElementEnterTransition(android.transition.Transition)}. + * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * @param transition The Transition to use for shared elements transferred out of the content + * Scene. + */ + public void setSharedElementReturnTransition(Transition transition) {} + + /** * Returns the Transition that will be used for shared elements transferred into the content * Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. * @return Transition to use for sharend elements transferred into the content Scene. @@ -1479,6 +1546,13 @@ public abstract class Window { public Transition getSharedElementEnterTransition() { return null; } /** + * Returns the Transition that will be used for shared elements transferred back to a + * calling Activity. Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * @return Transition to use for sharend elements transferred into the content Scene. + */ + public Transition getSharedElementReturnTransition() { return null; } + + /** * Sets the Transition that will be used for shared elements after starting a new Activity * before the shared elements are transferred to the called Activity. If the shared elements * must animate during the exit transition, this Transition should be used. Upon completion, @@ -1490,6 +1564,17 @@ public abstract class Window { public void setSharedElementExitTransition(Transition transition) {} /** + * Sets the Transition that will be used for shared elements reentering from a started + * Activity after it has returned the shared element to it start location. If no value + * is set, this will default to + * {@link #setSharedElementExitTransition(android.transition.Transition)}. + * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * @param transition The Transition to use for shared elements in the launching Window + * after the shared element has returned to the Window. + */ + public void setSharedElementReenterTransition(Transition transition) {} + + /** * Returns the Transition to use for shared elements in the launching Window prior * to transferring to the launched Activity's Window. * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. @@ -1500,6 +1585,16 @@ public abstract class Window { public Transition getSharedElementExitTransition() { return null; } /** + * Returns the Transition that will be used for shared elements reentering from a started + * Activity after it has returned the shared element to it start location. + * Requires {@link #FEATURE_CONTENT_TRANSITIONS}. + * + * @return the Transition that will be used for shared elements reentering from a started + * Activity after it has returned the shared element to it start location. + */ + public Transition getSharedElementReenterTransition() { return null; } + + /** * Controls how the transition set in * {@link #setEnterTransition(android.transition.Transition)} overlaps with the exit * transition of the calling Activity. When true, the transition will start as soon as possible. diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 8ea1090..682f2ae 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -100,13 +100,35 @@ public class Switch extends CompoundButton { private int mMinFlingVelocity; private float mThumbPosition; + + /** + * Width required to draw the switch track and thumb. Includes padding and + * optical bounds for both the track and thumb. + */ private int mSwitchWidth; + + /** + * Height required to draw the switch track and thumb. Includes padding and + * optical bounds for both the track and thumb. + */ private int mSwitchHeight; - private int mThumbWidth; // Does not include padding + /** + * Width of the thumb's content region. Does not include padding or + * optical bounds. + */ + private int mThumbWidth; + + /** Left bound for drawing the switch track and thumb. */ private int mSwitchLeft; + + /** Top bound for drawing the switch track and thumb. */ private int mSwitchTop; + + /** Right bound for drawing the switch track and thumb. */ private int mSwitchRight; + + /** Bottom bound for drawing the switch track and thumb. */ private int mSwitchBottom; private TextPaint mTextPaint; @@ -539,7 +561,7 @@ public class Switch extends CompoundButton { * Sets whether the on/off text should be displayed. * * @param showText {@code true} to display on/off text - * @hide + * @attr ref android.R.styleable#Switch_showText */ public void setShowText(boolean showText) { if (mShowText != showText) { @@ -550,7 +572,7 @@ public class Switch extends CompoundButton { /** * @return whether the on/off text should be displayed - * @hide + * @attr ref android.R.styleable#Switch_showText */ public boolean getShowText() { return mShowText; @@ -568,32 +590,50 @@ public class Switch extends CompoundButton { } } - final int trackHeight; final Rect padding = mTempRect; - if (mTrackDrawable != null) { - mTrackDrawable.getPadding(padding); - trackHeight = mTrackDrawable.getIntrinsicHeight(); - } else { - padding.setEmpty(); - trackHeight = 0; - } - final int thumbWidth; final int thumbHeight; if (mThumbDrawable != null) { - thumbWidth = mThumbDrawable.getIntrinsicWidth(); + // Cached thumb width does not include padding. + mThumbDrawable.getPadding(padding); + thumbWidth = mThumbDrawable.getIntrinsicWidth() - padding.left - padding.right; thumbHeight = mThumbDrawable.getIntrinsicHeight(); } else { thumbWidth = 0; thumbHeight = 0; } - final int maxTextWidth = mShowText ? Math.max(mOnLayout.getWidth(), mOffLayout.getWidth()) - + mThumbTextPadding * 2 : 0; + final int maxTextWidth; + if (mShowText) { + maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth()) + + mThumbTextPadding * 2; + } else { + maxTextWidth = 0; + } + mThumbWidth = Math.max(maxTextWidth, thumbWidth); + final int trackHeight; + if (mTrackDrawable != null) { + mTrackDrawable.getPadding(padding); + trackHeight = mTrackDrawable.getIntrinsicHeight(); + } else { + padding.setEmpty(); + trackHeight = 0; + } + + // Adjust left and right padding to ensure there's enough room for the + // thumb's padding (when present). + int paddingLeft = padding.left; + int paddingRight = padding.right; + if (mThumbDrawable != null) { + final Insets inset = mThumbDrawable.getOpticalInsets(); + paddingLeft = Math.max(paddingLeft, inset.left); + paddingRight = Math.max(paddingRight, inset.right); + } + final int switchWidth = Math.max(mSwitchMinWidth, - 2 * mThumbWidth + padding.left + padding.right); + 2 * mThumbWidth + paddingLeft + paddingRight); final int switchHeight = Math.max(trackHeight, thumbHeight); mSwitchWidth = switchWidth; mSwitchHeight = switchHeight; @@ -806,19 +846,33 @@ public class Switch extends CompoundButton { protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - int switchRight; - int switchLeft; + int opticalInsetLeft = 0; + int opticalInsetRight = 0; + if (mThumbDrawable != null) { + final Rect trackPadding = mTempRect; + if (mTrackDrawable != null) { + mTrackDrawable.getPadding(trackPadding); + } else { + trackPadding.setEmpty(); + } + + final Insets insets = mThumbDrawable.getOpticalInsets(); + opticalInsetLeft = Math.max(0, insets.left - trackPadding.left); + opticalInsetRight = Math.max(0, insets.right - trackPadding.right); + } + final int switchRight; + final int switchLeft; if (isLayoutRtl()) { - switchLeft = getPaddingLeft(); - switchRight = switchLeft + mSwitchWidth; + switchLeft = getPaddingLeft() + opticalInsetLeft; + switchRight = switchLeft + mSwitchWidth - opticalInsetLeft - opticalInsetRight; } else { - switchRight = getWidth() - getPaddingRight(); - switchLeft = switchRight - mSwitchWidth; + switchRight = getWidth() - getPaddingRight() - opticalInsetRight; + switchLeft = switchRight - mSwitchWidth + opticalInsetLeft + opticalInsetRight; } - int switchTop = 0; - int switchBottom = 0; + final int switchTop; + final int switchBottom; switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) { default: case Gravity.TOP: @@ -847,27 +901,55 @@ public class Switch extends CompoundButton { @Override public void draw(Canvas c) { final Rect padding = mTempRect; - - // Layout the track. final int switchLeft = mSwitchLeft; final int switchTop = mSwitchTop; final int switchRight = mSwitchRight; final int switchBottom = mSwitchBottom; - if (mTrackDrawable != null) { - mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom); - mTrackDrawable.getPadding(padding); + + int thumbInitialLeft = switchLeft + getThumbOffset(); + + final Insets thumbInsets; + if (mThumbDrawable != null) { + thumbInsets = mThumbDrawable.getOpticalInsets(); + } else { + thumbInsets = Insets.NONE; } - final int switchInnerLeft = switchLeft + padding.left; + // Layout the track. + if (mTrackDrawable != null) { + mTrackDrawable.getPadding(padding); - // Relies on mTempRect, MUST be called first! - final int thumbPos = getThumbOffset(); + // Adjust thumb position for track padding. + thumbInitialLeft += padding.left; + + // If necessary, offset by the optical insets of the thumb asset. + int trackLeft = switchLeft; + int trackTop = switchTop; + int trackRight = switchRight; + int trackBottom = switchBottom; + if (thumbInsets != Insets.NONE) { + if (thumbInsets.left > padding.left) { + trackLeft += thumbInsets.left - padding.left; + } + if (thumbInsets.top > padding.top) { + trackTop += thumbInsets.top - padding.top; + } + if (thumbInsets.right > padding.right) { + trackRight -= thumbInsets.right - padding.right; + } + if (thumbInsets.bottom > padding.bottom) { + trackBottom -= thumbInsets.bottom - padding.bottom; + } + } + mTrackDrawable.setBounds(trackLeft, trackTop, trackRight, trackBottom); + } // Layout the thumb. if (mThumbDrawable != null) { mThumbDrawable.getPadding(padding); - final int thumbLeft = switchInnerLeft - padding.left + thumbPos; - final int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + padding.right; + + final int thumbLeft = thumbInitialLeft - padding.left; + final int thumbRight = thumbInitialLeft + mThumbWidth + padding.right; mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom); final Drawable background = getBackground(); @@ -894,9 +976,7 @@ public class Switch extends CompoundButton { final int switchTop = mSwitchTop; final int switchBottom = mSwitchBottom; - final int switchInnerLeft = mSwitchLeft + padding.left; final int switchInnerTop = switchTop + padding.top; - final int switchInnerRight = mSwitchRight - padding.right; final int switchInnerBottom = switchBottom - padding.bottom; final Drawable thumbDrawable = mThumbDrawable; @@ -919,7 +999,6 @@ public class Switch extends CompoundButton { final int saveCount = canvas.save(); if (thumbDrawable != null) { - canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom); thumbDrawable.draw(canvas); } @@ -974,7 +1053,7 @@ public class Switch extends CompoundButton { /** * Translates thumb position to offset according to current RTL setting and - * thumb scroll range. + * thumb scroll range. Accounts for both track and thumb padding. * * @return thumb offset */ @@ -990,8 +1069,18 @@ public class Switch extends CompoundButton { private int getThumbScrollRange() { if (mTrackDrawable != null) { - mTrackDrawable.getPadding(mTempRect); - return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right; + final Rect padding = mTempRect; + mTrackDrawable.getPadding(padding); + + final Insets insets; + if (mThumbDrawable != null) { + insets = mThumbDrawable.getOpticalInsets(); + } else { + insets = Insets.NONE; + } + + return mSwitchWidth - mThumbWidth - padding.left - padding.right + - insets.left - insets.right; } else { return 0; } diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java index dca9921..7db70ba 100644 --- a/core/java/com/android/internal/util/XmlUtils.java +++ b/core/java/com/android/internal/util/XmlUtils.java @@ -16,12 +16,18 @@ package com.android.internal.util; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap.CompressFormat; +import android.net.Uri; +import android.util.Base64; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -1415,6 +1421,20 @@ public class XmlUtils { out.attribute(null, name, Long.toString(value)); } + public static float readFloatAttribute(XmlPullParser in, String name) throws IOException { + final String value = in.getAttributeValue(null, name); + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + throw new ProtocolException("problem parsing " + name + "=" + value + " as long"); + } + } + + public static void writeFloatAttribute(XmlSerializer out, String name, float value) + throws IOException { + out.attribute(null, name, Float.toString(value)); + } + public static boolean readBooleanAttribute(XmlPullParser in, String name) { final String value = in.getAttributeValue(null, name); return Boolean.parseBoolean(value); @@ -1425,6 +1445,63 @@ public class XmlUtils { out.attribute(null, name, Boolean.toString(value)); } + public static Uri readUriAttribute(XmlPullParser in, String name) { + final String value = in.getAttributeValue(null, name); + return (value != null) ? Uri.parse(value) : null; + } + + public static void writeUriAttribute(XmlSerializer out, String name, Uri value) + throws IOException { + if (value != null) { + out.attribute(null, name, value.toString()); + } + } + + public static String readStringAttribute(XmlPullParser in, String name) { + return in.getAttributeValue(null, name); + } + + public static void writeStringAttribute(XmlSerializer out, String name, String value) + throws IOException { + if (value != null) { + out.attribute(null, name, value); + } + } + + public static byte[] readByteArrayAttribute(XmlPullParser in, String name) { + final String value = in.getAttributeValue(null, name); + if (value != null) { + return Base64.decode(value, Base64.DEFAULT); + } else { + return null; + } + } + + public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value) + throws IOException { + if (value != null) { + out.attribute(null, name, Base64.encodeToString(value, Base64.DEFAULT)); + } + } + + public static Bitmap readBitmapAttribute(XmlPullParser in, String name) { + final byte[] value = readByteArrayAttribute(in, name); + if (value != null) { + return BitmapFactory.decodeByteArray(value, 0, value.length); + } else { + return null; + } + } + + public static void writeBitmapAttribute(XmlSerializer out, String name, Bitmap value) + throws IOException { + if (value != null) { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + value.compress(CompressFormat.PNG, 90, os); + writeByteArrayAttribute(out, name, os.toByteArray()); + } + } + /** @hide */ public interface WriteMapCallback { /** diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp index 47f72c4..b00e1ab 100644 --- a/core/jni/android/graphics/MinikinUtils.cpp +++ b/core/jni/android/graphics/MinikinUtils.cpp @@ -59,6 +59,7 @@ void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, T minikinPaint.skewX = paint->getTextSkewX(); minikinPaint.letterSpacing = paint->getLetterSpacing(); minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint); + minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings(); layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint); } diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 2b0d68c..235e4f2 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -428,6 +428,16 @@ public: paint->setLetterSpacing(letterSpacing); } + static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + if (!settings) + paint->setFontFeatureSettings(std::string()); + else { + ScopedUtfChars settingsChars(env, settings); + paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size())); + } + } + static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) { const int kElegantTop = 2500; const int kElegantBottom = -1000; @@ -987,6 +997,7 @@ static JNINativeMethod methods[] = { {"setTextSkewX","(F)V", (void*) PaintGlue::setTextSkewX}, {"native_getLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing}, {"native_setLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing}, + {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, {"ascent","()F", (void*) PaintGlue::ascent}, {"descent","()F", (void*) PaintGlue::descent}, {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h index 7235cc4..efc65be 100644 --- a/core/jni/android/graphics/Paint.h +++ b/core/jni/android/graphics/Paint.h @@ -18,6 +18,7 @@ #define ANDROID_GRAPHICS_PAINT_H #include <SkPaint.h> +#include <string> namespace android { @@ -42,8 +43,17 @@ public: return mLetterSpacing; } + void setFontFeatureSettings(const std::string &fontFeatureSettings) { + mFontFeatureSettings = fontFeatureSettings; + } + + std::string getFontFeatureSettings() const { + return mFontFeatureSettings; + } + private: float mLetterSpacing; + std::string mFontFeatureSettings; }; } // namespace android diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp index ff2bbc5..05020d2 100644 --- a/core/jni/android/graphics/PaintImpl.cpp +++ b/core/jni/android/graphics/PaintImpl.cpp @@ -23,11 +23,11 @@ namespace android { Paint::Paint() : SkPaint(), - mLetterSpacing(0) { + mLetterSpacing(0), mFontFeatureSettings() { } Paint::Paint(const Paint& paint) : SkPaint(paint), - mLetterSpacing(0) { + mLetterSpacing(0), mFontFeatureSettings() { } Paint::~Paint() { @@ -36,12 +36,14 @@ Paint::~Paint() { Paint& Paint::operator=(const Paint& other) { SkPaint::operator=(other); mLetterSpacing = other.mLetterSpacing; + mFontFeatureSettings = other.mFontFeatureSettings; return *this; } bool operator==(const Paint& a, const Paint& b) { return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) - && a.mLetterSpacing == b.mLetterSpacing; + && a.mLetterSpacing == b.mLetterSpacing + && a.mFontFeatureSettings == b.mFontFeatureSettings; } } diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp index d214575..630999c 100644 --- a/core/jni/android/graphics/Picture.cpp +++ b/core/jni/android/graphics/Picture.cpp @@ -42,6 +42,10 @@ Canvas* Picture::beginRecording(int width, int height) { mWidth = width; mHeight = height; SkCanvas* canvas = mRecorder->beginRecording(width, height, NULL, 0); + // the java side will wrap this guy in a Canvas.java, which will call + // unref in its finalizer, so we have to ref it here, so that both that + // Canvas.java and our picture can both be owners + canvas->ref(); return Canvas::create_canvas(canvas); } diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_000.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_000.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..9076900 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00001.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..3c72bf8 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00002.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..d31e113 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00003.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..d0c693e --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00004.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..dfa19b4 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00005.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..151f205 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00006.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..ad3ee2c --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00007.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..43d66d7 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00008.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..13e4f8b --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00009.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..a09b6b2 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00010.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..be02e53 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00011.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..655d387 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_00012.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_001.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_001.png Binary files differdeleted file mode 100644 index e062f61..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_002.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_002.png Binary files differdeleted file mode 100644 index 7737646..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_003.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_003.png Binary files differdeleted file mode 100644 index 65ff45e..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_004.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_004.png Binary files differdeleted file mode 100644 index 11aaec0..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_005.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_005.png Binary files differdeleted file mode 100644 index 9e1b60f..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_006.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_006.png Binary files differdeleted file mode 100644 index 1e45687..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_007.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_007.png Binary files differdeleted file mode 100644 index 1e45687..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_008.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_008.png Binary files differdeleted file mode 100644 index 6c48456..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_009.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_009.png Binary files differdeleted file mode 100644 index a4d084b..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_010.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_010.png Binary files differdeleted file mode 100644 index 1e1a1b0..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_011.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_011.png Binary files differdeleted file mode 100644 index 1e1a1b0..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_012.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_012.png Binary files differdeleted file mode 100644 index 1e1a1b0..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_013.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_013.png Binary files differdeleted file mode 100644 index 1e1a1b0..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_014.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_014.png Binary files differdeleted file mode 100644 index 1e1a1b0..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_000.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_000.png Binary files differdeleted file mode 100644 index cf09f97..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..e870a0a --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00001.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..1d8f805 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00002.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..d348871 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00003.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..941e91e --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00004.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..adee78d --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00005.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..e6b4ca3 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00006.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..6c2bc0d --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00007.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..763833c --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00008.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..9a87fbc --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00009.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..6ccf70b --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00010.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..d1c14a5 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00011.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..c2290f0 --- /dev/null +++ b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_00012.9.png diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_001.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_001.png Binary files differdeleted file mode 100644 index 3218e66..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_002.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_002.png Binary files differdeleted file mode 100644 index 0acff03..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_003.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_003.png Binary files differdeleted file mode 100644 index c93adf4..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_004.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_004.png Binary files differdeleted file mode 100644 index 5d8ddc96..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_005.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_005.png Binary files differdeleted file mode 100644 index 47206a4..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_006.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_006.png Binary files differdeleted file mode 100644 index 7d6a91f..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_007.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_007.png Binary files differdeleted file mode 100644 index e062f61..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_008.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_008.png Binary files differdeleted file mode 100644 index b0f0dde..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_009.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_009.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_010.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_010.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_011.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_011.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_012.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_012.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_013.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_013.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_014.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_014.png Binary files differdeleted file mode 100644 index c54f8d7..0000000 --- a/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-hdpi/ic_corp_icon.png b/core/res/res/drawable-hdpi/ic_corp_icon.png Binary files differindex fc986fe..829962c 100644 --- a/core/res/res/drawable-hdpi/ic_corp_icon.png +++ b/core/res/res/drawable-hdpi/ic_corp_icon.png diff --git a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png Binary files differindex ac1fc23..0ebe65e 100644 --- a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png +++ b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_000.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_000.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..0238898 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00001.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..ada1be9 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00002.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..82aec64 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00003.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..1c6ea9f --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00004.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..ac11400 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00005.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..2025972 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00006.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..7420fd8 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00007.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..1f40832 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00008.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..cf58e44 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00009.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..930a280 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00010.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..ed9bc37 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00011.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..cddb5b0 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_00012.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_001.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_001.png Binary files differdeleted file mode 100644 index 3617168..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_002.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_002.png Binary files differdeleted file mode 100644 index e4366f4..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_003.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_003.png Binary files differdeleted file mode 100644 index ea4533b..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_004.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_004.png Binary files differdeleted file mode 100644 index 94aedbb..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_005.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_005.png Binary files differdeleted file mode 100644 index ef84578..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_006.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_006.png Binary files differdeleted file mode 100644 index 4de2321..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_007.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_007.png Binary files differdeleted file mode 100644 index 4de2321..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_008.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_008.png Binary files differdeleted file mode 100644 index d62fbd5..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_009.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_009.png Binary files differdeleted file mode 100644 index 3d87c4e..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_010.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_010.png Binary files differdeleted file mode 100644 index 536ed46..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_011.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_011.png Binary files differdeleted file mode 100644 index 536ed46..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_012.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_012.png Binary files differdeleted file mode 100644 index 536ed46..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_013.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_013.png Binary files differdeleted file mode 100644 index 536ed46..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_014.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_014.png Binary files differdeleted file mode 100644 index 536ed46..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_000.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_000.png Binary files differdeleted file mode 100644 index f5b660d..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..bc1f979 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00001.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..e6fdbcc --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00002.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..3d60b43 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00003.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..b9afdc2 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00004.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..c3c8bf2 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00005.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..1c7e5e1 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00006.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..6329b73 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00007.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..424202c --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00008.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..313beca --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00009.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..f18d86a --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00010.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..8ab48c0 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00011.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..fbc2c16 --- /dev/null +++ b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_00012.9.png diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_001.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_001.png Binary files differdeleted file mode 100644 index 9e4db6c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_002.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_002.png Binary files differdeleted file mode 100644 index 7de2128..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_003.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_003.png Binary files differdeleted file mode 100644 index 1980c2c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_004.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_004.png Binary files differdeleted file mode 100644 index 6e73ef0..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_005.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_005.png Binary files differdeleted file mode 100644 index f897392..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_006.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_006.png Binary files differdeleted file mode 100644 index 74a6ebd..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_007.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_007.png Binary files differdeleted file mode 100644 index 3617168..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_008.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_008.png Binary files differdeleted file mode 100644 index 884eb66..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_009.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_009.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_010.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_010.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_011.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_011.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_012.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_012.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_013.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_013.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_014.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_014.png Binary files differdeleted file mode 100644 index 8c3f26c..0000000 --- a/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/ic_corp_icon.png b/core/res/res/drawable-mdpi/ic_corp_icon.png Binary files differindex deb7966..44eb2d5 100644 --- a/core/res/res/drawable-mdpi/ic_corp_icon.png +++ b/core/res/res/drawable-mdpi/ic_corp_icon.png diff --git a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png Binary files differindex b6538e4..4918d33 100644 --- a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png +++ b/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_000.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..265aeb7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00001.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..2f036ad --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00002.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..bb26440 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00003.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..1b70047 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00004.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..b544b98 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00005.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..c461f3d --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00006.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..f57da14 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00007.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..22c6fbc --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00008.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..cd21ac9 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00009.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..a38dc87 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00010.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..d84a342 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00011.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..b82a2eb --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_00012.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_001.png Binary files differdeleted file mode 100644 index 7bd99fe..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_002.png Binary files differdeleted file mode 100644 index 2ef623b..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_003.png Binary files differdeleted file mode 100644 index 19db3e0..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_004.png Binary files differdeleted file mode 100644 index 984c3c5..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_005.png Binary files differdeleted file mode 100644 index 6454190..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_006.png Binary files differdeleted file mode 100644 index cee9393..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_007.png Binary files differdeleted file mode 100644 index cee9393..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_008.png Binary files differdeleted file mode 100644 index 437ffdd..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_009.png Binary files differdeleted file mode 100644 index d2e14ad..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_010.png Binary files differdeleted file mode 100644 index 4e2f5bc..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_011.png Binary files differdeleted file mode 100644 index 4e2f5bc..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_012.png Binary files differdeleted file mode 100644 index 4e2f5bc..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_013.png Binary files differdeleted file mode 100644 index 4e2f5bc..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_014.png Binary files differdeleted file mode 100644 index 4e2f5bc..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_000.png Binary files differdeleted file mode 100644 index f1bcfa3..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..6a33ebf --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00001.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..dafc250 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00002.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..27df6ff --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00003.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..cb4121c --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00004.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..c5cbb75 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00005.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..c69ef41 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00006.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..aff03d1 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00007.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..fb56ae6 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00008.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..88b9d28 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00009.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..8451958 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00010.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..6f57654 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00011.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..21bfc28 --- /dev/null +++ b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_00012.9.png diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_001.png Binary files differdeleted file mode 100644 index ede2fec..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_002.png Binary files differdeleted file mode 100644 index 94ce017..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_003.png Binary files differdeleted file mode 100644 index 647cfe3..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_004.png Binary files differdeleted file mode 100644 index b3bf923..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_005.png Binary files differdeleted file mode 100644 index ae95b2b..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_006.png Binary files differdeleted file mode 100644 index b8e4bd6..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_007.png Binary files differdeleted file mode 100644 index ec6d6d7..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_008.png Binary files differdeleted file mode 100644 index c0e493f..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_009.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_010.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_011.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_012.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_013.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_014.png Binary files differdeleted file mode 100644 index 2494fd4..0000000 --- a/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/ic_corp_icon.png b/core/res/res/drawable-xhdpi/ic_corp_icon.png Binary files differindex ec4f44b..04faf00 100644 --- a/core/res/res/drawable-xhdpi/ic_corp_icon.png +++ b/core/res/res/drawable-xhdpi/ic_corp_icon.png diff --git a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png Binary files differindex d6a0ab2..fd47f15 100644 --- a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png +++ b/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_000.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..c30cb5a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00001.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..eaba558 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00002.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..17c18c9 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00003.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..0fce07a --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00004.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..c29b837 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00005.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..ae56a41 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00006.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..85290ac --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00007.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..1e8513b --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00008.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..8810a12 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00009.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..717207f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00010.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..db046f3 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00011.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..c5c07a4 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_00012.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_001.png Binary files differdeleted file mode 100644 index eff3dd0..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_002.png Binary files differdeleted file mode 100644 index 000a23a..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_003.png Binary files differdeleted file mode 100644 index 394d661..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_004.png Binary files differdeleted file mode 100644 index 4e7311d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_005.png Binary files differdeleted file mode 100644 index d9dcf91..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_006.png Binary files differdeleted file mode 100644 index 674142e..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_007.png Binary files differdeleted file mode 100644 index 674142e..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_008.png Binary files differdeleted file mode 100644 index 9d4026a..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_009.png Binary files differdeleted file mode 100644 index bb4b426..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_010.png Binary files differdeleted file mode 100644 index a37076d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_011.png Binary files differdeleted file mode 100644 index a37076d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_012.png Binary files differdeleted file mode 100644 index a37076d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_013.png Binary files differdeleted file mode 100644 index a37076d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_014.png Binary files differdeleted file mode 100644 index a37076d..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_000.png Binary files differdeleted file mode 100644 index 22e9951..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..c9bdf1f --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00001.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..6bfd943 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00002.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..a1d3fbb --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00003.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..40c3a5b --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00004.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..26b8736 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00005.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..88c027e --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00006.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..02567c6 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00007.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..037d3bf --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00008.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..0252769 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00009.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..3ae501d --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00010.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..ecf2831 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00011.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..0877749 --- /dev/null +++ b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_00012.9.png diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_001.png Binary files differdeleted file mode 100644 index 14e6b39..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_002.png Binary files differdeleted file mode 100644 index 86b2c01..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_003.png Binary files differdeleted file mode 100644 index 1c565df..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_004.png Binary files differdeleted file mode 100644 index b825449..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_005.png Binary files differdeleted file mode 100644 index 170c234..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_006.png Binary files differdeleted file mode 100644 index 5477007..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_007.png Binary files differdeleted file mode 100644 index eff3dd0..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_008.png Binary files differdeleted file mode 100644 index e3fd96a..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_009.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_010.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_011.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_012.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_013.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_014.png Binary files differdeleted file mode 100644 index 198ac07..0000000 --- a/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/ic_corp_icon.png b/core/res/res/drawable-xxhdpi/ic_corp_icon.png Binary files differindex 6888377..68400ea 100644 --- a/core/res/res/drawable-xxhdpi/ic_corp_icon.png +++ b/core/res/res/drawable-xxhdpi/ic_corp_icon.png diff --git a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png Binary files differindex a8067cb..3e3174d 100644 --- a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png +++ b/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_000.png Binary files differdeleted file mode 100644 index 8b202c6..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..bc21279 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00001.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..b57b592 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00002.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..0fb9277 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00003.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..340722d --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00004.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..8554a76 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00005.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..a05e335 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00006.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..a5ded14 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00007.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..0300a49 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00008.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..37dd7ce --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00009.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..6bc549a --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00010.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..b026d5d --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00011.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..89238dc --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_00012.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_001.png Binary files differdeleted file mode 100644 index 3b497f3..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_002.png Binary files differdeleted file mode 100644 index 532b6de..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_003.png Binary files differdeleted file mode 100644 index 403b2fe..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_004.png Binary files differdeleted file mode 100644 index 8c5086c..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_005.png Binary files differdeleted file mode 100644 index d4870f8..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_006.png Binary files differdeleted file mode 100644 index c05adf5..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_007.png Binary files differdeleted file mode 100644 index 99b2056..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_008.png Binary files differdeleted file mode 100644 index d839358..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_009.png Binary files differdeleted file mode 100644 index 913f94d..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_010.png Binary files differdeleted file mode 100644 index 7f325b3..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_011.png Binary files differdeleted file mode 100644 index 149a9aa..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_012.png Binary files differdeleted file mode 100644 index 95c219e..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_013.png Binary files differdeleted file mode 100644 index 462a128..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_014.png Binary files differdeleted file mode 100644 index 5911d16..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_000.png Binary files differdeleted file mode 100644 index e0c6d85..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_000.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png Binary files differnew file mode 100644 index 0000000..1d309fe --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00001.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png Binary files differnew file mode 100644 index 0000000..2e58fa9 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00002.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png Binary files differnew file mode 100644 index 0000000..2ebe7a7 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00003.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png Binary files differnew file mode 100644 index 0000000..04bab76 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00004.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png Binary files differnew file mode 100644 index 0000000..3497e48 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00005.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png Binary files differnew file mode 100644 index 0000000..42333b4 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00006.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png Binary files differnew file mode 100644 index 0000000..732e175 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00007.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png Binary files differnew file mode 100644 index 0000000..12eddd8 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00008.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png Binary files differnew file mode 100644 index 0000000..95cbc61 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00009.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png Binary files differnew file mode 100644 index 0000000..105ec07 --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00010.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png Binary files differnew file mode 100644 index 0000000..fac253a --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00011.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png Binary files differnew file mode 100644 index 0000000..1b8d11c --- /dev/null +++ b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_00012.9.png diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_001.png Binary files differdeleted file mode 100644 index 5679943..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_001.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_002.png Binary files differdeleted file mode 100644 index 54b636d..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_002.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_003.png Binary files differdeleted file mode 100644 index bf9fac0..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_003.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_004.png Binary files differdeleted file mode 100644 index 25d5319..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_004.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_005.png Binary files differdeleted file mode 100644 index d2df595..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_005.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_006.png Binary files differdeleted file mode 100644 index 7700bde..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_006.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_007.png Binary files differdeleted file mode 100644 index 883f98b..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_007.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_008.png Binary files differdeleted file mode 100644 index b3b2108..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_008.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_009.png Binary files differdeleted file mode 100644 index 3aad596..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_009.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_010.png Binary files differdeleted file mode 100644 index 2017e17..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_010.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_011.png Binary files differdeleted file mode 100644 index 1fc2700..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_011.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_012.png Binary files differdeleted file mode 100644 index bb8b0f2..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_012.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_013.png Binary files differdeleted file mode 100644 index 66ab8f6..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_013.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_014.png Binary files differdeleted file mode 100644 index e3424db..0000000 --- a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_014.png +++ /dev/null diff --git a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png Binary files differindex fb07f2a..1e4a74c 100644 --- a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png +++ b/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png diff --git a/core/res/res/drawable/switch_thumb_material_anim.xml b/core/res/res/drawable/switch_thumb_material_anim.xml index 67e460a..71f6cfd 100644 --- a/core/res/res/drawable/switch_thumb_material_anim.xml +++ b/core/res/res/drawable/switch_thumb_material_anim.xml @@ -19,130 +19,116 @@ <item android:state_enabled="false" android:state_checked="true"> - <bitmap - android:src="@drawable/btn_switch_to_on_mtrl_014" + <nine-patch + android:src="@drawable/btn_switch_to_on_mtrl_00012" android:gravity="center" + android:tintMode="multiply" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" /> </item> <item android:state_enabled="false"> - <bitmap - android:src="@drawable/btn_switch_to_on_mtrl_000" + <nine-patch + android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" - android:tint="?attr/colorControlNormal" + android:tintMode="multiply" + android:tint="?attr/colorButtonNormal" android:alpha="?attr/disabledAlpha" /> </item> <item android:state_checked="true" android:id="@+id/on"> - <bitmap - android:src="@drawable/btn_switch_to_on_mtrl_014" + <nine-patch + android:src="@drawable/btn_switch_to_on_mtrl_00012" android:gravity="center" + android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:id="@+id/off"> - <bitmap - android:src="@drawable/btn_switch_to_on_mtrl_000" + <nine-patch + android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" - android:tint="?attr/colorControlNormal" /> + android:tintMode="multiply" + android:tint="?attr/colorButtonNormal" /> </item> <transition android:fromId="@+id/off" android:toId="@+id/on"> <animation-list> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_000" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_001" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_002" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_003" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_004" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_005" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_006" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_007" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_008" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_009" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_010" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_011" android:gravity="center" android:tint="?attr/colorControlActivated" /> - </item> - <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_012" android:gravity="center" android:tint="?attr/colorControlActivated" /> - </item> - <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_013" android:gravity="center" android:tint="?attr/colorControlActivated" /> - </item> - <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_on_mtrl_014" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> </animation-list> </transition> <transition android:fromId="@+id/on" android:toId="@+id/off"> <animation-list> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_000" android:gravity="center" android:tint="?attr/colorControlActivated" /> - </item> - <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_001" android:gravity="center" android:tint="?attr/colorControlActivated" /> - </item> - <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_002" android:gravity="center" android:tint="?attr/colorControlActivated" /> - </item> - <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_003" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_004" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_005" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_006" android:gravity="center" android:tint="?attr/colorControlActivated" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_007" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_008" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_009" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_010" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_011" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_012" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_013" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> <item android:duration="15"> - <bitmap android:src="@drawable/btn_switch_to_off_mtrl_014" android:gravity="center" android:tint="?attr/colorControlNormal" /> + <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" /> </item> </animation-list> </transition> diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml index 6ca2489..b400644 100644 --- a/core/res/res/drawable/switch_track_material.xml +++ b/core/res/res/drawable/switch_track_material.xml @@ -18,19 +18,21 @@ <item android:state_enabled="false" android:state_checked="true"> <nine-patch android:src="@drawable/switch_track_mtrl_alpha" android:tint="?attr/colorControlActivated" - android:alpha="?attr/disabledAlpha" /> + android:alpha="0.15" /> </item> <item android:state_enabled="false"> <nine-patch android:src="@drawable/switch_track_mtrl_alpha" - android:tint="?attr/colorControlNormal" - android:alpha="?attr/disabledAlpha" /> + android:tint="?attr/colorButtonNormal" + android:alpha="0.15" /> </item> <item android:state_checked="true"> <nine-patch android:src="@drawable/switch_track_mtrl_alpha" - android:tint="?attr/colorControlActivated" /> + android:tint="?attr/colorControlActivated" + android:alpha="0.3" /> </item> <item> <nine-patch android:src="@drawable/switch_track_mtrl_alpha" - android:tint="?attr/colorControlNormal" /> + android:tint="?attr/colorButtonNormal" + android:alpha="0.3" /> </item> </selector> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index 1af4d10..327782d 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -368,36 +368,30 @@ <item>@drawable/btn_rating_star_off_mtrl_alpha</item> <item>@drawable/btn_rating_star_on_mtrl_alpha</item> <item>@drawable/btn_star_mtrl_alpha</item> - <item>@drawable/btn_switch_to_off_mtrl_000</item> - <item>@drawable/btn_switch_to_off_mtrl_001</item> - <item>@drawable/btn_switch_to_off_mtrl_002</item> - <item>@drawable/btn_switch_to_off_mtrl_003</item> - <item>@drawable/btn_switch_to_off_mtrl_004</item> - <item>@drawable/btn_switch_to_off_mtrl_005</item> - <item>@drawable/btn_switch_to_off_mtrl_006</item> - <item>@drawable/btn_switch_to_off_mtrl_007</item> - <item>@drawable/btn_switch_to_off_mtrl_008</item> - <item>@drawable/btn_switch_to_off_mtrl_009</item> - <item>@drawable/btn_switch_to_off_mtrl_010</item> - <item>@drawable/btn_switch_to_off_mtrl_011</item> - <item>@drawable/btn_switch_to_off_mtrl_012</item> - <item>@drawable/btn_switch_to_off_mtrl_013</item> - <item>@drawable/btn_switch_to_off_mtrl_014</item> - <item>@drawable/btn_switch_to_on_mtrl_000</item> - <item>@drawable/btn_switch_to_on_mtrl_001</item> - <item>@drawable/btn_switch_to_on_mtrl_002</item> - <item>@drawable/btn_switch_to_on_mtrl_003</item> - <item>@drawable/btn_switch_to_on_mtrl_004</item> - <item>@drawable/btn_switch_to_on_mtrl_005</item> - <item>@drawable/btn_switch_to_on_mtrl_006</item> - <item>@drawable/btn_switch_to_on_mtrl_007</item> - <item>@drawable/btn_switch_to_on_mtrl_008</item> - <item>@drawable/btn_switch_to_on_mtrl_009</item> - <item>@drawable/btn_switch_to_on_mtrl_010</item> - <item>@drawable/btn_switch_to_on_mtrl_011</item> - <item>@drawable/btn_switch_to_on_mtrl_012</item> - <item>@drawable/btn_switch_to_on_mtrl_013</item> - <item>@drawable/btn_switch_to_on_mtrl_014</item> + <item>@drawable/btn_switch_to_off_mtrl_00001</item> + <item>@drawable/btn_switch_to_off_mtrl_00002</item> + <item>@drawable/btn_switch_to_off_mtrl_00003</item> + <item>@drawable/btn_switch_to_off_mtrl_00004</item> + <item>@drawable/btn_switch_to_off_mtrl_00005</item> + <item>@drawable/btn_switch_to_off_mtrl_00006</item> + <item>@drawable/btn_switch_to_off_mtrl_00007</item> + <item>@drawable/btn_switch_to_off_mtrl_00008</item> + <item>@drawable/btn_switch_to_off_mtrl_00009</item> + <item>@drawable/btn_switch_to_off_mtrl_00010</item> + <item>@drawable/btn_switch_to_off_mtrl_00011</item> + <item>@drawable/btn_switch_to_off_mtrl_00012</item> + <item>@drawable/btn_switch_to_on_mtrl_00001</item> + <item>@drawable/btn_switch_to_on_mtrl_00002</item> + <item>@drawable/btn_switch_to_on_mtrl_00003</item> + <item>@drawable/btn_switch_to_on_mtrl_00004</item> + <item>@drawable/btn_switch_to_on_mtrl_00005</item> + <item>@drawable/btn_switch_to_on_mtrl_00006</item> + <item>@drawable/btn_switch_to_on_mtrl_00007</item> + <item>@drawable/btn_switch_to_on_mtrl_00008</item> + <item>@drawable/btn_switch_to_on_mtrl_00009</item> + <item>@drawable/btn_switch_to_on_mtrl_00010</item> + <item>@drawable/btn_switch_to_on_mtrl_00011</item> + <item>@drawable/btn_switch_to_on_mtrl_00012</item> <item>@drawable/btn_toggle_indicator_mtrl_alpha</item> <item>@drawable/expander_close_mtrl_alpha</item> <item>@drawable/expander_open_mtrl_alpha</item> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 5cb3068..d07d0ab 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -464,24 +464,48 @@ <attr name="windowEnterTransition" format="reference"/> <!-- Reference to a Transition XML resource defining the desired Transition + used to move Views out of the scene when the Window is + preparing to close. Corresponds to + {@link android.view.Window#setReturnTransition(android.transition.Transition)}. --> + <attr name="windowReturnTransition" format="reference"/> + + <!-- Reference to a Transition XML resource defining the desired Transition used to move Views out of the Window's content Scene when launching a new Activity. Corresponds to {@link android.view.Window#setExitTransition(android.transition.Transition)}. --> <attr name="windowExitTransition" format="reference"/> <!-- Reference to a Transition XML resource defining the desired Transition + used to move Views in to the scene when returning from a previously-started Activity. + Corresponds to + {@link android.view.Window#setReenterTransition(android.transition.Transition)}. --> + <attr name="windowReenterTransition" format="reference"/> + + <!-- Reference to a Transition XML resource defining the desired Transition used to move shared elements transferred into the Window's initial content Scene. Corresponds to {@link android.view.Window#setSharedElementEnterTransition( android.transition.Transition)}. --> <attr name="windowSharedElementEnterTransition" format="reference"/> <!-- Reference to a Transition XML resource defining the desired Transition + used to move shared elements transferred back to a calling Activity. + Corresponds to {@link android.view.Window#setSharedElementReturnTransition( + android.transition.Transition)}. --> + <attr name="windowSharedElementReturnTransition" format="reference"/> + + <!-- Reference to a Transition XML resource defining the desired Transition used when starting a new Activity to move shared elements prior to transferring to the called Activity. Corresponds to {@link android.view.Window#setSharedElementExitTransition( android.transition.Transition)}. --> <attr name="windowSharedElementExitTransition" format="reference"/> + <!-- Reference to a Transition XML resource defining the desired Transition + used for shared elements transferred back to a calling Activity. + Corresponds to {@link android.view.Window#setSharedElementReenterTransition( + android.transition.Transition)}. --> + <attr name="windowSharedElementReenterTransition" format="reference"/> + <!-- Flag indicating whether this Window's transition should overlap with the exiting transition of the calling Activity. Corresponds to {@link android.view.Window#setAllowEnterTransitionOverlap(boolean)}. --> @@ -1751,30 +1775,54 @@ or a fraction of the screen size in that dimension. --> <attr name="windowFixedHeightMajor" format="dimension|fraction" /> <attr name="windowOutsetBottom" format="dimension" /> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition used to move Views into the initial Window's content Scene. Corresponds to {@link android.view.Window#setEnterTransition(android.transition.Transition)}. --> <attr name="windowEnterTransition"/> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition + used to move Views out of the scene when the Window is + preparing to close. Corresponds to + {@link android.view.Window#setReturnTransition(android.transition.Transition)}. --> + <attr name="windowReturnTransition"/> + + <!-- Reference to a Transition XML resource defining the desired Transition used to move Views out of the Window's content Scene when launching a new Activity. Corresponds to {@link android.view.Window#setExitTransition(android.transition.Transition)}. --> <attr name="windowExitTransition"/> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition + used to move Views in to the scene when returning from a previously-started Activity. + Corresponds to + {@link android.view.Window#setReenterTransition(android.transition.Transition)}. --> + <attr name="windowReenterTransition"/> + + <!-- Reference to a Transition XML resource defining the desired Transition used to move shared elements transferred into the Window's initial content Scene. Corresponds to {@link android.view.Window#setSharedElementEnterTransition( android.transition.Transition)}. --> <attr name="windowSharedElementEnterTransition"/> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition + used to move shared elements transferred back to a calling Activity. + Corresponds to {@link android.view.Window#setSharedElementReturnTransition( + android.transition.Transition)}. --> + <attr name="windowSharedElementReturnTransition"/> + + <!-- Reference to a Transition XML resource defining the desired Transition used when starting a new Activity to move shared elements prior to transferring to the called Activity. Corresponds to {@link android.view.Window#setSharedElementExitTransition( android.transition.Transition)}. --> <attr name="windowSharedElementExitTransition"/> + <!-- Reference to a Transition XML resource defining the desired Transition + used for shared elements transferred back to a calling Activity. + Corresponds to {@link android.view.Window#setSharedElementReenterTransition( + android.transition.Transition)}. --> + <attr name="windowSharedElementReenterTransition"/> + <!-- Flag indicating whether this Window's transition should overlap with the exiting transition of the calling Activity. Corresponds to diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 9acd4a6..d8f9665 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2264,6 +2264,11 @@ <public type="attr" name="toolbarStyle" /> <public type="attr" name="windowClipToOutline" /> <public type="attr" name="datePickerDialogTheme" /> + <public type="attr" name="showText" /> + <public type="attr" name="windowReturnTransition" /> + <public type="attr" name="windowReenterTransition" /> + <public type="attr" name="windowSharedElementReturnTransition" /> + <public type="attr" name="windowSharedElementReenterTransition" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 61dff1b..9ee377f 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -537,12 +537,9 @@ please see styles_device_defaults.xml. <style name="Widget.Material.CompoundButton.Switch"> <item name="track">@drawable/switch_track_material</item> <item name="thumb">@drawable/switch_thumb_material_anim</item> - <item name="splitTrack">true</item> <item name="switchTextAppearance">@style/TextAppearance.Material.Widget.Switch</item> <item name="textOn">@string/capital_on</item> <item name="textOff">@string/capital_off</item> - <item name="switchMinWidth">4dip</item> - <item name="switchPadding">4dip</item> <item name="background">?attr/selectableItemBackgroundBorderless</item> <item name="showText">false</item> </style> diff --git a/data/fonts/Roboto-Black.ttf b/data/fonts/Roboto-Black.ttf Binary files differindex 82bc9fc..1eb7cf2 100644 --- a/data/fonts/Roboto-Black.ttf +++ b/data/fonts/Roboto-Black.ttf diff --git a/data/fonts/Roboto-BlackItalic.ttf b/data/fonts/Roboto-BlackItalic.ttf Binary files differindex 40f8bc8..8f9da76 100644 --- a/data/fonts/Roboto-BlackItalic.ttf +++ b/data/fonts/Roboto-BlackItalic.ttf diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf Binary files differindex 2957cd8..d3a6ed9 100644 --- a/data/fonts/Roboto-Bold.ttf +++ b/data/fonts/Roboto-Bold.ttf diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf Binary files differindex 85ff2e9..49bd012 100644 --- a/data/fonts/Roboto-BoldItalic.ttf +++ b/data/fonts/Roboto-BoldItalic.ttf diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf Binary files differindex d496291..da58461 100644 --- a/data/fonts/Roboto-Italic.ttf +++ b/data/fonts/Roboto-Italic.ttf diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf Binary files differindex 1489708..9ca4e92 100644 --- a/data/fonts/Roboto-Light.ttf +++ b/data/fonts/Roboto-Light.ttf diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf Binary files differindex 2dd300e..710c14c 100644 --- a/data/fonts/Roboto-LightItalic.ttf +++ b/data/fonts/Roboto-LightItalic.ttf diff --git a/data/fonts/Roboto-Medium.ttf b/data/fonts/Roboto-Medium.ttf Binary files differindex 8a8e89d..aaa3723 100644 --- a/data/fonts/Roboto-Medium.ttf +++ b/data/fonts/Roboto-Medium.ttf diff --git a/data/fonts/Roboto-MediumItalic.ttf b/data/fonts/Roboto-MediumItalic.ttf Binary files differindex 830a471..8c2b101 100644 --- a/data/fonts/Roboto-MediumItalic.ttf +++ b/data/fonts/Roboto-MediumItalic.ttf diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf Binary files differindex f392d64..e5b0c83 100644 --- a/data/fonts/Roboto-Regular.ttf +++ b/data/fonts/Roboto-Regular.ttf diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf Binary files differindex 1b58ba4..781ef3d 100644 --- a/data/fonts/Roboto-Thin.ttf +++ b/data/fonts/Roboto-Thin.ttf diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf Binary files differindex 316a9e9..0ed5203 100644 --- a/data/fonts/Roboto-ThinItalic.ttf +++ b/data/fonts/Roboto-ThinItalic.ttf diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf Binary files differindex 194a710..9f34ffe 100644 --- a/data/fonts/RobotoCondensed-Bold.ttf +++ b/data/fonts/RobotoCondensed-Bold.ttf diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf Binary files differindex 013640f..c8dea7a 100644 --- a/data/fonts/RobotoCondensed-BoldItalic.ttf +++ b/data/fonts/RobotoCondensed-BoldItalic.ttf diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf Binary files differindex 42c48aa..09f4f5b 100644 --- a/data/fonts/RobotoCondensed-Italic.ttf +++ b/data/fonts/RobotoCondensed-Italic.ttf diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf Binary files differindex 5ca51e8..c33a3e1 100644 --- a/data/fonts/RobotoCondensed-Light.ttf +++ b/data/fonts/RobotoCondensed-Light.ttf diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf Binary files differindex b788bd7..adfefc4 100644 --- a/data/fonts/RobotoCondensed-LightItalic.ttf +++ b/data/fonts/RobotoCondensed-LightItalic.ttf diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf Binary files differindex 573100b..d750454 100644 --- a/data/fonts/RobotoCondensed-Regular.ttf +++ b/data/fonts/RobotoCondensed-Regular.ttf diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs index b770135..7cce86b 100644 --- a/docs/html/google/google_toc.cs +++ b/docs/html/google/google_toc.cs @@ -138,9 +138,6 @@ <li><a href="<?cs var:toroot?>google/play/billing/billing_admin.html"> <span class="en">Administering In-app Billing</span></a> </li> - <li><a href="<?cs var:toroot?>google/play/billing/gp-purchase-status-api.html"> - <span class="en">Purchase Status API</span></a> - </li> <li><a href="<?cs var:toroot?>google/play/billing/versions.html"> <span class="en">Version Notes</span></a> </li> @@ -205,7 +202,9 @@ <li><a href="<?cs var:toroot ?>google/play/filters.html"> <span class="en">Filters on Google Play</span></a> </li> - + <li><a href="<?cs var:toroot?>google/play/billing/gp-purchase-status-api.html"> + <span class="en">Google Play Developer API</span></a> + </li> <li><a href="<?cs var:toroot ?>google/play/publishing/multiple-apks.html"> <span class="en">Multiple APK Support</span></a> </li> diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd index d0e6dc5..3c72da1 100644 --- a/docs/html/google/play/billing/billing_subscriptions.jd +++ b/docs/html/google/play/billing/billing_subscriptions.jd @@ -24,6 +24,7 @@ directly from Google Play.</li> <li><a href="#administering">Configuring Subscriptions Items</a></li> <li><a href="#cancellation">Cancellation</a></li> <li><a href="#payment">Payment Processing</a></li> + <li><a href="#strategies">Purchase Verification Strategies</a></li> </ol> <h2>See also</h2> <ol> @@ -325,6 +326,21 @@ each recurring transaction by appending an integer as follows: </p> {@code orderId} field of the {@code INAPP_PURCHASE_DATA} JSON field (in V3) or the {@code PURCHASE_STATE_CHANGED} intent (in V2).</p> +<h2 id="strategies">Purchase Verification Strategies</h2> + +<p>In a typical scenario, your app verifies the order status for new purchases +to ensure that they are valid before granting access to the purchased +content.</p> + +<p>To verify a purchase, the app passes the purchase token and other details up +to your backend servers, which verifies them directly with Google Play using the +Purchase Status API. If the backend server determines that the purchase is +valid, it notifies the app and grants access to the content.</p> + +<p>Keep in mind that users will want the ability to use your app at any time, +including when there may be no network connection available. Make sure that your +approach to purchase verification accounts for the offline use-case.</p> + <h2 id="play-dev-api">Google Play Android Developer API</h2> <p>Google Play offers an HTTP-based API that lets you remotely query the @@ -333,4 +349,4 @@ API is designed to be used from your backend servers as a way of securely managing subscriptions, as well as extending and integrating subscriptions with other services.</p> -<p>For complete information, see <a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Purchase Status API</a>.</p>
\ No newline at end of file +<p>For complete information, see <a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Purchase Status API</a>.</p> diff --git a/docs/html/google/play/billing/gp-purchase-status-api.jd b/docs/html/google/play/billing/gp-purchase-status-api.jd index d272301..fa0c397 100644 --- a/docs/html/google/play/billing/gp-purchase-status-api.jd +++ b/docs/html/google/play/billing/gp-purchase-status-api.jd @@ -1,38 +1,114 @@ -page.title=Purchase Status API -page.tags=In-app Billing,Google Play,inapp billing,in app billing,iab,billing +page.title=Google Play Developer API +page.tags="In-app Billing", "Google Play", "inapp billing", "in app billing", "iab", "billing", "publishing" + @jd:body <div id="qv-wrapper"> <div id="qv"> <h2>In this document</h2> + <!-- TODO: Update TOC --> <ol> - <li><a href="#overview">Overview</a></li> - <li><a href="#using">Using the API</a></li> - <li><a href="#strategies">Verification Strategies</a></li> - <li><a href="#practices">Using the API Efficiently</a></li> + <li><a href="#publishing_api_overview">Publishing API</a> + <li><a href="#subscriptions_api_overview">Subscriptions and In-App + Purchases API</a></li> + <li><a href="#using">Using the API</a> + <li><a href="#edits">Staged Edits</a></li> + <li><a href="#practices">Using the API Efficiently</a> + <ol> + <li><a href="#quota">Quota</a></li> + </ol> + </li> </ol> + <h2>See also</h2> <ol> - <li><a href="https://developers.google.com/android-publisher/v1_1/">Google Play Android Developer API</a></li> + <li><a href="https://developers.google.com/android-publisher/">Google Play + Developer API</a> documentation</li> + <li><a href="https://support.google.com/googleplay/android-developer/answer/6071616">Google + Help Center</a> overview of the Google Play Developer API</li> </ol> </div> </div> -<p>Google Play provides an HTTP-based Purchase Status API that lets -you remotely query the status of a specific in-app product or subscription, -or cancel an active subscription. The API is designed to be used from your -backend servers as a way of securely managing in-app products and -subscriptions, as well as extending and integrating them with other services.</p> +<p>The Google Play Developer API is a REST-based web service that allows you to perform publishing +and app-management tasks. You can use this API to integrate your publishing +operations with your release-management process.</p> + +<p>Not all developers will need to use these APIs—in most cases you will +continue to manage your apps directly using the Google Play Developer Console. +However, if you have a large number of APKs to manage, or have to track user +purchases and subscriptions, you may find this API very useful.</p> + +<p>Using the Google Play Developer API, you can automate a variety of +app-management tasks, including:</p> + +<ul> +<li>Uploading and releasing new versions of your app</li> +<li>Editing your app Google Play Store listings, including localized text and + graphics</li> +<li>Managing your in-app product catalog, your products purchase status and your + app subscriptions</li> +</li> +</ul> + -<h2 id="overview">Overview</h2> -<p>With the Purchase Status API you can quickly retrieve the details of any -purchase using a standard GET request. In the request you supply information -about the purchase — app package name, purchase or subscription ID, -and the purchase token. The server responds with a JSON object describing -the associated purchase details, order status, developer payload, and other -information.</p> +<p>The Google Play Developer API lets you focus on designing and developing your +app, while spending less time and effort managing your releases, even as you +grow to new markets.</p> + +<p>The Google Play Developer API includes two components:</p> + +<ul> +<li>The <a href="#publishing_api_overview">Publishing API</a> lets you upload and publish + apps, and perform other publishing-related tasks.</li> +<li>The <a href="#subscriptions_api_overview">Subscriptions and In-App Purchases + API</a> lets you manage in-app purchases and subscriptions. (This was + previously known as the "Purchase Status API".)</li> +</ul> + +<h2 id="publishing_api_overview">Publishing API</h2> + +<p> +The Google Play Developer Publishing API allows you to automate frequent tasks +having to do with app distribution. This provides functions +similar to those available to a developer through the Google Play +Developer Console, such +as: +</p> + +<ul><li>Uploading new versions of an app</li> +<li>Releasing apps, by assigning APKs to various <em>Tracks</em> (alpha, beta, + staged rollout, or production)</li> +<li>Creating and modifying Google Play Store listings, including localized text + and graphics and multi-device screenshots</li></ul> + +<p>Those tasks are performed using the +<a href="#edits">edits</a> +functionality, which takes a transactional approach to making changes — +you bundle several changes into a single draft edit, then commit the changes all +at once. (None of the changes take effect until the edit is committed.)</p> + +<p class="note"><strong>Note:</strong> Not all developers will need to use this +API. All the functionality provided by the API is also available through the +Google Play +Developer Console. However, this API lets you integrate your app and listing +update process with your existing tools, which will be very useful for some +developers. In particular, if you have a large number of APKs to manage, or +localized listings in many different locales, you may find this API invaluable. +</p> + +<h2 id="subscriptions_api_overview">Subscriptions and In-App Purchases API</h2> + +<p>The API allows you to manage your app's catalog of in-app products and +subscriptions. In addition, with the Subscriptions and In-App Purchases API you +can quickly retrieve the +details of any purchase using a standard GET request. In the request you supply +information about the purchase — app package name, purchase or +subscription ID, and the purchase token. The server responds with a JSON object +describing the associated purchase details, order status, developer payload, and +other information.</p> <p>You can use the Purchase Status API in several ways, such as for reporting and reconciliation of individual orders and for verifying purchases and @@ -40,101 +116,85 @@ subscription expirations. You can also use the API to learn about cancelled orders and confirm whether in-app products have been consumed, including whether they were consumed before being cancelled.</p> -<p>For subscriptions, in addition to querying for order status and expiration, -you can use the Purchase Status API to remotely cancel a subscription. This is a -convenient way to manage cancellations on behalf of customers, without -requiring them to manage the cancellation themselves on their Android devices.</p> - -<p>If you plan to use the Purchase Status API, keep in mind that:</p> -<ul><li>You can use the API to check the status of individual items only -— bulk requests for order status are not supported at this time.</li> -<li>You can query for the details of orders placed on or after 12 June 2013, -but not for orders placed earlier.</li> -<li>You can query purchases of any item type made with the In-app -Billing v3 API, or purchases of managed items made with In-app Billing v1 and -v2. You can not use the Purchase Status API to query purchases of unmanaged items -made with In-app Billing v1 or v2.</li> -</ul> +<p class="note"><strong>Note:</strong> The Subscriptions and In-App +Purchases API does not use the new, transactional "edits" functionality used by +the <a href="#publishing_api_overview">Publishing API</a>. Methods for the +<a href="https://developers.google.com/android-publisher/api-ref/inappproducts">Inappproducts</a>, +<a href="https://developers.google.com/android-publisher/api-ref/purchases/products">Purchases.products</a>, +and <a href="https://developers.google.com/android-publisher/api-ref/purchases/subscriptions">Purchases.subscriptions</a> +resources take effect immediately. Each resource's API reference page notes +specifically whether the methods for that resource use the "edits" +model.</p> <p>The Purchase Status API is part of the <a -href="https://developers.google.com/android-publisher/v1_1/">Google Play Android -Developer API v1.1</a>, available through the Google Developers Console. The new version -of the API supersedes the v1 API, which is deprecated. If you are using the v1 -API, please migrate your operations to the v1.1 API as soon as possible.</p> - +href="https://developers.google.com/android-publisher/">Google Play Developer +API</a> v. 2.0, available through the Google Developers Console.</p> <h2 id="using">Using the API</h2> -<p>To use the API, you must first register a project at the <a -href="https://cloud.google.com/console">Google Developers Console</a> and receive -a Client ID and shared secret that your app will present when calling the -API. All calls are authenticated with OAuth 2.0.</p> +<p>To start making API calls, you’ll set up and manage the Google Play Developer +API directly from the <a href="https://play.google.com/apps/publish/">Google +Play Developer Console</a>. The API can only be managed by the owner of your +Google Play Developer account.</p> -<p>Once your app is registered, you can access the API directly, using standard -HTTP methods to retrieve and manipulate resources. The API is built on a RESTful -design that uses HTTP and JSON. so any standard web stack can send requests and -parse the responses. However, if you don’t want to send HTTP requests and parse -responses manually, you can access the API using the Google APIs Client -Libraries, which provide better language integration, improved security, -and support for making calls that require user authorization.</p> +<p>To access the API, you'll need to:</p> -<p>For more information about the API and how to access it through the Google -APIs Client Libraries, see the documentation at:</p> - -<p style="margin-left:1.5em;"><a -href="https://developers.google.com/android-publisher/v1_1/">https://developers. -google.com/android-publisher/v1_1/</a></p> - -<h3 id="quota">Quota</h3> - -<p>Applications using the Google Play Android Developer API are limited to an -initial courtesy usage quota of <strong>200,000 requests per day</strong> (per -application). This should provide enough access for normal -subscription-validation needs, assuming that you follow the recommendation in -this section.</p> - -<p>If you need to request a higher limit for your application, see the -instructions in the <a -href="https://developers.google.com/console/help/new/#trafficcontrols">Google Developers -Console Help</a>. -Also, please read the section below on design best practices for minimizing your -use of the API.</p> +<ol><li>Set up a new or existing API project</li> +<li>Set up one or more authorized clients, which can be either: +<ul> + <li><a href="https://developers.google.com/accounts/docs/OAuth2">OAuth + clients</a></li> + <li><a href="https://developers.google.com/accounts/docs/OAuth2ServiceAccount"> + service account</a></li> +</ul></li></ol> -<h3 id="auth">Authorization</h3> +<p>For full details, see the Google Play Developer API +<a href="https://developers.google.com/android-publisher/getting_started">Getting +Started</a> page.</p> -<p>Calls to the Google Play Android Developer API require authorization. Google -uses the OAuth 2.0 protocol to allow authorized applications to access user -data. To learn more, see <a -href="https://developers.google.com/android-publisher/authorization">Authorization</a> -in the Google Play Android Developer API documentation.</p> +<h2 id="edits">Staged Edits</h2> -<h2 id="strategies">Purchase Verification Strategies</h2> +<p>The Google Play Developer Publishing API Edits methods allow you to prepare +and commit changes to your Google Play apps. Once your update is ready to go, +you can deploy it with a single operation. The changes you can make include:</p> -<p>In a typical scenario, your app verifies the order status for new purchases -to ensure that they are valid before granting access to the purchased content.</p> +<ul> + <li>Uploading one or more APKs</li> + <li>Assigning different APKs to different “tracks”: alpha, beta, staged + rollout, and production</li> + <li>Creating and modifying localized store listings for the app</li> + <li>Uploading screenshots and other images for the app’s store listings</li> +</ul> -<p>To verify a purchase, the app passes the purchase token and other details up -to your backend servers, which verifies them directly with Google Play using the -Purchase Status API. For security reasons, the app should not normally attempt to verify -the purchase itself using the Purchase Status API.</p> +<p>Once all the desired changes have been staged, they are all committed with a +single operation.</p> -<p>If the backend server determines that the purchase is valid, it notifies the -app and grants access to the content. For improved performance, the backend servers -should store the purchase details and order status in a local database, updated at -intervals or as-needed.</p> +<p>For full details on staged edits, see the Google Play Developer API +<a href="https://developers.google.com/android-publisher/edits/">Edits</a> +page.</p> -<p>Keep in mind that users will want the ability to use your app at any time, including -when there may be no network connection available. Make sure that your approach to -purchase verification accounts for the offline use-case.</p> +<p class="note"><strong>Note:</strong> The new, transactional "edits" +functionality is only used by the <a href="#publishing_api_overview">Publishing +API</a>. Methods for the <a href="#subscriptions_api_overview">Subscriptions and +In-App Purchases API</a> take effect immediately. Each resource's API reference +page notes specifically whether the methods for that resource use the "edits" +model.</p> <h2 id="practices">Using the API Efficiently</h2> -<p>Access to the Google Play Android Developer API is regulated to help ensure a -high-performance environment for all applications that use it. While you can +<p>Access to the Google Play Developer API is regulated to help ensure a +high-performance environment for all applications that use it (as described in +<a href="#quota">Quota</a>). While you can request a higher daily quota for your application, we highly recommend that you -minimize your access using the techniques below. </p> +minimize your access using these techniques: </p> <ul> + <li><em>Limit the number of app updates</em> — Do not publish alpha or beta + updates more frequently than once a day. (Production apps should be updated + even less frequently than that.) Every update costs your users time and + possibly money. If you update too frequently, users will start ignoring + updates, or even uninstall the product. (Of course, if there's a major problem + with your app, go ahead and fix it.)</li> <li><em>Query the Purchase Status API for new purchases only</em> — At purchase, your app can pass the purchase token and other details to your backend servers, which can use the Purchase Status API to verify the purchase.</li> @@ -163,6 +223,15 @@ minimize your access using the techniques below. </p> </ul> <p>By following those general guidelines, your implementation will offer the -best possible performance for users and minimize use of the <a -href="https://developers.google.com/android-publisher/v1_1/">Google Play Android -Developer API</a>.</p> +best possible performance for users.</p> + +<h3 id="quota">Quota</h3> + +<p>Applications using the Google Play Developer API are limited to an +initial courtesy usage quota of <strong>200,000 requests per day</strong> (per +application). This should provide enough access for publishing activities and +normal subscription-validation needs.</p> + +<p>If you need to request a higher limit for your application, use the "Request +more" link on the <strong>Quotas</strong> +pane of the Google Developers Console.</p> diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd index dce20cb..18b1523 100644 --- a/docs/html/google/play/billing/index.jd +++ b/docs/html/google/play/billing/index.jd @@ -14,7 +14,11 @@ and features, and more. You can use In-app Billing to sell products as</p> <div class="sidebox"> <h2><strong>New in In-App Billing</strong></h2> <ul> - <li><strong>Purchase Status API</strong>—The <a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Purchase Status API</a> lets you query the status of in-app product or subscription purchases. </li> + <li><strong>Google Play Developer API</strong>—The + <a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Google + Play Developer API</a> allows you to perform a number of publishing and + app-management tasks. It includes the functionality previously known as the + <em>Purchase Status API.</em> </li> <li><strong>In-app Billing Version 3</strong>—The <a href="{@docRoot}google/play/billing/api.html">latest version</a> of In-app Billing features a synchronous API that is easier to implement and lets you manage in-app products and subscriptions more effectively.</li> <li><strong>Subscriptions now supported in Version 3</strong>—You can query and launch purchase flows for subscription items using the V3 API.</li> <li><strong>Free trials</strong>—You can now offer users a configurable <a href="/google/play/billing/v2/billing_subscriptions.html#trials">free trial period</a> for your in-app subscriptions. You can set up trials with a simple change in the Developer Console—no change to your app code is needed.</li> diff --git a/docs/html/google/play/dist.jd b/docs/html/google/play/dist.jd index b4efe40..f1ad834 100644 --- a/docs/html/google/play/dist.jd +++ b/docs/html/google/play/dist.jd @@ -49,4 +49,12 @@ page.title=Google Play Distribution <p>Protect your revenue streams and integrate policies for usage into your app. </p><a href="{@docRoot}google/play/licensing/index.html">Learn more »</a> </div> -</div>
\ No newline at end of file + <div class="layout-content-col span-6"> + <h4> + Google Play Developer API + </h4> + <p>Integrate your publishing operations with your release-management + process. + </p><a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Learn more »</a> + </div> +</div> diff --git a/docs/html/preview/preview_toc.cs b/docs/html/preview/preview_toc.cs index a505905..819976e 100644 --- a/docs/html/preview/preview_toc.cs +++ b/docs/html/preview/preview_toc.cs @@ -68,6 +68,8 @@ Recommendations</a></li> </ul> </li> + <li><a href="<?cs var:toroot ?>preview/tv/tif/index.html"> + TV Input Framework</a></li> <li><a href="<?cs var:toroot ?>preview/tv/games/index.html"> Games on TV</a></li> <li><a href="<?cs var:toroot ?>preview/tv/start/hardware-features.html"> diff --git a/docs/html/preview/tv/adt-1/index.jd b/docs/html/preview/tv/adt-1/index.jd index 882f421..b37a55a 100644 --- a/docs/html/preview/tv/adt-1/index.jd +++ b/docs/html/preview/tv/adt-1/index.jd @@ -52,16 +52,16 @@ Android TV platform.</p> </p> <p>Unplug the included power cable from the back of ADT-1. The device does not have an on/off switch. However, ADT-1 will begin sleeping (daydream) based on user settings in - <strong>Settings > Display > Daydream</strong>. + <strong>Settings > Device > Display > Daydream</strong>. </p> <p> <strong>How do I connect to the network?</strong> </p> <p>ADT-1 has both wireless and Ethernet for connecting to your network. To change your wireless - network, go to <strong>Settings -> Wi-Fi</strong>. To use an Ethernet network connection, - simply plug an Ethernet cable (that is connected to your network) into the port on the back of - ADT-1.</p> + network, go to <strong>Settings > Device > Wi-Fi</strong>. To use an Ethernet network + connection, simply plug an Ethernet cable (that is connected to your network) into the port on + the back of ADT-1.</p> <p> <strong>How do I use the developer cable?</strong> @@ -70,6 +70,35 @@ Android TV platform.</p> power port on the back of ADT-1, a standard male USB-A connector that connects your PC, and a small, female power connector that the included power supply plugs into.</p> +<p class="note"> + <strong>Note:</strong> Make sure you have enabled USB debugging in <strong>Settings > + Preferences > Developer options > Debugging > USB debugging</strong>, so that you can + use the Android Debug Bridge (adb) to connect with the ADT-1 device. +</p> + +<p id="adb-tcp"> + <strong>Can I connect without a developer cable?</strong> +</p> +<p> + Yes. The ADT-1 device is enabled for Android Debug Bridge (adb) connections over TCP/IP. To + connect to the ADT-1 device using this method: +</p> +<ol> + <li>Make sure that your development computer and the ADT-1 device are on the same network.</li> + <li>Determine the IP address of the ADT-1 device by navigating to <strong>Settings > + Device > Wi-Fi > your-network-name > Status info</strong>.</li> + <li>Connect to the ADT-1 device using the following adb command: +<pre> +$ adb connect <ip-address-for-adt-1>:4321 +</pre> + </li> +</ol> + +<p class="note"> + <strong>Note:</strong> Make sure you have enabled USB debugging in <strong>Settings > + Preferences > Developer options > Debugging > USB debugging</strong>, so that you can + use the Android Debug Bridge (adb) to connect with the ADT-1 device. +</p> <h3 id="input">User Input</h3> @@ -179,8 +208,8 @@ Android TV platform.</p> <strong>How do I register my ADT-1 in order to run my apps?</strong> </p> <ol> - <li>Go to <strong>Settings > Google Cast</strong> and turn on developer support, allowing the - ADT-1 device to send its serial number to Google.</li> + <li>Go to <strong>Settings > Device > Google Cast</strong> and turn on developer support, + allowing the ADT-1 device to send its serial number to Google.</li> <li>Register your ADT-1 device in the Google Cast Developer Console, using the 12 character serial number engraved on the back of the ADT-1.</li> </ol> @@ -203,8 +232,8 @@ Android TV platform.</p> <p> <strong>Why doesn't the on-screen keyboard come up?</strong> </p> -<p>Enable the keyboard in the device Settings. Go to <strong>Settings > Keyboard > Current - keyboard</strong> and choose <strong>Leanback keyboard</strong>. +<p>Enable the keyboard in the device Settings. Go to <strong>Settings > Preferences > + Keyboard > Current keyboard</strong> and choose <strong>Leanback keyboard</strong>. <p> <strong>How do I perform a hardware reboot?</strong> @@ -221,8 +250,8 @@ Android TV platform.</p> data, downloaded apps, app data, and account settings. </p> -<p>From the home screen, go to <strong>Settings > Device > Factory data reset</strong>, and - select <strong>Reset device</strong>. +<p>From the home screen, go to <strong>Settings > Device > Storage & Reset</strong>, and + select <strong>Factory data reset</strong>. </p> <p> @@ -279,4 +308,3 @@ read this information before using the device:</p> <li><a href="regulatory.html">Regulatory Disclosures</a></li> <li><a href="safety.html">Important Safety Information</a></li> </ul> - diff --git a/docs/html/preview/tv/images/tif-overview.png b/docs/html/preview/tv/images/tif-overview.png Binary files differnew file mode 100644 index 0000000..197775e --- /dev/null +++ b/docs/html/preview/tv/images/tif-overview.png diff --git a/docs/html/preview/tv/tif/index.jd b/docs/html/preview/tv/tif/index.jd new file mode 100644 index 0000000..ef02def --- /dev/null +++ b/docs/html/preview/tv/tif/index.jd @@ -0,0 +1,38 @@ +page.title=TV Input Framework +page.tags=tif + +@jd:body + +<p> + Watching live television shows and other continuous, channel-based content is a big part of the + TV experience. Android supports receiving and playback of live video content through the TV Input + Framework. This framework provides a unified method for receiving audio and video channel content + from hardware sources, such as HDMI ports and built-in-tuners, and software sources, such as + video streamed over the internet. +</p> +<p> + The framework enables developers to define live TV input sources by implementing a TV input + service. This service publishes a list of channels and programs to the TV Provider. The live TV + app on a TV device gets the list of available channels and programs from the TV Provider and + displays them to a user. When a user selects a specific channel, the live TV app creates a + session for the associated TV input service through the TV Input Manager, and tells the TV input + service to tune to the requested channel and play the content to a display surface provided by + the TV app. +</p> + +<img src="{@docRoot}preview/tv/images/tif-overview.png" id="figure1"> +<p class="img-caption"> + <strong>Figure 1.</strong> Functional diagram of the TV Input Framework +</p> + +<p> + The TV Input Framework is designed to provide access to a wide variety of live TV input sources + and bring them together in a single user interface for users to browse, view, and enjoy content. + Building a TV input service for your content can help make it more accessible on TV devices. +</p> + +<p> + The APIs for the TV Input Framework are available in the L Developer Preview and you can + review them in the preview API reference docs. However, more changes are planned, so stay tuned + for additional information with the official Android platform launch. +</p> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 58a1bf2..ec862f8 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -51,6 +51,7 @@ public class Paint { private float mInvCompatScaling; private Locale mLocale; + private String mFontFeatureSettings; /** * @hide @@ -474,6 +475,7 @@ public class Paint { mBidiFlags = BIDI_DEFAULT_LTR; setTextLocale(Locale.getDefault()); setElegantTextHeight(false); + mFontFeatureSettings = null; } /** @@ -513,6 +515,7 @@ public class Paint { mBidiFlags = paint.mBidiFlags; mLocale = paint.mLocale; + mFontFeatureSettings = paint.mFontFeatureSettings; } /** @hide */ @@ -1283,6 +1286,34 @@ public class Paint { } /** + * Get font feature settings. Default is null. + * + * @return the paint's currently set font feature settings. + * @hide + */ + public String getFontFeatureSettings() { + return mFontFeatureSettings; + } + + /** + * Set font feature settings. + * + * The format is the same as the CSS font-feature-settings attribute: + * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings + * + * @param settings the font feature settings string to use, may be null. + * @hide + */ + public void setFontFeatureSettings(String settings) { + if (settings != null && settings.equals("")) + settings = null; + if ((settings == null && mFontFeatureSettings == null) + || (settings != null && settings.equals(mFontFeatureSettings))) return; + mFontFeatureSettings = settings; + native_setFontFeatureSettings(mNativePaint, settings); + } + + /** * Return the distance above (negative) the baseline (ascent) based on the * current typeface and text size. * @@ -2259,4 +2290,6 @@ public class Paint { private static native float native_getLetterSpacing(long native_object); private static native void native_setLetterSpacing(long native_object, float letterSpacing); + private static native void native_setFontFeatureSettings(long native_object, + String settings); } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index eb313ae..3397e94 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -245,9 +245,8 @@ public class NinePatchDrawable extends Drawable { final int restoreAlpha; if (mNinePatchState.mBaseAlpha != 1.0f) { - final Paint p = getPaint(); - restoreAlpha = p.getAlpha(); - p.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f)); + restoreAlpha = mPaint.getAlpha(); + mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f)); } else { restoreAlpha = -1; } @@ -445,6 +444,16 @@ public class NinePatchDrawable extends Drawable { // Hey, now might be a good time to actually load optical bounds! bitmap.getOpticalInsets(opticalInsets); + // Sanity check for valid padding when we have optical insets. + if (padding.left < opticalInsets.left) { + padding.left = opticalInsets.left; + padding.right = opticalInsets.right; + } + if (padding.top < opticalInsets.top) { + padding.top = opticalInsets.top; + padding.bottom = opticalInsets.bottom; + } + state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk()); state.mPadding = padding; state.mOpticalInsets = Insets.of(opticalInsets); @@ -611,6 +620,16 @@ public class NinePatchDrawable extends Drawable { mOpticalInsets = Insets.of(opticalInsets); mDither = dither; mAutoMirrored = autoMirror; + + // Sanity check for valid padding when we have optical insets. + if (mPadding.left < mOpticalInsets.left) { + mPadding.left = mOpticalInsets.left; + mPadding.right = mOpticalInsets.right; + } + if (mPadding.top < mOpticalInsets.top) { + mPadding.top = mOpticalInsets.top; + mPadding.bottom = mOpticalInsets.bottom; + } } // Copy constructor diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index f41b11a..be02c9b 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -364,13 +364,19 @@ 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 XmlPullParser parser = resources.getXml(rid); + final AttributeSet attrs = Xml.asAttributeSet(parser); + int type; + while ((type=parser.next()) != XmlPullParser.START_TAG && + type != XmlPullParser.END_DOCUMENT) { + // Empty loop + } + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } final VectorDrawable drawable = new VectorDrawable(); - drawable.inflate(resources, xpp, attrs); + drawable.inflate(resources, parser, attrs); return drawable; } catch (XmlPullParserException e) { @@ -436,10 +442,10 @@ public class VectorDrawable extends Drawable { if (pathRenderer.mViewportWidth <= 0) { throw new XmlPullParserException(a.getPositionDescription() + - "<viewport> tag requires viewportWidth > 0"); + "<vector> tag requires viewportWidth > 0"); } else if (pathRenderer.mViewportHeight <= 0) { throw new XmlPullParserException(a.getPositionDescription() + - "<viewport> tag requires viewportHeight > 0"); + "<vector> tag requires viewportHeight > 0"); } pathRenderer.mBaseWidth = a.getDimension( @@ -449,10 +455,10 @@ public class VectorDrawable extends Drawable { if (pathRenderer.mBaseWidth <= 0) { throw new XmlPullParserException(a.getPositionDescription() + - "<size> tag requires width > 0"); + "<vector> tag requires width > 0"); } else if (pathRenderer.mBaseHeight <= 0) { throw new XmlPullParserException(a.getPositionDescription() + - "<size> tag requires height > 0"); + "<vector> tag requires height > 0"); } } diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index c088906..7975e04 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -82,4 +82,12 @@ public class AudioDevicePort extends AudioPort { } return super.equals(o); } + + @Override + public String toString() { + return "{" + super.toString() + + ", mType:" + mType + + ", mAddress: " + mAddress + + "}"; + } } diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java index b58e7a3..6493dac 100644 --- a/media/java/android/media/AudioHandle.java +++ b/media/java/android/media/AudioHandle.java @@ -46,4 +46,9 @@ class AudioHandle { public int hashCode() { return mId; } + + @Override + public String toString() { + return Integer.toString(mId); + } } diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java index 8b74842..53212aa 100644 --- a/media/java/android/media/AudioPort.java +++ b/media/java/android/media/AudioPort.java @@ -173,5 +173,11 @@ public class AudioPort { public int hashCode() { return mHandle.hashCode(); } -} + @Override + public String toString() { + return "{mHandle:" + mHandle + + ", mRole:" + mRole + + "}"; + } +} diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java index 5dc768d..f937cc2 100644 --- a/media/java/android/media/AudioPortConfig.java +++ b/media/java/android/media/AudioPortConfig.java @@ -90,4 +90,14 @@ public class AudioPortConfig { public AudioGainConfig gain() { return mGain; } + + @Override + public String toString() { + return "{mPort:" + mPort + + ", mSamplingRate:" + mSamplingRate + + ", mChannelMask: " + mChannelMask + + ", mFormat:" + mFormat + + ", mGain:" + mGain + + "}"; + } } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 275d9b2..4a1c0ae 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ReadOnlyBufferException; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; /** @@ -531,9 +532,13 @@ final public class MediaCodec { public native final Surface createInputSurface(); /** - * After successfully configuring the component, call start. On return - * you can query the component for its input/output buffers. - * @throws IllegalStateException if not in the Configured state. + * After successfully configuring the component, call {@code start}. + * <p> + * Call {@code start} also if the codec is configured in asynchronous mode, + * and it has just been flushed, to resume requesting input buffers. + * @throws IllegalStateException if not in the Configured state + * or just after {@link #flush} for a codec that is configured + * in asynchronous mode. * @throws MediaCodec.CodecException upon codec error. Note that some codec errors * for start may be attributed to future method calls. */ @@ -569,6 +574,15 @@ final public class MediaCodec { * Flush both input and output ports of the component, all indices * previously returned in calls to {@link #dequeueInputBuffer} and * {@link #dequeueOutputBuffer} become invalid. + * <p> + * If codec is configured in asynchronous mode, call {@link #start} + * after {@code flush} has returned to resume codec operations. The + * codec will not request input buffers until this has happened. + * <p> + * If codec is configured in synchronous mode, codec will resume + * automatically if an input surface was created. Otherwise, it + * will resume when {@link #dequeueInputBuffer} is called. + * * @throws IllegalStateException if not in the Executing state. * @throws MediaCodec.CodecException upon codec error. */ @@ -576,10 +590,8 @@ final public class MediaCodec { synchronized(mBufferLock) { invalidateByteBuffers(mCachedInputBuffers); invalidateByteBuffers(mCachedOutputBuffers); - invalidateByteBuffers(mDequeuedInputBuffers); - invalidateByteBuffers(mDequeuedOutputBuffers); - freeImages(mDequeuedInputImages); - freeImages(mDequeuedOutputImages); + mDequeuedInputBuffers.clear(); + mDequeuedOutputBuffers.clear(); } native_flush(); } @@ -719,7 +731,7 @@ final public class MediaCodec { throws CryptoException { synchronized(mBufferLock) { invalidateByteBuffer(mCachedInputBuffers, index); - updateDequeuedByteBuffer(mDequeuedInputBuffers, index, null); + mDequeuedInputBuffers.remove(index); } native_queueInputBuffer( index, offset, size, presentationTimeUs, flags); @@ -839,7 +851,7 @@ final public class MediaCodec { int flags) throws CryptoException { synchronized(mBufferLock) { invalidateByteBuffer(mCachedInputBuffers, index); - updateDequeuedByteBuffer(mDequeuedInputBuffers, index, null); + mDequeuedInputBuffers.remove(index); } native_queueSecureInputBuffer( index, offset, info, presentationTimeUs, flags); @@ -859,7 +871,8 @@ final public class MediaCodec { * for the availability of an input buffer if timeoutUs < 0 or wait up * to "timeoutUs" microseconds if timeoutUs > 0. * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite". - * @throws IllegalStateException if not in the Executing state. + * @throws IllegalStateException if not in the Executing state, + * or codec is configured in asynchronous mode. * @throws MediaCodec.CodecException upon codec error. */ public final int dequeueInputBuffer(long timeoutUs) { @@ -907,7 +920,8 @@ final public class MediaCodec { * decoded or one of the INFO_* constants below. * @param info Will be filled with buffer meta data. * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite". - * @throws IllegalStateException if not in the Executing state. + * @throws IllegalStateException if not in the Executing state, + * or codec is configured in asynchronous mode. * @throws MediaCodec.CodecException upon codec error. */ public final int dequeueOutputBuffer( @@ -946,7 +960,7 @@ final public class MediaCodec { public final void releaseOutputBuffer(int index, boolean render) { synchronized(mBufferLock) { invalidateByteBuffer(mCachedOutputBuffers, index); - updateDequeuedByteBuffer(mDequeuedOutputBuffers, index, null); + mDequeuedOutputBuffers.remove(index); } releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */); } @@ -1003,7 +1017,7 @@ final public class MediaCodec { public final void releaseOutputBuffer(int index, long renderTimestampNs) { synchronized(mBufferLock) { invalidateByteBuffer(mCachedOutputBuffers, index); - updateDequeuedByteBuffer(mDequeuedOutputBuffers, index, null); + mDequeuedOutputBuffers.remove(index); } releaseOutputBuffer( index, true /* render */, true /* updatePTS */, renderTimestampNs); @@ -1068,17 +1082,82 @@ final public class MediaCodec { private native final Map<String, Object> getOutputFormatNative(int index); + // used to track dequeued buffers + private static class BufferMap { + // various returned representations of the codec buffer + private static class CodecBuffer { + private Image mImage; + private ByteBuffer mByteBuffer; + + public void free() { + if (mByteBuffer != null) { + // all of our ByteBuffers are direct + java.nio.NioUtils.freeDirectBuffer(mByteBuffer); + mByteBuffer = null; + } + if (mImage != null) { + mImage.close(); + mImage = null; + } + } + + public void setImage(Image image) { + free(); + mImage = image; + } + + public void setByteBuffer(ByteBuffer buffer) { + free(); + mByteBuffer = buffer; + } + } + + private final Map<Integer, CodecBuffer> mMap = + new HashMap<Integer, CodecBuffer>(); + + public void remove(int index) { + CodecBuffer buffer = mMap.get(index); + if (buffer != null) { + buffer.free(); + mMap.remove(index); + } + } + + public void put(int index, ByteBuffer newBuffer) { + CodecBuffer buffer = mMap.get(index); + if (buffer == null) { // likely + buffer = new CodecBuffer(); + mMap.put(index, buffer); + } + buffer.setByteBuffer(newBuffer); + } + + public void put(int index, Image newImage) { + CodecBuffer buffer = mMap.get(index); + if (buffer == null) { // likely + buffer = new CodecBuffer(); + mMap.put(index, buffer); + } + buffer.setImage(newImage); + } + + public void clear() { + for (CodecBuffer buffer: mMap.values()) { + buffer.free(); + } + mMap.clear(); + } + } + private ByteBuffer[] mCachedInputBuffers; private ByteBuffer[] mCachedOutputBuffers; - private ByteBuffer[] mDequeuedInputBuffers; - private ByteBuffer[] mDequeuedOutputBuffers; - private Image[] mDequeuedInputImages; - private Image[] mDequeuedOutputImages; + private final BufferMap mDequeuedInputBuffers = new BufferMap(); + private final BufferMap mDequeuedOutputBuffers = new BufferMap(); final private Object mBufferLock; private final void invalidateByteBuffer( ByteBuffer[] buffers, int index) { - if (index >= 0 && index < buffers.length) { + if (buffers != null && index >= 0 && index < buffers.length) { ByteBuffer buffer = buffers[index]; if (buffer != null) { buffer.setAccessible(false); @@ -1088,7 +1167,7 @@ final public class MediaCodec { private final void validateInputByteBuffer( ByteBuffer[] buffers, int index) { - if (index >= 0 && index < buffers.length) { + if (buffers != null && index >= 0 && index < buffers.length) { ByteBuffer buffer = buffers[index]; if (buffer != null) { buffer.setAccessible(true); @@ -1099,7 +1178,7 @@ final public class MediaCodec { private final void validateOutputByteBuffer( ByteBuffer[] buffers, int index, BufferInfo info) { - if (index >= 0 && index < buffers.length) { + if (buffers != null && index >= 0 && index < buffers.length) { ByteBuffer buffer = buffers[index]; if (buffer != null) { buffer.setAccessible(true); @@ -1133,46 +1212,29 @@ final public class MediaCodec { } } - private final void freeImage(Image image) { - if (image != null) { - image.close(); - } - } - - private final void freeImages(Image[] images) { - if (images != null) { - for (Image image: images) { - freeImage(image); - } - } - } - private final void freeAllTrackedBuffers() { - freeByteBuffers(mCachedInputBuffers); - freeByteBuffers(mCachedOutputBuffers); - freeImages(mDequeuedInputImages); - freeImages(mDequeuedOutputImages); - freeByteBuffers(mDequeuedInputBuffers); - freeByteBuffers(mDequeuedOutputBuffers); - mCachedInputBuffers = null; - mCachedOutputBuffers = null; - mDequeuedInputImages = null; - mDequeuedOutputImages = null; - mDequeuedInputBuffers = null; - mDequeuedOutputBuffers = null; + synchronized (mBufferLock) { + freeByteBuffers(mCachedInputBuffers); + freeByteBuffers(mCachedOutputBuffers); + mCachedInputBuffers = null; + mCachedOutputBuffers = null; + mDequeuedInputBuffers.clear(); + mDequeuedOutputBuffers.clear(); + } } private final void cacheBuffers(boolean input) { - ByteBuffer[] buffers = getBuffers(input); - invalidateByteBuffers(buffers); + ByteBuffer[] buffers = null; + try { + buffers = getBuffers(input); + invalidateByteBuffers(buffers); + } catch (IllegalStateException e) { + // we don't get buffers in async mode + } if (input) { mCachedInputBuffers = buffers; - mDequeuedInputImages = new Image[buffers.length]; - mDequeuedInputBuffers = new ByteBuffer[buffers.length]; } else { mCachedOutputBuffers = buffers; - mDequeuedOutputImages = new Image[buffers.length]; - mDequeuedOutputBuffers = new ByteBuffer[buffers.length]; } } @@ -1188,7 +1250,8 @@ final public class MediaCodec { * <b>Note:</b>As of API 21, dequeued input buffers are * automatically {@link java.nio.Buffer#clear cleared}. * - * @throws IllegalStateException if not in the Executing state. + * @throws IllegalStateException if not in the Executing state, + * or codec is configured in asynchronous mode. * @throws MediaCodec.CodecException upon codec error. */ public ByteBuffer[] getInputBuffers() { @@ -1227,26 +1290,6 @@ final public class MediaCodec { return mCachedOutputBuffers; } - private boolean updateDequeuedByteBuffer( - ByteBuffer[] buffers, int index, ByteBuffer newBuffer) { - if (index < 0 || index >= buffers.length) { - return false; - } - freeByteBuffer(buffers[index]); - buffers[index] = newBuffer; - return newBuffer != null; - } - - private boolean updateDequeuedImage( - Image[] images, int index, Image newImage) { - if (index < 0 || index >= images.length) { - return false; - } - freeImage(images[index]); - images[index] = newImage; - return newImage != null; - } - /** * Returns a {@link java.nio.Buffer#clear cleared}, writable ByteBuffer * object for a dequeued input buffer index to contain the input data. @@ -1268,13 +1311,10 @@ final public class MediaCodec { public ByteBuffer getInputBuffer(int index) { ByteBuffer newBuffer = getBuffer(true /* input */, index); synchronized(mBufferLock) { - if (updateDequeuedByteBuffer(mDequeuedInputBuffers, index, newBuffer)) { - updateDequeuedImage(mDequeuedInputImages, index, null); - invalidateByteBuffer(mCachedInputBuffers, index); - return newBuffer; - } + invalidateByteBuffer(mCachedInputBuffers, index); + mDequeuedInputBuffers.put(index, newBuffer); } - return null; + return newBuffer; } /** @@ -1298,12 +1338,11 @@ final public class MediaCodec { */ public Image getInputImage(int index) { Image newImage = getImage(true /* input */, index); - if (updateDequeuedImage(mDequeuedInputImages, index, newImage)) { - updateDequeuedByteBuffer(mDequeuedInputBuffers, index, null); + synchronized(mBufferLock) { invalidateByteBuffer(mCachedInputBuffers, index); - return newImage; + mDequeuedInputBuffers.put(index, newImage); } - return null; + return newImage; } /** @@ -1328,13 +1367,10 @@ final public class MediaCodec { public ByteBuffer getOutputBuffer(int index) { ByteBuffer newBuffer = getBuffer(false /* input */, index); synchronized(mBufferLock) { - if (updateDequeuedByteBuffer(mDequeuedOutputBuffers, index, newBuffer)) { - updateDequeuedImage(mDequeuedOutputImages, index, null); - invalidateByteBuffer(mCachedOutputBuffers, index); - return newBuffer; - } + invalidateByteBuffer(mCachedOutputBuffers, index); + mDequeuedOutputBuffers.put(index, newBuffer); } - return null; + return newBuffer; } /** @@ -1358,13 +1394,10 @@ final public class MediaCodec { public Image getOutputImage(int index) { Image newImage = getImage(false /* input */, index); synchronized(mBufferLock) { - if (updateDequeuedImage(mDequeuedOutputImages, index, newImage)) { - updateDequeuedByteBuffer(mDequeuedOutputBuffers, index, null); - invalidateByteBuffer(mCachedOutputBuffers, index); - return newImage; - } + invalidateByteBuffer(mCachedOutputBuffers, index); + mDequeuedOutputBuffers.put(index, newImage); } - return null; + return newImage; } /** @@ -1445,7 +1478,12 @@ final public class MediaCodec { * a valid callback should be provided before {@link #configure} is called. * * When asynchronous callback is enabled, the client should not call - * {@link #dequeueInputBuffer(long)} or {@link #dequeueOutputBuffer(BufferInfo, long)} + * {@link #getInputBuffers}, {@link #getOutputBuffers}, + * {@link #dequeueInputBuffer(long)} or {@link #dequeueOutputBuffer(BufferInfo, long)}. + * <p> + * Also, {@link #flush} behaves differently in asynchronous mode. After calling + * {@code flush}, you must call {@link #start} to "resume" receiving input buffers, + * even if an input surface was created. * * @param cb The callback that will run. */ diff --git a/media/java/android/media/browse/MediaBrowserItem.java b/media/java/android/media/browse/MediaBrowserItem.java index d0a0342..47ec46b 100644 --- a/media/java/android/media/browse/MediaBrowserItem.java +++ b/media/java/android/media/browse/MediaBrowserItem.java @@ -135,6 +135,19 @@ public final class MediaBrowserItem implements Parcelable { } } + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("MediaBrowserItem{"); + sb.append("mUri=").append(mUri); + sb.append(", mFlags=").append(mFlags); + sb.append(", mTitle=").append(mTitle); + sb.append(", mSummary=").append(mSummary); + sb.append(", mIconUri=").append(mIconUri); + sb.append(", mIconResourceId=").append(mIconResourceId); + sb.append('}'); + return sb.toString(); + } + public static final Parcelable.Creator<MediaBrowserItem> CREATOR = new Parcelable.Creator<MediaBrowserItem>() { @Override diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl index c48ddf1..2c39afa 100644 --- a/media/java/android/media/tv/ITvInputClient.aidl +++ b/media/java/android/media/tv/ITvInputClient.aidl @@ -34,6 +34,7 @@ oneway interface ITvInputClient { void onSessionEvent(in String name, in Bundle args, int seq); void onChannelRetuned(in Uri channelUri, int seq); void onTrackInfoChanged(in List<TvTrackInfo> tracks, int seq); + void onTrackSelectionChanged(in List<TvTrackInfo> selectedTracks, int seq); void onVideoAvailable(int seq); void onVideoUnavailable(int reason, int seq); void onContentAllowed(int seq); diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl index 4186bb5..3773987 100644 --- a/media/java/android/media/tv/ITvInputSessionCallback.aidl +++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl @@ -31,6 +31,7 @@ oneway interface ITvInputSessionCallback { void onSessionEvent(in String name, in Bundle args); void onChannelRetuned(in Uri channelUri); void onTrackInfoChanged(in List<TvTrackInfo> tracks); + void onTrackSelectionChanged(in List<TvTrackInfo> selectedTracks); void onVideoAvailable(); void onVideoUnavailable(int reason); void onContentAllowed(); diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index d97aee0..49b2240 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -164,7 +164,7 @@ public final class TvInputManager { * This is called when the channel of this session is changed by the underlying TV input * with out any {@link TvInputManager.Session#tune(Uri)} request. * - * @param session A {@link TvInputManager.Session} associated with this callback + * @param session A {@link TvInputManager.Session} associated with this callback. * @param channelUri The URI of a channel. */ public void onChannelRetuned(Session session, Uri channelUri) { @@ -173,16 +173,25 @@ public final class TvInputManager { /** * This is called when the track information of the session has been changed. * - * @param session A {@link TvInputManager.Session} associated with this callback + * @param session A {@link TvInputManager.Session} associated with this callback. * @param tracks A list which includes track information. */ public void onTrackInfoChanged(Session session, List<TvTrackInfo> tracks) { } /** - * This is called when the video is available, so the TV input starts the playback. + * This is called when there is a change on the selected tracks in this session. * * @param session A {@link TvInputManager.Session} associated with this callback + * @param selectedTracks A list of selected tracks. + */ + public void onTrackSelectionChanged(Session session, List<TvTrackInfo> selectedTracks) { + } + + /** + * This is called when the video is available, so the TV input starts the playback. + * + * @param session A {@link TvInputManager.Session} associated with this callback. */ public void onVideoAvailable(Session session) { } @@ -277,12 +286,22 @@ public final class TvInputManager { mHandler.post(new Runnable() { @Override public void run() { - mSession.setTracks(tracks); + mSession.mTracks = tracks; mSessionCallback.onTrackInfoChanged(mSession, tracks); } }); } + public void postTrackSelectionChanged(final List<TvTrackInfo> selectedTracks) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSession.mSelectedTracks = selectedTracks; + mSessionCallback.onTrackSelectionChanged(mSession, selectedTracks); + } + }); + } + public void postVideoAvailable() { mHandler.post(new Runnable() { @Override @@ -469,6 +488,18 @@ public final class TvInputManager { } @Override + public void onTrackSelectionChanged(List<TvTrackInfo> selectedTracks, int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postTrackSelectionChanged(selectedTracks); + } + } + + @Override public void onVideoAvailable(int seq) { synchronized (mSessionCallbackRecordMap) { SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); @@ -868,6 +899,7 @@ public final class TvInputManager { private TvInputEventSender mSender; private InputChannel mChannel; private List<TvTrackInfo> mTracks; + private List<TvTrackInfo> mSelectedTracks; private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId, int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) { @@ -1067,8 +1099,17 @@ public final class TvInputManager { return new ArrayList<TvTrackInfo>(mTracks); } - private void setTracks(List<TvTrackInfo> tracks) { - mTracks = tracks; + /** + * Returns a list of selected tracks May return {@code null} if the information is not + * available. + * @see #selectTrack(TvTrackInfo) + * @see #unselectTrack(TvTrackInfo) + */ + public List<TvTrackInfo> getSelectedTracks() { + if (mSelectedTracks == null) { + return null; + } + return new ArrayList<TvTrackInfo>(mSelectedTracks); } /** diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index a321809..29a2230 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -325,10 +325,6 @@ public abstract class TvInputService extends Service { * @param tracks A list which includes track information. */ public void notifyTrackInfoChanged(final List<TvTrackInfo> tracks) { - if (!TvTrackInfo.checkSanity(tracks)) { - throw new IllegalArgumentException( - "Two or more selected tracks for a track type."); - } mHandler.post(new Runnable() { @Override public void run() { @@ -343,6 +339,28 @@ public abstract class TvInputService extends Service { } /** + * Sends the list of selected tracks. This is expected to be called whenever there is a + * change on track selection. + * + * @param selectedTracks A list of selected tracks. + * @see #onSelectTrack(TvTrackInfo) + * @see #onUnselectTrack(TvTrackInfo) + */ + public void notifyTrackSelectionChanged(final List<TvTrackInfo> selectedTracks) { + mHandler.post(new Runnable() { + @Override + public void run() { + try { + if (DEBUG) Log.d(TAG, "notifyTrackSelectionChanged"); + mSessionCallback.onTrackSelectionChanged(selectedTracks); + } catch (RemoteException e) { + Log.w(TAG, "error in notifyTrackSelectionChanged"); + } + } + }); + } + + /** * Informs the application that video is available and the playback of the TV stream has * been started. */ @@ -572,13 +590,12 @@ public abstract class TvInputService extends Service { * If it is called multiple times on the same type of track (ie. Video, Audio, Text), the * track selected previously should be unselected in the implementation of this method. * Also, if the select operation was successful, the implementation should call - * {@link #notifyTrackInfoChanged(List)} to report the updated track information. + * {@link #notifyTrackSelectionChanged(List)} to report the selected track list. * </p> * * @param track The track to be selected. * @return {@code true} if the select operation was successful, {@code false} otherwise. - * @see #notifyTrackInfoChanged - * @see TvTrackInfo#KEY_IS_SELECTED + * @see #notifyTrackSelectionChanged(List) */ public boolean onSelectTrack(TvTrackInfo track) { return false; @@ -588,13 +605,12 @@ public abstract class TvInputService extends Service { * Unselects a given track. * <p> * If the unselect operation was successful, the implementation should call - * {@link #notifyTrackInfoChanged(List)} to report the updated track information. + * {@link #notifyTrackSelectionChanged(List)} to report the selected track list. * </p> * * @param track The track to be unselected. * @return {@code true} if the unselect operation was successful, {@code false} otherwise. - * @see #notifyTrackInfoChanged - * @see TvTrackInfo#KEY_IS_SELECTED + * @see #notifyTrackSelectionChanged(List) */ public boolean onUnselectTrack(TvTrackInfo track) { return false; diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java index 243f864..a7e7e44 100644 --- a/media/java/android/media/tv/TvStreamConfig.java +++ b/media/java/android/media/tv/TvStreamConfig.java @@ -88,6 +88,16 @@ public class TvStreamConfig implements Parcelable { return mGeneration; } + @Override + public String toString() { + StringBuilder b = new StringBuilder(128); + b.append("TvStreamConfig {"); + b.append("mStreamId=").append(mStreamId).append(";"); + b.append("mType=").append(mType).append(";"); + b.append("mGeneration=").append(mGeneration).append("}"); + return b.toString(); + } + // Parcelable @Override public int describeContents() { diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java index de4f4b7..3b80db4 100644 --- a/media/java/android/media/tv/TvTrackInfo.java +++ b/media/java/android/media/tv/TvTrackInfo.java @@ -16,171 +16,121 @@ package android.media.tv; -import android.media.MediaFormat; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import java.util.List; - /** * Encapsulates the format of tracks played in {@link TvInputService}. */ public final class TvTrackInfo implements Parcelable { /** - * A key describing the type of this track. The associated value is an integer and it should be - * one of {@link #VALUE_TYPE_AUDIO}, {@link #VALUE_TYPE_VIDEO}, and {@link #VALUE_TYPE_SUBTITLE}. - * <p> - * This is a required key. - * </p> - */ - public static final String KEY_TYPE = "type"; - - /** - * A key describing the language of the track, using either ISO 639-1 or 639-2/T codes. - * If the language is unknown or could not be determined, the corresponding value will be "und". - * The associated value is a string. - * <p> - * This is a required key. - * </p> + * The type value for audio tracks. */ - public static final String KEY_LANGUAGE = MediaFormat.KEY_LANGUAGE; + public static final int TYPE_AUDIO = 0; /** - * A key describing whether this track is selected for the playback. - * The associated value is a boolean. - * <p> - * This is a required key. - * </p> + * The type value for video tracks. */ - public static final String KEY_IS_SELECTED = "is-selected"; + public static final int TYPE_VIDEO = 1; /** - * A key describing the sample rate of an audio track. - * The associated value is an integer. + * The type value for subtitle tracks. */ - public static final String KEY_SAMPLE_RATE = MediaFormat.KEY_SAMPLE_RATE; - - /** - * A key describing the number of channels in an audio track. - * The associated value is an integer. - */ - public static final String KEY_CHANNEL_COUNT = MediaFormat.KEY_CHANNEL_COUNT; - - /** - * A key describing the width of the content in a video track. - * The associated value is an integer. - */ - public static final String KEY_WIDTH = MediaFormat.KEY_WIDTH; - - /** - * A key describing the height of the content in a video track. - * The associated value is an integer. - */ - public static final String KEY_HEIGHT = MediaFormat.KEY_HEIGHT; - - /** - * A key describing a tag associated with this track. Expected to be used as an identifier with - * in a session. The associated value is a string. - */ - public static final String KEY_TAG = "tag"; + public static final int TYPE_SUBTITLE = 2; + + private final int mType; + private final String mLanguage; + private final int mAudioChannelCount; + private final int mAudioSampleRate; + private final int mVideoWidth; + private final int mVideoHeight; + private final Bundle mExtra; + + private TvTrackInfo(int type, String language, int audioChannelCount, + int audioSampleRate, int videoWidth, int videoHeight, Bundle extra) { + mType = type; + mLanguage = language; + mAudioChannelCount = audioChannelCount; + mAudioSampleRate = audioSampleRate; + mVideoWidth = videoWidth; + mVideoHeight = videoHeight; + mExtra = extra; + } - /** - * The type value for audio track. - */ - public static final int VALUE_TYPE_AUDIO = 0; + private TvTrackInfo(Parcel in) { + mType = in.readInt(); + mLanguage = in.readString(); + mAudioChannelCount = in.readInt(); + mAudioSampleRate = in.readInt(); + mVideoWidth = in.readInt(); + mVideoHeight = in.readInt(); + mExtra = in.readBundle(); + } /** - * The type value for video track. + * Returns the type of the track. The type should be one of the followings: + * {@link #TYPE_AUDIO}, {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}. */ - public static final int VALUE_TYPE_VIDEO = 1; + public final int getType() { + return mType; + } /** - * The type value for subtitle track. + * Returns the language information encoded by either ISO 639-1 or ISO 639-2/T. If the language + * is unknown or could not be determined, the corresponding value will be {@code null}. */ - public static final int VALUE_TYPE_SUBTITLE = 2; - - private final Bundle mBundle; - - private TvTrackInfo(Bundle bundle) { - mBundle = new Bundle(bundle); - } - - private TvTrackInfo(Parcel in) { - mBundle = in.readBundle(); + public final String getLanguage() { + return mLanguage; } /** - * Checks if there is only one or zero selected track per track type. - * - * @param tracks a list including tracks which will be checked. - * @return true if there is only one or zero selected track per track type, false otherwise - * @hide + * Returns the audio channel count. Valid for {@link #TYPE_AUDIO} tracks only. */ - public static boolean checkSanity(List<TvTrackInfo> tracks) { - int selectedAudioTracks = 0; - int selectedVideoTracks = 0; - int selectedSubtitleTracks = 0; - for (TvTrackInfo track : tracks) { - if (track.getBoolean(KEY_IS_SELECTED)) { - int type = track.getInt(KEY_TYPE); - if (type == VALUE_TYPE_AUDIO) { - selectedAudioTracks++; - } else if (type == VALUE_TYPE_VIDEO) { - selectedVideoTracks++; - } else if (type == VALUE_TYPE_SUBTITLE) { - selectedSubtitleTracks++; - } - } - } - if (selectedAudioTracks > 1 || selectedVideoTracks > 1 || selectedSubtitleTracks > 1) { - return false; + public final int getAudioChannelCount() { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); } - return true; + return mAudioChannelCount; } /** - * Returns true if the given key is contained in the metadata - * - * @param key A String key - * @return true If the key exists in this metadata, false otherwise + * Returns the audio sample rate, in the unit of Hz. Valid for {@link #TYPE_AUDIO} tracks only. */ - public boolean containsKey(String key) { - return mBundle.containsKey(key); + public final int getAudioSampleRate() { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + return mAudioSampleRate; } /** - * Returns the value associated with the given key, or null if no mapping of - * the desired type exists for the given key or a null value is explicitly - * associated with the key. - * - * @param key The key the value is stored under - * @return A String value, or null + * Returns the width of the video, in the unit of pixels. Valid for {@link #TYPE_VIDEO} tracks + * only. */ - public String getString(String key) { - return mBundle.getString(key); + public final int getVideoWidth() { + if (mType != TYPE_VIDEO) { + throw new IllegalStateException("Not a video track"); + } + return mVideoWidth; } /** - * Returns the value associated with the given key, or 0L if no integer exists - * for the given key. - * - * @param key The key the value is stored under - * @return An integer value + * Returns the height of the video, in the unit of pixels. Valid for {@link #TYPE_VIDEO} tracks + * only. */ - public int getInt(String key) { - return mBundle.getInt(key, 0); + public final int getVideoHeight() { + if (mType != TYPE_VIDEO) { + throw new IllegalStateException("Not a video track"); + } + return mVideoHeight; } /** - * Returns the value associated with the given key, or false if no integer exists - * for the given key. - * - * @param key The key the value is stored under - * @return A boolean value + * Returns the extra information about the current track. */ - public boolean getBoolean(String key) { - return mBundle.getBoolean(key, false); + public final Bundle getExtra() { + return mExtra; } @Override @@ -188,13 +138,25 @@ public final class TvTrackInfo implements Parcelable { return 0; } + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeBundle(mBundle); + dest.writeInt(mType); + dest.writeString(mLanguage); + dest.writeInt(mAudioChannelCount); + dest.writeInt(mAudioSampleRate); + dest.writeInt(mVideoWidth); + dest.writeInt(mVideoHeight); + dest.writeBundle(mExtra); } - public static final Parcelable.Creator<TvTrackInfo> CREATOR - = new Parcelable.Creator<TvTrackInfo>() { + public static final Parcelable.Creator<TvTrackInfo> CREATOR = + new Parcelable.Creator<TvTrackInfo>() { @Override public TvTrackInfo createFromParcel(Parcel in) { return new TvTrackInfo(in); @@ -210,73 +172,100 @@ public final class TvTrackInfo implements Parcelable { * A builder class for creating {@link TvTrackInfo} objects. */ public static final class Builder { - private final Bundle mBundle; + private int mType; + private String mLanguage; + private int mAudioChannelCount; + private int mAudioSampleRate; + private int mVideoWidth; + private int mVideoHeight; + private Bundle mExtra; /** - * Create a {@link Builder}. Any field that should be included in the - * {@link TvTrackInfo} must be added. + * Create a {@link Builder}. Any field that should be included in the {@link TvTrackInfo} + * must be added. * * @param type The type of the track. - * @param language The language of the track, using either ISO 639-1 or 639-2/T codes. - * "und" if the language is unknown. - * @param isSelected Whether this track is selected for the playback or not. */ - public Builder(int type, String language, boolean isSelected) { - if (type != VALUE_TYPE_AUDIO - && type != VALUE_TYPE_VIDEO - && type != VALUE_TYPE_SUBTITLE) { + public Builder(int type) { + if (type != TYPE_AUDIO + && type != TYPE_VIDEO + && type != TYPE_SUBTITLE) { throw new IllegalArgumentException("Unknown type: " + type); } - mBundle = new Bundle(); - putInt(KEY_TYPE, type); - putString(KEY_LANGUAGE, language); - putBoolean(KEY_IS_SELECTED, isSelected); + mType = type; } /** - * Create a Builder using a {@link TvTrackInfo} instance to set the - * initial values. All fields in the source metadata will be included in - * the new metadata. Fields can be overwritten by adding the same key. + * Sets the language information of the current track. * - * @param source The source {@link TvTrackInfo} instance + * @param language The language string encoded by either ISO 639-1 or ISO 639-2/T. */ - public Builder(TvTrackInfo source) { - mBundle = new Bundle(source.mBundle); + public final Builder setLanguage(String language) { + mLanguage = language; + return this; } /** - * Put a String value into the track. + * Sets the audio channel count. Valid for {@link #TYPE_AUDIO} tracks only. * - * @param key The key for referencing this value - * @param value The String value to store - * @return The Builder to allow chaining + * @param audioChannelCount The audio channel count. */ - public Builder putString(String key, String value) { - mBundle.putString(key, value); + public final Builder setAudioChannelCount(int audioChannelCount) { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + mAudioChannelCount = audioChannelCount; return this; } /** - * Put an integer value into the track. + * Sets the audio sample rate, in the unit of Hz. Valid for {@link #TYPE_AUDIO} tracks only. * - * @param key The key for referencing this value - * @param value The integer value to store - * @return The Builder to allow chaining + * @param audioSampleRate The audio sample rate. */ - public Builder putInt(String key, int value) { - mBundle.putInt(key, value); + public final Builder setAudioSampleRate(int audioSampleRate) { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + mAudioSampleRate = audioSampleRate; + return this; + } + + /** + * Sets the width of the video, in the unit of pixels. Valid for {@link #TYPE_VIDEO} tracks + * only. + * + * @param videoWidth The width of the video. + */ + public final Builder setVideoWidth(int videoWidth) { + if (mType != TYPE_VIDEO) { + throw new IllegalStateException("Not a video track"); + } + mVideoWidth = videoWidth; + return this; + } + + /** + * Sets the height of the video, in the unit of pixels. Valid for {@link #TYPE_VIDEO} tracks + * only. + * + * @param videoHeight The height of the video. + */ + public final Builder setVideoHeight(int videoHeight) { + if (mType != TYPE_VIDEO) { + throw new IllegalStateException("Not a video track"); + } + mVideoHeight = videoHeight; return this; } /** - * Put a boolean value into the track. + * Sets the extra information about the current track. * - * @param key The key for referencing this value - * @param value The boolean value to store - * @return The Builder to allow chaining + * @param extra The extra information. */ - public Builder putBoolean(String key, boolean value) { - mBundle.putBoolean(key, value); + public final Builder setExtra(Bundle extra) { + mExtra = new Bundle(extra); return this; } @@ -286,7 +275,8 @@ public final class TvTrackInfo implements Parcelable { * @return The new {@link TvTrackInfo} instance */ public TvTrackInfo build() { - return new TvTrackInfo(mBundle); + return new TvTrackInfo(mType, mLanguage, mAudioChannelCount, + mAudioSampleRate, mVideoWidth, mVideoHeight, mExtra); } } }
\ No newline at end of file diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index f6af8c8..7031f05 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -68,7 +68,7 @@ public class TvView extends ViewGroup { private final Handler mHandler = new Handler(); private Session mSession; - private final SurfaceView mSurfaceView; + private SurfaceView mSurfaceView; private Surface mSurface; private boolean mOverlayViewCreated; private Rect mOverlayViewFrame; @@ -84,6 +84,8 @@ public class TvView extends ViewGroup { private int mSurfaceFormat; private int mSurfaceWidth; private int mSurfaceHeight; + private final AttributeSet mAttrs; + private final int mDefStyleAttr; private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { @Override @@ -143,14 +145,9 @@ public class TvView extends ViewGroup { public TvView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mSurfaceView = new SurfaceView(context, attrs, defStyleAttr) { - @Override - protected void updateWindow(boolean force, boolean redrawNeeded) { - super.updateWindow(force, redrawNeeded); - relayoutSessionOverlayView(); - }}; - mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback); - addView(mSurfaceView); + mAttrs = attrs; + mDefStyleAttr = defStyleAttr; + resetSurfaceView(); mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE); } @@ -228,9 +225,7 @@ public class TvView extends ViewGroup { mSessionCallback.mChannelUri = channelUri; } } else { - if (mSession != null) { - release(); - } + reset(); // When createSession() is called multiple times before the callback is called, // only the callback of the last createSession() call will be actually called back. // The previous callbacks will be ignored. For the logic, mSessionCallback @@ -249,6 +244,7 @@ public class TvView extends ViewGroup { public void reset() { if (mSession != null) { release(); + resetSurfaceView(); } } @@ -325,6 +321,17 @@ public class TvView extends ViewGroup { } /** + * Returns a list of selected tracks. May return {@code null} if the information is not + * available. + */ + public List<TvTrackInfo> getSelectedTracks() { + if (mSession == null) { + return null; + } + return mSession.getSelectedTracks(); + } + + /** * Call {@link TvInputService.Session#appPrivateCommand(String, Bundle) * TvInputService.Session.appPrivateCommand()} on the current TvView. * @@ -495,6 +502,21 @@ public class TvView extends ViewGroup { } } + private void resetSurfaceView() { + if (mSurfaceView != null) { + mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback); + removeView(mSurfaceView); + } + mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) { + @Override + protected void updateWindow(boolean force, boolean redrawNeeded) { + super.updateWindow(force, redrawNeeded); + relayoutSessionOverlayView(); + }}; + mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback); + addView(mSurfaceView); + } + private void release() { setSessionSurface(null); removeSessionOverlayView(); @@ -558,10 +580,9 @@ public class TvView extends ViewGroup { private void updateVideoSize(List<TvTrackInfo> tracks) { for (TvTrackInfo track : tracks) { - if (track.getBoolean(TvTrackInfo.KEY_IS_SELECTED) - && track.getInt(TvTrackInfo.KEY_TYPE) == TvTrackInfo.VALUE_TYPE_VIDEO) { - int width = track.getInt(TvTrackInfo.KEY_WIDTH); - int height = track.getInt(TvTrackInfo.KEY_HEIGHT); + if (track.getType() == TvTrackInfo.TYPE_VIDEO) { + int width = track.getVideoWidth(); + int height = track.getVideoHeight(); if (width != mVideoWidth || height != mVideoHeight) { mVideoWidth = width; mVideoHeight = height; @@ -619,6 +640,15 @@ public class TvView extends ViewGroup { } /** + * This is called when there is a change on the selected tracks. + * + * @param inputId The ID of the TV input bound to this view. + * @param selectedTracks A list which includes track information. + */ + public void onTrackSelectionChanged(String inputId, List<TvTrackInfo> selectedTracks) { + } + + /** * This is called when the video is available, so the TV input starts the playback. * * @param inputId The ID of the TV input bound to this view. @@ -768,13 +798,26 @@ public class TvView extends ViewGroup { if (DEBUG) { Log.d(TAG, "onTrackInfoChanged()"); } - updateVideoSize(tracks); if (mListener != null) { mListener.onTrackInfoChanged(mInputId, tracks); } } @Override + public void onTrackSelectionChanged(Session session, List<TvTrackInfo> selectedTracks) { + if (this != mSessionCallback) { + return; + } + if (DEBUG) { + Log.d(TAG, "onTrackInfoChanged()"); + } + updateVideoSize(selectedTracks); + if (mListener != null) { + mListener.onTrackSelectionChanged(mInputId, selectedTracks); + } + } + + @Override public void onVideoAvailable(Session session) { if (this != mSessionCallback) { return; diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml new file mode 100644 index 0000000..d4b1214 --- /dev/null +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -0,0 +1,78 @@ +<?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 + --> + +<!-- Extends RelativeLayout --> +<com.android.systemui.statusbar.phone.KeyguardStatusBarView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" + android:id="@+id/keyguard_header" + android:layout_width="match_parent" + android:layout_height="@dimen/status_bar_header_height_keyguard" + android:baselineAligned="false" + > + + <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch" + android:layout_width="@dimen/multi_user_switch_width_keyguard" + android:layout_height="@dimen/status_bar_header_height_keyguard" + android:layout_alignParentEnd="true" + android:background="@drawable/ripple_drawable" + android:layout_marginEnd="@dimen/multi_user_switch_keyguard_margin"> + <ImageView android:id="@+id/multi_user_avatar" + android:layout_width="@dimen/multi_user_avatar_keyguard_size" + android:layout_height="@dimen/multi_user_avatar_keyguard_size" + android:layout_gravity="center" + android:scaleType="centerInside"/> + </com.android.systemui.statusbar.phone.MultiUserSwitch> + + <LinearLayout android:id="@+id/system_icons_super_container" + android:layout_width="wrap_content" + android:layout_height="@dimen/status_bar_header_height" + android:layout_toStartOf="@id/multi_user_switch" + android:layout_alignWithParentIfMissing="true" + android:layout_marginStart="16dp" + android:paddingEnd="2dp"> + <FrameLayout android:id="@+id/system_icons_container" + android:layout_width="wrap_content" + android:layout_height="@dimen/status_bar_height" + android:layout_gravity="center_vertical" + > + <include layout="@layout/system_icons" /> + </FrameLayout> + <TextView android:id="@+id/battery_level" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginStart="@dimen/header_battery_margin_keyguard" + android:paddingEnd="@dimen/battery_level_padding_end" + android:textColor="#ffffff" + android:visibility="gone" + android:textSize="12sp"/> + </LinearLayout> + + <com.android.keyguard.CarrierText + android:id="@+id/keyguard_carrier_text" + android:layout_width="match_parent" + android:layout_height="@dimen/status_bar_header_height_keyguard" + android:layout_marginStart="@dimen/keyguard_carrier_text_margin" + android:layout_toStartOf="@id/system_icons_super_container" + android:gravity="center_vertical" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="#ffffff" + android:singleLine="true" /> + +</com.android.systemui.statusbar.phone.KeyguardStatusBarView> diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 19dc36d..beb8e00 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -82,33 +82,9 @@ android:layout_height="match_parent" android:orientation="horizontal" > - <LinearLayout android:id="@+id/system_icons" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - > - <com.android.systemui.statusbar.AlphaOptimizedLinearLayout - android:id="@+id/statusIcons" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:orientation="horizontal"/> - <include layout="@layout/signal_cluster_view" - android:id="@+id/signal_cluster" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="2dp" - /> - <!-- battery must be padded below to match assets --> - <com.android.systemui.BatteryMeterView - android:id="@+id/battery" - android:layout_height="16dp" - android:layout_width="10.5dp" - android:layout_marginBottom="0.33dp" - android:layout_marginStart="4dip" - /> - </LinearLayout> + <include layout="@layout/system_icons" /> + <com.android.systemui.statusbar.policy.Clock android:id="@+id/clock" android:textAppearance="@style/TextAppearance.StatusBar.Clock" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 9af2879..53a832a 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -50,6 +50,10 @@ android:visibility="gone" /> + <include + layout="@layout/keyguard_status_bar" + android:visibility="invisible" /> + <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer style="@style/NotificationsQuickSettings" android:id="@+id/notification_container_parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index b260a4a..1afde69 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -68,7 +68,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:layout_marginStart="@dimen/header_battery_margin_keyguard" + android:layout_marginStart="@dimen/header_battery_margin_expanded" android:paddingEnd="@dimen/battery_level_padding_end" android:textColor="#ffffff" android:textSize="12sp"/> @@ -139,18 +139,6 @@ android:visibility="gone" /> - <com.android.keyguard.CarrierText - android:id="@+id/keyguard_carrier_text" - android:layout_width="match_parent" - android:layout_height="@dimen/status_bar_header_height_keyguard" - android:layout_marginStart="@dimen/keyguard_carrier_text_margin" - android:layout_toStartOf="@id/system_icons_super_container" - android:gravity="center_vertical" - android:ellipsize="marquee" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="#ffffff" - android:singleLine="true" /> - <include android:id="@+id/qs_detail_header" layout="@layout/qs_detail_header" diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml new file mode 100644 index 0000000..69f9c14 --- /dev/null +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -0,0 +1,41 @@ +<?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 + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/system_icons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical"> + + <com.android.systemui.statusbar.AlphaOptimizedLinearLayout android:id="@+id/statusIcons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:orientation="horizontal"/> + + <include layout="@layout/signal_cluster_view" + android:id="@+id/signal_cluster" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="2dp"/> + + <!-- battery must be padded below to match assets --> + <com.android.systemui.BatteryMeterView android:id="@+id/battery" + android:layout_height="16dp" + android:layout_width="10.5dp" + android:layout_marginBottom="0.33dp" + android:layout_marginStart="4dip"/> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 8eca0ae..4b037d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -220,7 +220,7 @@ public abstract class BaseStatusBar extends SystemUI implements setZenMode(mode); final boolean show = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1) != 0; - setShowLockscreenNotifications(show); + mShowLockscreenNotifications = show; } }; @@ -1423,7 +1423,8 @@ public abstract class BaseStatusBar extends SystemUI implements } private boolean shouldShowOnKeyguard(StatusBarNotification sbn) { - return sbn.getNotification().priority >= Notification.PRIORITY_LOW; + return mShowLockscreenNotifications && + sbn.getNotification().priority >= Notification.PRIORITY_LOW; } protected void setZenMode(int mode) { @@ -1432,10 +1433,6 @@ public abstract class BaseStatusBar extends SystemUI implements updateNotifications(); } - protected void setShowLockscreenNotifications(boolean show) { - mShowLockscreenNotifications = show; - } - protected abstract void haltTicker(); protected abstract void setAreThereNotifications(); protected abstract void updateNotifications(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java new file mode 100644 index 0000000..bf66c41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -0,0 +1,150 @@ +/* + * 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.phone; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; +import com.android.systemui.statusbar.policy.UserInfoController; + +/** + * The header group on Keyguard. + */ +public class KeyguardStatusBarView extends RelativeLayout + implements BatteryController.BatteryStateChangeCallback { + + private boolean mBatteryCharging; + private boolean mKeyguardUserSwitcherShowing; + private boolean mBatteryListening; + + private View mSystemIconsSuperContainer; + private MultiUserSwitch mMultiUserSwitch; + private ImageView mMultiUserAvatar; + private TextView mBatteryLevel; + + private BatteryController mBatteryController; + private KeyguardUserSwitcher mKeyguardUserSwitcher; + + private int mSystemIconsSwitcherHiddenExpandedMargin; + + public KeyguardStatusBarView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container); + mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); + mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar); + mBatteryLevel = (TextView) findViewById(R.id.battery_level); + loadDimens(); + updateUserSwitcher(); + } + + private void loadDimens() { + mSystemIconsSwitcherHiddenExpandedMargin = getResources().getDimensionPixelSize( + R.dimen.system_icons_switcher_hidden_expanded_margin); + } + + private void updateVisibilities() { + mMultiUserSwitch.setVisibility(!mKeyguardUserSwitcherShowing ? VISIBLE : GONE); + mBatteryLevel.setVisibility(mBatteryCharging ? View.VISIBLE : View.GONE); + } + + private void updateSystemIconsLayoutParams() { + RelativeLayout.LayoutParams lp = + (LayoutParams) mSystemIconsSuperContainer.getLayoutParams(); + int marginEnd = mKeyguardUserSwitcherShowing ? mSystemIconsSwitcherHiddenExpandedMargin : 0; + if (marginEnd != lp.getMarginEnd()) { + lp.setMarginEnd(marginEnd); + mSystemIconsSuperContainer.setLayoutParams(lp); + } + } + + public void setListening(boolean listening) { + if (listening == mBatteryListening) { + return; + } + mBatteryListening = listening; + if (mBatteryListening) { + mBatteryController.addStateChangedCallback(this); + } else { + mBatteryController.removeStateChangedCallback(this); + } + } + + private void updateUserSwitcher() { + boolean keyguardSwitcherAvailable = mKeyguardUserSwitcher != null; + mMultiUserSwitch.setClickable(keyguardSwitcherAvailable); + mMultiUserSwitch.setFocusable(keyguardSwitcherAvailable); + mMultiUserSwitch.setKeyguardMode(keyguardSwitcherAvailable); + } + + public void setBatteryController(BatteryController batteryController) { + mBatteryController = batteryController; + } + + public void setUserInfoController(UserInfoController userInfoController) { + userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() { + @Override + public void onUserInfoChanged(String name, Drawable picture) { + mMultiUserAvatar.setImageDrawable(picture); + } + }); + } + + @Override + public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); + boolean changed = mBatteryCharging != charging; + mBatteryCharging = charging; + if (changed) { + updateVisibilities(); + } + } + + @Override + public void onPowerSaveChanged() { + // could not care less + } + + public void setKeyguardUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { + mKeyguardUserSwitcher = keyguardUserSwitcher; + mMultiUserSwitch.setKeyguardUserSwitcher(keyguardUserSwitcher); + updateUserSwitcher(); + } + + public void setKeyguardUserSwitcherShowing(boolean showing) { + mKeyguardUserSwitcherShowing = showing; + updateVisibilities(); + updateSystemIconsLayoutParams(); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } +} 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 cccfb7b..602b914 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -60,6 +60,7 @@ public class NotificationPanelView extends PanelView implements private KeyguardAffordanceHelper mAfforanceHelper; private StatusBarHeaderView mHeader; + private KeyguardStatusBarView mKeyguardStatusBar; private View mQsContainer; private QSPanel mQsPanel; private View mKeyguardStatusView; @@ -138,6 +139,7 @@ public class NotificationPanelView extends PanelView implements private boolean mIsLaunchTransitionRunning; private Runnable mLaunchAnimationEndRunnable; private boolean mOnlyAffordanceInThisMotion; + private boolean mKeyguardStatusBarAnimatingIn; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -153,6 +155,7 @@ public class NotificationPanelView extends PanelView implements super.onFinishInflate(); mHeader = (StatusBarHeaderView) findViewById(R.id.header); mHeader.setOnClickListener(this); + mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header); mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mQsContainer = findViewById(R.id.quick_settings_container); mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel); @@ -196,11 +199,10 @@ public class NotificationPanelView extends PanelView implements // Update Clock Pivot mKeyguardStatusView.setPivotX(getWidth() / 2); - mKeyguardStatusView.setPivotY( - (FONT_HEIGHT - CAP_HEIGHT) / 2048f * mClockView.getTextSize()); + mKeyguardStatusView.setPivotY((FONT_HEIGHT - CAP_HEIGHT) / 2048f * mClockView.getTextSize()); // Calculate quick setting heights. - mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight; + mQsMinExpansionHeight = mKeyguardShowing ? 0 : mHeader.getCollapsedHeight() + mQsPeekHeight; mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight(); if (mQsExpanded) { if (mQsFullyExpanded) { @@ -223,10 +225,11 @@ public class NotificationPanelView extends PanelView implements private void positionClockAndNotifications() { boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending(); int stackScrollerPadding; - if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { + if (mStatusBarState != StatusBarState.KEYGUARD) { int bottom = mHeader.getCollapsedHeight(); - stackScrollerPadding = bottom + mQsPeekHeight - + mNotificationTopPadding; + stackScrollerPadding = mStatusBarState == StatusBarState.SHADE + ? bottom + mQsPeekHeight + mNotificationTopPadding + : mKeyguardStatusBar.getHeight() + mNotificationTopPadding; mTopPaddingAdjustment = 0; } else { mClockPositionAlgorithm.setup( @@ -671,6 +674,8 @@ public class NotificationPanelView extends PanelView implements public void setBarState(int statusBarState) { boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD || statusBarState == StatusBarState.SHADE_LOCKED; + mKeyguardStatusBar.setAlpha(1f); + mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); if (!mKeyguardShowing && keyguardShowing) { setQsTranslation(mQsExpansionHeight); mHeader.setTranslationY(0f); @@ -682,9 +687,11 @@ public class NotificationPanelView extends PanelView implements private void updateQsState() { boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling; - mHeader.setExpanded(expandVisually, mStackScrollerOverscrolling); - mNotificationStackScroller.setScrollingEnabled(mStatusBarState != StatusBarState.KEYGUARD - && (!mQsExpanded || mQsExpansionFromOverscroll)); + mHeader.setVisibility((mQsExpanded || !mKeyguardShowing) ? View.VISIBLE : View.INVISIBLE); + mHeader.setExpanded(mKeyguardShowing || (mQsExpanded && !mStackScrollerOverscrolling)); + mNotificationStackScroller.setScrollingEnabled( + mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded + || mQsExpansionFromOverscroll)); mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE); mQsContainer.setVisibility( mKeyguardShowing && !expandVisually ? View.INVISIBLE : View.VISIBLE); @@ -700,10 +707,22 @@ public class NotificationPanelView extends PanelView implements setQsExpanded(false); } mQsExpansionHeight = height; - mHeader.setExpansion(getQsExpansionFraction()); + mHeader.setExpansion(getHeaderExpansionFraction()); setQsTranslation(height); requestScrollerTopPaddingUpdate(false /* animate */); updateNotificationScrim(height); + if (mKeyguardShowing) { + float alpha = getQsExpansionFraction(); + alpha *= 2; + alpha = Math.min(1, alpha); + alpha = 1 - alpha; + if (alpha == 0f) { + mKeyguardStatusBar.setVisibility(View.INVISIBLE); + } else { + mKeyguardStatusBar.setVisibility(View.VISIBLE); + mKeyguardStatusBar.setAlpha(alpha); + } + } } private void updateNotificationScrim(float height) { @@ -713,12 +732,33 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setScrimAlpha(progress); } + private float getHeaderExpansionFraction() { + if (!mKeyguardShowing) { + return getQsExpansionFraction(); + } else { + return 1f; + } + } + private void setQsTranslation(float height) { mQsContainer.setY(height - mQsContainer.getHeight() + getHeaderTranslation()); + if (mKeyguardShowing) { + mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0)); + } + } + + private float calculateQsTopPadding() { + if (mKeyguardShowing) { + return interpolate(getQsExpansionFraction(), + mNotificationStackScroller.getIntrinsicPadding() - mNotificationTopPadding, + mQsMaxExpansionHeight); + } else { + return mQsExpansionHeight; + } } private void requestScrollerTopPaddingUpdate(boolean animate) { - mNotificationStackScroller.updateTopPadding(mQsExpansionHeight, + mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(), mScrollView.getScrollY(), mAnimateNextTopPaddingChange || animate); mAnimateNextTopPaddingChange = false; @@ -794,8 +834,9 @@ public class NotificationPanelView extends PanelView implements if (!mQsExpansionEnabled) { return false; } - boolean onHeader = x >= mHeader.getLeft() && x <= mHeader.getRight() - && y >= mHeader.getTop() && y <= mHeader.getBottom(); + View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader; + boolean onHeader = x >= header.getLeft() && x <= header.getRight() + && y >= header.getTop() && y <= header.getBottom(); if (mQsExpanded) { return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0); } else { @@ -862,12 +903,9 @@ public class NotificationPanelView extends PanelView implements } int maxHeight; if (mTwoFingerQsExpand || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted) { - maxHeight = (int) calculatePanelHeightQsExpanded(); + maxHeight = Math.max(calculatePanelHeightQsExpanded(), calculatePanelHeightShade()); } else { - int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin(); - maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin - - mTopPaddingAdjustment; - maxHeight += mNotificationStackScroller.getTopPaddingOverflow(); + maxHeight = calculatePanelHeightShade(); } maxHeight = Math.max(maxHeight, min); return maxHeight; @@ -912,7 +950,15 @@ public class NotificationPanelView extends PanelView implements return qsTempMaxExpansion; } - private float calculatePanelHeightQsExpanded() { + private int calculatePanelHeightShade() { + int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin(); + int maxHeight = mNotificationStackScroller.getHeight() - emptyBottomMargin + - mTopPaddingAdjustment; + maxHeight += mNotificationStackScroller.getTopPaddingOverflow(); + return maxHeight; + } + + private int calculatePanelHeightQsExpanded() { float notificationHeight = mNotificationStackScroller.getHeight() - mNotificationStackScroller.getEmptyBottomMargin() - mNotificationStackScroller.getTopPadding(); @@ -925,7 +971,7 @@ public class NotificationPanelView extends PanelView implements - getScrollViewScrollY(); totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight()); } - return totalHeight; + return (int) totalHeight; } private int getScrollViewScrollY() { @@ -993,7 +1039,6 @@ public class NotificationPanelView extends PanelView implements } private void updateHeaderShade() { - mHeader.setAlpha(1f); mHeader.setTranslationY(getHeaderTranslation()); setQsTranslation(mQsExpansionHeight); } @@ -1014,7 +1059,6 @@ public class NotificationPanelView extends PanelView implements } private void updateHeaderKeyguard() { - mHeader.setTranslationY(0f); float alpha; if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) { @@ -1032,7 +1076,9 @@ public class NotificationPanelView extends PanelView implements } alpha = Math.max(0, Math.min(alpha, 1)); alpha = (float) Math.pow(alpha, 0.75); - mHeader.setAlpha(alpha); + if (!mQsExpanded && !mKeyguardStatusBarAnimatingIn) { + mKeyguardStatusBar.setAlpha(alpha); + } mKeyguardBottomArea.setAlpha(alpha); setQsTranslation(mQsExpansionHeight); } @@ -1062,21 +1108,24 @@ public class NotificationPanelView extends PanelView implements mIsExpanding = false; mScrollYOverride = -1; if (mExpandedHeight == 0f) { - mHeader.setListening(false); - mQsPanel.setListening(false); + setListening(false); } else { - mHeader.setListening(true); - mQsPanel.setListening(true); + setListening(true); } mTwoFingerQsExpand = false; mTwoFingerQsExpandPossible = false; } + private void setListening(boolean listening) { + mHeader.setListening(listening); + mKeyguardStatusBar.setListening(listening); + mQsPanel.setListening(listening); + } + @Override public void instantExpand() { super.instantExpand(); - mHeader.setListening(true); - mQsPanel.setListening(true); + setListening(true); } @Override @@ -1352,4 +1401,8 @@ public class NotificationPanelView extends PanelView implements mEmptyDragAmount = amount * factor; positionClockAndNotifications(); } + + private static float interpolate(float t, float start, float end) { + return (1 - t) * start + t * end; + } } 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 20a4092..0284036 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -252,6 +252,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // left-hand icons LinearLayout mStatusIcons; + LinearLayout mStatusIconsKeyguard; + // the icons themselves IconMerger mNotificationIcons; View mNotificationIconArea; @@ -273,6 +275,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // top bar StatusBarHeaderView mHeader; + KeyguardStatusBarView mKeyguardStatusBar; View mKeyguardStatusView; KeyguardBottomAreaView mKeyguardBottomArea; boolean mLeaveOpenOnKeyguardHide; @@ -406,8 +409,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private Interpolator mLinearOutSlowIn; private Interpolator mLinearInterpolator = new LinearInterpolator(); private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator(); - private Interpolator mAlphaIn = new PathInterpolator(0f, 0.2f, 1f, 1f); - private Interpolator mAlphaOut = new PathInterpolator(0f, 0f, 0.8f, 1f); + public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); + public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); private FrameLayout mBackdrop; private ImageView mBackdropFront, mBackdropBack; @@ -534,12 +537,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, }; @Override - protected void setShowLockscreenNotifications(boolean show) { - super.setShowLockscreenNotifications(show); - updateStackScrollerState(); - } - - @Override public void start() { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); @@ -695,6 +692,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header); mHeader.setActivityStarter(this); + mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); + mStatusIconsKeyguard = (LinearLayout) mKeyguardStatusBar.findViewById(R.id.statusIcons); mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); mKeyguardBottomArea = (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); @@ -744,10 +743,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mZenModeController = mVolumeComponent.getZenController(); mCastController = new CastControllerImpl(mContext); final SignalClusterView signalCluster = - (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster); - + (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); + final SignalClusterView signalClusterKeyguard = + (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); mNetworkController.addSignalCluster(signalCluster); + mNetworkController.addSignalCluster(signalClusterKeyguard); signalCluster.setNetworkController(mNetworkController); + signalClusterKeyguard.setNetworkController(mNetworkController); final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); if (isAPhone) { mNetworkController.addEmergencyLabelView(mHeader); @@ -783,8 +785,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardMonitor = new KeyguardMonitor(); mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, - (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mHeader, - mUserSwitcherController); + (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), + mKeyguardStatusBar, mUserSwitcherController); // Set up the quick settings tile panel @@ -808,9 +810,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // User info. Trigger first load. mHeader.setUserInfoController(mUserInfoController); + mKeyguardStatusBar.setUserInfoController(mUserInfoController); mUserInfoController.reloadUserInfo(); mHeader.setBatteryController(mBatteryController); + mKeyguardStatusBar.setBatteryController(mBatteryController); mHeader.setNextAlarmController(mNextAlarmController); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); @@ -1167,6 +1171,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void refreshAllStatusBarIcons() { refreshAllIconsForLayout(mStatusIcons); + refreshAllIconsForLayout(mStatusIconsKeyguard); refreshAllIconsForLayout(mNotificationIcons); } @@ -1186,19 +1191,26 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, StatusBarIconView view = new StatusBarIconView(mContext, slot, null); view.set(icon); mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); + view = new StatusBarIconView(mContext, slot, null); + view.set(icon); + mStatusIconsKeyguard.addView(view, viewIndex, + new LinearLayout.LayoutParams(mIconSize, mIconSize)); } public void updateIcon(String slot, int index, int viewIndex, StatusBarIcon old, StatusBarIcon icon) { if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + " old=" + old + " icon=" + icon); - StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); + StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex); + view.set(icon); + view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex); view.set(icon); } public void removeIcon(String slot, int index, int viewIndex) { if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); mStatusIcons.removeViewAt(viewIndex); + mStatusIconsKeyguard.removeViewAt(viewIndex); } public UserHandle getCurrentUserHandle() { @@ -1919,7 +1931,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, .alpha(0f) .setDuration(160) .setStartDelay(0) - .setInterpolator(mAlphaOut) + .setInterpolator(ALPHA_OUT) .withEndAction(new Runnable() { @Override public void run() { @@ -1941,7 +1953,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, v.animate() .alpha(1f) .setDuration(320) - .setInterpolator(mAlphaIn) + .setInterpolator(ALPHA_IN) .setStartDelay(50); // Synchronize the motion with the Keyguard fading if necessary. @@ -3378,11 +3390,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { mKeyguardBottomArea.setVisibility(View.VISIBLE); - mHeader.setKeyguardShowing(true); mScrimController.setKeyguardShowing(true); } else { mKeyguardBottomArea.setVisibility(View.GONE); - mHeader.setKeyguardShowing(false); mScrimController.setKeyguardShowing(false); } mNotificationPanel.setBarState(mState); @@ -3398,20 +3408,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private void updateDozingState() { - final boolean bottomGone = mKeyguardBottomArea.getVisibility() == View.GONE; + if (mState != StatusBarState.KEYGUARD) { + return; + } if (mDozing) { mNotificationPanel.setBackgroundColor(0xff000000); - mHeader.setVisibility(View.INVISIBLE); - if (!bottomGone) { - mKeyguardBottomArea.setVisibility(View.INVISIBLE); - } + mKeyguardStatusBar.setVisibility(View.INVISIBLE); + mKeyguardBottomArea.setVisibility(View.INVISIBLE); mStackScroller.setDark(true, false /*animate*/); } else { mNotificationPanel.setBackground(null); - mHeader.setVisibility(View.VISIBLE); - if (!bottomGone) { + mKeyguardStatusBar.setVisibility(View.VISIBLE); mKeyguardBottomArea.setVisibility(View.VISIBLE); - } mStackScroller.setDark(false, false /*animate*/); } mScrimController.setDozing(mDozing); @@ -3421,8 +3429,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mStackScroller == null) return; boolean onKeyguard = mState == StatusBarState.KEYGUARD; mStackScroller.setDimmed(onKeyguard, false /* animate */); - mStackScroller.setVisibility(!mShowLockscreenNotifications && onKeyguard - ? View.INVISIBLE : View.VISIBLE); mStackScroller.setExpandingEnabled(!onKeyguard); ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild(); mStackScroller.setActivatedChild(null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 197bb39..b3051b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -38,7 +38,6 @@ import com.android.systemui.R; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -50,9 +49,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private boolean mExpanded; private boolean mListening; - private boolean mOverscrolled; - private boolean mKeyguardShowing; - private boolean mCharging; private ViewGroup mSystemIconsContainer; private View mSystemIconsSuperContainer; @@ -60,7 +56,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private View mClock; private View mTime; private View mAmPm; - private View mKeyguardCarrierText; private MultiUserSwitch mMultiUserSwitch; private ImageView mMultiUserAvatar; private View mDateCollapsed; @@ -77,29 +72,19 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private TextView mAlarmStatus; private boolean mShowEmergencyCallsOnly; - private boolean mKeyguardUserSwitcherShowing; private boolean mAlarmShowing; private AlarmClockInfo mNextAlarm; private int mCollapsedHeight; private int mExpandedHeight; - private int mKeyguardHeight; - private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT; - private int mNormalWidth; - private int mPadding; private int mMultiUserExpandedMargin; private int mMultiUserCollapsedMargin; - private int mMultiUserKeyguardMargin; - private int mSystemIconsSwitcherHiddenExpandedMargin; + private int mClockMarginBottomExpanded; private int mClockMarginBottomCollapsed; private int mMultiUserSwitchWidthCollapsed; private int mMultiUserSwitchWidthExpanded; - private int mMultiUserSwitchWidthKeyguard; - private int mBatteryPaddingEnd; - private int mBatteryMarginExpanded; - private int mBatteryMarginKeyguard; /** * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice @@ -107,13 +92,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL */ private float mClockCollapsedScaleFactor; private float mAvatarCollapsedScaleFactor; - private float mAvatarKeyguardScaleFactor; private ActivityStarter mActivityStarter; private BatteryController mBatteryController; private NextAlarmController mNextAlarmController; private QSPanel mQSPanel; - private KeyguardUserSwitcher mKeyguardUserSwitcher; + private final Rect mClipBounds = new Rect(); @@ -139,7 +123,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mClock = findViewById(R.id.clock); mTime = findViewById(R.id.time_view); mAmPm = findViewById(R.id.am_pm_view); - mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text); mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar); mDateCollapsed = findViewById(R.id.date_collapsed); @@ -187,7 +170,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (mCaptureValues) { - if (mExpanded && !mOverscrolled) { + if (mExpanded) { captureLayoutValues(mExpandedValues); } else { captureLayoutValues(mCollapsedValues); @@ -207,18 +190,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height); mExpandedHeight = getResources().getDimensionPixelSize( R.dimen.status_bar_header_height_expanded); - mKeyguardHeight = getResources().getDimensionPixelSize( - R.dimen.status_bar_header_height_keyguard); - mNormalWidth = getLayoutParams().width; - mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding); mMultiUserExpandedMargin = getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin); mMultiUserCollapsedMargin = getResources().getDimensionPixelSize(R.dimen.multi_user_switch_collapsed_margin); - mMultiUserKeyguardMargin = - getResources().getDimensionPixelSize(R.dimen.multi_user_switch_keyguard_margin); - mSystemIconsSwitcherHiddenExpandedMargin = getResources().getDimensionPixelSize( - R.dimen.system_icons_switcher_hidden_expanded_margin); + mClockMarginBottomExpanded = getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin); mClockMarginBottomCollapsed = @@ -227,23 +203,12 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed); mMultiUserSwitchWidthExpanded = getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded); - mMultiUserSwitchWidthKeyguard = - getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_keyguard); mAvatarCollapsedScaleFactor = getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size) / (float) mMultiUserAvatar.getLayoutParams().width; - mAvatarKeyguardScaleFactor = - getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size) - / (float) mMultiUserAvatar.getLayoutParams().width; mClockCollapsedScaleFactor = (float) getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size) / (float) getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size); - mBatteryPaddingEnd = - getResources().getDimensionPixelSize(R.dimen.battery_level_padding_end); - mBatteryMarginExpanded = - getResources().getDimensionPixelSize(R.dimen.header_battery_margin_expanded); - mBatteryMarginKeyguard = - getResources().getDimensionPixelSize(R.dimen.header_battery_margin_keyguard); } public void setActivityStarter(ActivityStarter activityStarter) { @@ -259,7 +224,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } public int getCollapsedHeight() { - return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight; + return mCollapsedHeight; } public int getExpandedHeight() { @@ -274,130 +239,73 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateListeners(); } - public void setExpanded(boolean expanded, boolean overscrolled) { + public void setExpanded(boolean expanded) { boolean changed = expanded != mExpanded; - boolean overscrollChanged = overscrolled != mOverscrolled; mExpanded = expanded; - mOverscrolled = overscrolled; - if (changed || overscrollChanged) { + if (changed) { updateHeights(); updateVisibilities(); updateSystemIconsLayoutParams(); - updateZTranslation(); updateClickTargets(); - updateWidth(); - updatePadding(); updateMultiUserSwitch(); if (mQSPanel != null) { - mQSPanel.setExpanded(expanded && !overscrolled); + mQSPanel.setExpanded(expanded); } updateClockScale(); updateAvatarScale(); updateClockLp(); - updateBatteryLevelPaddingEnd(); - updateBatteryLevelLp(); requestCaptureValues(); } } private void updateHeights() { - boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded; - int height; - if (mExpanded && !mOverscrolled) { - height = mExpandedHeight; - } else if (onKeyguardAndCollapsed) { - height = mKeyguardHeight; - } else { - height = mCollapsedHeight; - } + int height = mExpanded ? mExpandedHeight : mCollapsedHeight; ViewGroup.LayoutParams lp = getLayoutParams(); if (lp.height != height) { lp.height = height; setLayoutParams(lp); } - int systemIconsContainerHeight = onKeyguardAndCollapsed ? mKeyguardHeight : mCollapsedHeight; - lp = mSystemIconsSuperContainer.getLayoutParams(); - if (lp.height != systemIconsContainerHeight) { - lp.height = systemIconsContainerHeight; - mSystemIconsSuperContainer.setLayoutParams(lp); - } - lp = mMultiUserSwitch.getLayoutParams(); - if (lp.height != systemIconsContainerHeight) { - lp.height = systemIconsContainerHeight; - mMultiUserSwitch.setLayoutParams(lp); - } - } - - private void updateWidth() { - int width = (mKeyguardShowing && !mExpanded) ? mKeyguardWidth : mNormalWidth; - ViewGroup.LayoutParams lp = getLayoutParams(); - if (width != lp.width) { - lp.width = width; - setLayoutParams(lp); - } } private void updateVisibilities() { - boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded; - if (onKeyguardAndCollapsed) { - setBackground(null); - } else { - setBackgroundResource(R.drawable.notification_header_bg); - } - mDateGroup.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); - mClock.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE); - mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE); - mDateCollapsed.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing - ? View.VISIBLE : View.INVISIBLE); - mDateExpanded.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing - ? View.INVISIBLE : View.VISIBLE); - mAlarmStatus.setVisibility(mExpanded && !mOverscrolled && mAlarmShowing - ? View.VISIBLE : View.INVISIBLE); - mSettingsButton.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.INVISIBLE); + mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); + mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE); + mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); + mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE); mQsDetailHeader.setVisibility(mExpanded ? View.VISIBLE : View.GONE); - if (mStatusIcons != null) { - mStatusIcons.setVisibility(mKeyguardShowing && (!mExpanded || mOverscrolled) - ? View.VISIBLE : View.GONE); - } if (mSignalCluster != null) { updateSignalClusterDetachment(); } - mEmergencyCallsOnly.setVisibility(mExpanded && !mOverscrolled && mShowEmergencyCallsOnly - ? VISIBLE : GONE); - mMultiUserSwitch.setVisibility(mExpanded || !mKeyguardUserSwitcherShowing - ? VISIBLE : GONE); - mBatteryLevel.setVisibility(mKeyguardShowing && mCharging || mExpanded && !mOverscrolled - ? View.VISIBLE : View.GONE); - if (mExpanded && !mOverscrolled && mKeyguardUserSwitcherShowing) { - mKeyguardUserSwitcher.hide(); - } + mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE); + mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE); } private void updateSignalClusterDetachment() { - boolean detached = mExpanded && !mOverscrolled; + boolean detached = mExpanded; if (detached != mSignalClusterDetached) { if (detached) { getOverlay().add(mSignalCluster); } else { - getOverlay().remove(mSignalCluster); - mSystemIcons.addView(mSignalCluster, 1); + reattachSignalCluster(); } } mSignalClusterDetached = detached; } + private void reattachSignalCluster() { + getOverlay().remove(mSignalCluster); + mSystemIcons.addView(mSignalCluster, 1); + } + private void updateSystemIconsLayoutParams() { RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams(); - lp.addRule(RelativeLayout.START_OF, mExpanded && !mOverscrolled + int rule = mExpanded ? mSettingsButton.getId() - : mMultiUserSwitch.getId()); - lp.removeRule(ALIGN_PARENT_START); - if (mMultiUserSwitch.getVisibility() == GONE) { - lp.setMarginEnd(mSystemIconsSwitcherHiddenExpandedMargin); - } else { - lp.setMarginEnd(0); + : mMultiUserSwitch.getId(); + if (rule != lp.getRules()[RelativeLayout.START_OF]) { + lp.addRule(RelativeLayout.START_OF, rule); + mSystemIconsSuperContainer.setLayoutParams(lp); } - mSystemIconsSuperContainer.setLayoutParams(lp); } private void updateListeners() { @@ -411,12 +319,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } private void updateAvatarScale() { - if (mExpanded && !mOverscrolled) { + if (mExpanded) { mMultiUserAvatar.setScaleX(1f); mMultiUserAvatar.setScaleY(1f); - } else if (mKeyguardShowing) { - mMultiUserAvatar.setScaleX(mAvatarKeyguardScaleFactor); - mMultiUserAvatar.setScaleY(mAvatarKeyguardScaleFactor); } else { mMultiUserAvatar.setScaleX(mAvatarCollapsedScaleFactor); mMultiUserAvatar.setScaleY(mAvatarCollapsedScaleFactor); @@ -432,7 +337,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } private float getTimeScale() { - return !mExpanded || mOverscrolled ? mClockCollapsedScaleFactor : 1f; + return !mExpanded ? mClockCollapsedScaleFactor : 1f; } private void updateAmPmTranslation() { @@ -440,20 +345,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mAmPm.setTranslationX((rtl ? 1 : -1) * mTime.getWidth() * (1 - mTime.getScaleX())); } - private void updateBatteryLevelPaddingEnd() { - mBatteryLevel.setPaddingRelative(0, 0, - mKeyguardShowing && !mExpanded ? 0 : mBatteryPaddingEnd, 0); - } - @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); - boolean changed = mCharging != charging; - mCharging = charging; - if (changed) { - updateVisibilities(); - requestCaptureValues(); - } } @Override @@ -472,37 +366,14 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL requestCaptureValues(); } - private void updateClickTargets() { - setClickable(!mKeyguardShowing || mExpanded); - - boolean keyguardSwitcherAvailable = - mKeyguardUserSwitcher != null && mKeyguardShowing && !mExpanded; - mMultiUserSwitch.setClickable(mExpanded || keyguardSwitcherAvailable); - mMultiUserSwitch.setKeyguardMode(keyguardSwitcherAvailable); + mMultiUserSwitch.setClickable(mExpanded); mSystemIconsSuperContainer.setClickable(mExpanded); mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null); } - private void updateZTranslation() { - - // If we are on the Keyguard, we need to set our z position to zero, so we don't get - // shadows. - if (mKeyguardShowing && !mExpanded) { - setZ(0); - } else { - setTranslationZ(0); - } - } - - private void updatePadding() { - boolean padded = !mKeyguardShowing || mExpanded; - int padding = padded ? mPadding : 0; - setPaddingRelative(padding, 0, padding, 0); - } - private void updateClockLp() { - int marginBottom = mExpanded && !mOverscrolled + int marginBottom = mExpanded ? mClockMarginBottomExpanded : mClockMarginBottomCollapsed; LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams(); @@ -515,12 +386,9 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private void updateMultiUserSwitch() { int marginEnd; int width; - if (mExpanded && !mOverscrolled) { + if (mExpanded) { marginEnd = mMultiUserExpandedMargin; width = mMultiUserSwitchWidthExpanded; - } else if (mKeyguardShowing) { - marginEnd = mMultiUserKeyguardMargin; - width = mMultiUserSwitchWidthKeyguard; } else { marginEnd = mMultiUserCollapsedMargin; width = mMultiUserSwitchWidthCollapsed; @@ -533,19 +401,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } } - private void updateBatteryLevelLp() { - int marginStart = mExpanded && !mOverscrolled - ? mBatteryMarginExpanded - : mBatteryMarginKeyguard; - MarginLayoutParams lp = (MarginLayoutParams) mBatteryLevel.getLayoutParams(); - if (marginStart != lp.getMarginStart()) { - lp.setMarginStart(marginStart); - mBatteryLevel.setLayoutParams(lp); - } - } - public void setExpansion(float t) { - if (mOverscrolled) { + if (!mExpanded) { t = 0f; } mCurrentT = t; @@ -580,12 +437,18 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mSignalCluster = systemIcons.findViewById(R.id.signal_cluster); mSystemIcons = systemIcons; updateVisibilities(); + if (mStatusIcons != null) { + mStatusIcons.setVisibility(View.GONE); + } } public void onSystemIconsDetached() { + if (mSignalClusterDetached) { + reattachSignalCluster(); + mSignalClusterDetached = false; + } if (mStatusIcons != null) { mStatusIcons.setVisibility(View.VISIBLE); - mStatusIcons.setAlpha(1f); } if (mSignalCluster != null) { mSignalCluster.setVisibility(View.VISIBLE); @@ -598,20 +461,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mSystemIcons = null; } - public void setKeyguardShowing(boolean keyguardShowing) { - mKeyguardShowing = keyguardShowing; - updateHeights(); - updateWidth(); - updateVisibilities(); - updateZTranslation(); - updatePadding(); - updateMultiUserSwitch(); - updateClickTargets(); - updateBatteryLevelPaddingEnd(); - updateAvatarScale(); - mCaptureValues = true; - } - public void setUserInfoController(UserInfoController userInfoController) { userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() { @Override @@ -651,11 +500,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mMultiUserSwitch.setQsPanel(qsp); } - public void setKeyguarUserSwitcher(KeyguardUserSwitcher keyguardUserSwitcher) { - mKeyguardUserSwitcher = keyguardUserSwitcher; - mMultiUserSwitch.setKeyguardUserSwitcher(keyguardUserSwitcher); - } - @Override public boolean shouldDelayChildPressedState() { return true; @@ -665,20 +509,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mShowEmergencyCallsOnly = show; if (mExpanded) { updateVisibilities(); + requestCaptureValues(); } } - public void setKeyguardUserSwitcherShowing(boolean showing) { - mKeyguardUserSwitcherShowing = showing; - updateVisibilities(); - updateSystemIconsLayoutParams(); - } - - @Override - public boolean hasOverlappingRendering() { - return !mKeyguardShowing || mExpanded; - } - @Override protected void dispatchSetPressed(boolean pressed) { // We don't want that everything lights up when we click on the header, so block the request @@ -700,11 +534,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop(); target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel); target.settingsAlpha = getAlphaForVisibility(mSettingsButton); - target.settingsTranslation = mExpanded && !mOverscrolled + target.settingsTranslation = mExpanded ? 0 : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft(); target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f; - target.settingsRotation = !mExpanded || mOverscrolled ? 90f : 0f; + target.settingsRotation = !mExpanded ? 90f : 0f; } private float getAlphaForVisibility(View v) { @@ -735,7 +569,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mMultiUserAvatar.setY(values.avatarY - mMultiUserSwitch.getTop()); mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getRight()); mSystemIconsSuperContainer.setY(values.batteryY - mSystemIconsContainer.getTop()); - if (mSignalCluster != null && mExpanded && !mOverscrolled) { + if (mSignalCluster != null && mExpanded) { mSignalCluster.setX(mSystemIconsSuperContainer.getX() - mSignalCluster.getWidth()); mSignalCluster.setY( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java index 2be566c..6795842 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -16,10 +16,6 @@ package com.android.systemui.statusbar.policy; -import com.android.systemui.R; -import com.android.systemui.statusbar.phone.StatusBarHeaderView; -import com.android.systemui.statusbar.phone.UserAvatarView; - import android.content.Context; import android.database.DataSetObserver; import android.provider.Settings; @@ -29,6 +25,10 @@ import android.view.ViewGroup; import android.view.ViewStub; import android.widget.TextView; +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.KeyguardStatusBarView; +import com.android.systemui.statusbar.phone.UserAvatarView; + /** * Manages the user switcher on the Keyguard. */ @@ -40,23 +40,23 @@ public class KeyguardUserSwitcher { "lockscreenSimpleUserSwitcher"; private final ViewGroup mUserSwitcher; - private final StatusBarHeaderView mHeader; + private final KeyguardStatusBarView mStatusBarView; private final Adapter mAdapter; private final boolean mSimpleUserSwitcher; public KeyguardUserSwitcher(Context context, ViewStub userSwitcher, - StatusBarHeaderView header, UserSwitcherController userSwitcherController) { + KeyguardStatusBarView statusBarView, UserSwitcherController userSwitcherController) { if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) { mUserSwitcher = (ViewGroup) userSwitcher.inflate(); - mHeader = header; - mHeader.setKeyguarUserSwitcher(this); + mStatusBarView = statusBarView; + mStatusBarView.setKeyguardUserSwitcher(this); mAdapter = new Adapter(context, userSwitcherController); mAdapter.registerDataSetObserver(mDataSetObserver); mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(), SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0; } else { mUserSwitcher = null; - mHeader = null; + mStatusBarView = null; mAdapter = null; mSimpleUserSwitcher = false; } @@ -84,7 +84,7 @@ public class KeyguardUserSwitcher { if (mUserSwitcher != null) { // TODO: animate mUserSwitcher.setVisibility(View.VISIBLE); - mHeader.setKeyguardUserSwitcherShowing(true); + mStatusBarView.setKeyguardUserSwitcherShowing(true); } } @@ -92,7 +92,7 @@ public class KeyguardUserSwitcher { if (mUserSwitcher != null) { // TODO: animate mUserSwitcher.setVisibility(View.GONE); - mHeader.setKeyguardUserSwitcherShowing(false); + mStatusBarView.setKeyguardUserSwitcherShowing(false); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index fdc91a4..ff3cd9d 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -50,7 +50,6 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.session.MediaController; -import android.media.session.MediaSession; import android.media.session.MediaSessionLegacyHelper; import android.net.Uri; import android.os.Bundle; @@ -63,6 +62,7 @@ import android.transition.Scene; import android.transition.Transition; import android.transition.TransitionInflater; import android.transition.TransitionManager; +import android.transition.TransitionSet; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; import android.util.EventLog; @@ -126,6 +126,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { (1 << FEATURE_CONTENT_TRANSITIONS) | (1 << FEATURE_ACTION_MODE_OVERLAY); + private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet(); + /** * Simple callback used by the context menu and its submenus. The options * menu submenus do not use this (their behavior is more complex). @@ -254,10 +256,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } }; - private Transition mEnterTransition; - private Transition mExitTransition; - private Transition mSharedElementEnterTransition; - private Transition mSharedElementExitTransition; + private Transition mEnterTransition = null; + private Transition mReturnTransition = USE_DEFAULT_TRANSITION; + private Transition mExitTransition = null; + private Transition mReenterTransition = USE_DEFAULT_TRANSITION; + private Transition mSharedElementEnterTransition = null; + private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION; + private Transition mSharedElementExitTransition = null; + private Transition mSharedElementReenterTransition = USE_DEFAULT_TRANSITION; private Boolean mAllowExitTransitionOverlap; private Boolean mAllowEnterTransitionOverlap; private long mBackgroundFadeDurationMillis = -1; @@ -3513,40 +3519,47 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - mEnterTransition = getTransition(mEnterTransition, + mEnterTransition = getTransition(mEnterTransition, null, R.styleable.Window_windowEnterTransition); - mExitTransition = getTransition(mExitTransition, + mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION, + R.styleable.Window_windowReturnTransition); + mExitTransition = getTransition(mExitTransition, null, R.styleable.Window_windowExitTransition); - mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, + mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION, + R.styleable.Window_windowReenterTransition); + mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null, R.styleable.Window_windowSharedElementEnterTransition); - mSharedElementExitTransition = getTransition(mSharedElementExitTransition, + mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition, + USE_DEFAULT_TRANSITION, + R.styleable.Window_windowSharedElementReturnTransition); + mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null, R.styleable.Window_windowSharedElementExitTransition); + mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition, + USE_DEFAULT_TRANSITION, + R.styleable.Window_windowSharedElementReenterTransition); if (mAllowEnterTransitionOverlap == null) { mAllowEnterTransitionOverlap = getWindowStyle().getBoolean( - R.styleable. - Window_windowAllowEnterTransitionOverlap, true); + R.styleable.Window_windowAllowEnterTransitionOverlap, true); } if (mAllowExitTransitionOverlap == null) { mAllowExitTransitionOverlap = getWindowStyle().getBoolean( - R.styleable. - Window_windowAllowExitTransitionOverlap, true); + R.styleable.Window_windowAllowExitTransitionOverlap, true); } if (mBackgroundFadeDurationMillis < 0) { mBackgroundFadeDurationMillis = getWindowStyle().getInteger( - R.styleable. - Window_windowTransitionBackgroundFadeDuration, + R.styleable.Window_windowTransitionBackgroundFadeDuration, DEFAULT_BACKGROUND_FADE_DURATION_MS); } } } } - private Transition getTransition(Transition currentValue, int id) { - if (currentValue != null) { + private Transition getTransition(Transition currentValue, Transition defaultValue, int id) { + if (currentValue != defaultValue) { return currentValue; } int transitionId = getWindowStyle().getResourceId(id, -1); - Transition transition = null; + Transition transition = defaultValue; if (transitionId != -1 && transitionId != R.transition.no_transition) { TransitionInflater inflater = TransitionInflater.from(getContext()); transition = inflater.inflateTransition(transitionId); @@ -3899,41 +3912,85 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public void setReturnTransition(Transition transition) { + mReturnTransition = transition; + } + + @Override public void setExitTransition(Transition exitTransition) { mExitTransition = exitTransition; } @Override + public void setReenterTransition(Transition transition) { + mReenterTransition = transition; + } + + @Override public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) { mSharedElementEnterTransition = sharedElementEnterTransition; } @Override + public void setSharedElementReturnTransition(Transition transition) { + mSharedElementReturnTransition = transition; + } + + @Override public void setSharedElementExitTransition(Transition sharedElementExitTransition) { mSharedElementExitTransition = sharedElementExitTransition; } @Override + public void setSharedElementReenterTransition(Transition transition) { + mSharedElementReenterTransition = transition; + } + + @Override public Transition getEnterTransition() { return mEnterTransition; } @Override + public Transition getReturnTransition() { + return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition() + : mReturnTransition; + } + + @Override public Transition getExitTransition() { return mExitTransition; } @Override + public Transition getReenterTransition() { + return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition() + : mReenterTransition; + } + + @Override public Transition getSharedElementEnterTransition() { return mSharedElementEnterTransition; } @Override + public Transition getSharedElementReturnTransition() { + return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION + ? getSharedElementEnterTransition() : mSharedElementReturnTransition; + } + + @Override public Transition getSharedElementExitTransition() { return mSharedElementExitTransition; } @Override + public Transition getSharedElementReenterTransition() { + return mSharedElementReenterTransition == USE_DEFAULT_TRANSITION + ? getSharedElementExitTransition() : mSharedElementReenterTransition; + } + + @Override public void setAllowEnterTransitionOverlap(boolean allow) { mAllowEnterTransitionOverlap = allow; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7aa69fd..5382489 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -556,6 +556,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } + + public void dump(IndentingPrintWriter pw) { + for (int type = 0; type < mTypeLists.length; type++) { + if (mTypeLists[type] == null) continue; + pw.print(type + " "); + pw.increaseIndent(); + if (mTypeLists[type].size() == 0) pw.println("none"); + for (NetworkAgentInfo nai : mTypeLists[type]) { + pw.println(nai.name()); + } + pw.decreaseIndent(); + } + } } private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(); @@ -1680,6 +1693,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.println(); pw.decreaseIndent(); + pw.println("mActiveDefaultNetwork:" + mActiveDefaultNetwork); + pw.println("mLegacyTypeTracker:"); + pw.increaseIndent(); + mLegacyTypeTracker.dump(pw); + pw.decreaseIndent(); + pw.println(); + synchronized (this) { pw.println("NetworkTranstionWakeLock is currently " + (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held."); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 3a4e2ee..28a6917 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -482,33 +482,36 @@ public class LocationManagerService extends ILocationManager.Stub { } // bind to fused hardware provider if supported + // in devices without support, requesting an instance of FlpHardwareProvider will raise an + // exception, so make sure we only do that when supported + FlpHardwareProvider flpHardwareProvider; if (FlpHardwareProvider.isSupported()) { - FlpHardwareProvider flpHardwareProvider = - FlpHardwareProvider.getInstance(mContext); - FusedProxy fusedProxy = FusedProxy.createAndBind( - mContext, - mLocationHandler, - flpHardwareProvider.getLocationHardware(), - com.android.internal.R.bool.config_enableHardwareFlpOverlay, - com.android.internal.R.string.config_hardwareFlpPackageName, - com.android.internal.R.array.config_locationProviderPackageNames); - if(fusedProxy == null) { - Slog.e(TAG, "Unable to bind FusedProxy."); - } - - // bind to geofence provider - GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, - com.android.internal.R.bool.config_enableGeofenceOverlay, - com.android.internal.R.string.config_geofenceProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler, - gpsProvider.getGpsGeofenceProxy(), - flpHardwareProvider.getGeofenceHardware()); - if (provider == null) { - Slog.e(TAG, "Unable to bind FLP Geofence proxy."); - } + flpHardwareProvider = FlpHardwareProvider.getInstance(mContext); + FusedProxy fusedProxy = FusedProxy.createAndBind( + mContext, + mLocationHandler, + flpHardwareProvider.getLocationHardware(), + com.android.internal.R.bool.config_enableHardwareFlpOverlay, + com.android.internal.R.string.config_hardwareFlpPackageName, + com.android.internal.R.array.config_locationProviderPackageNames); + if (fusedProxy == null) { + Slog.e(TAG, "Unable to bind FusedProxy."); + } } else { - Slog.e(TAG, "FLP HAL not supported."); + flpHardwareProvider = null; + Slog.e(TAG, "FLP HAL not supported"); + } + + // bind to geofence provider + GeofenceProxy provider = GeofenceProxy.createAndBind( + mContext,com.android.internal.R.bool.config_enableGeofenceOverlay, + com.android.internal.R.string.config_geofenceProviderPackageName, + com.android.internal.R.array.config_locationProviderPackageNames, + mLocationHandler, + gpsProvider.getGpsGeofenceProxy(), + flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null); + if (provider == null) { + Slog.e(TAG, "Unable to bind FLP Geofence proxy."); } // bind to the hardware activity recognition if supported diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index f59edc7..4c6b772 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -73,6 +73,7 @@ final class UiModeManagerService extends SystemService { private boolean mTelevision; private boolean mWatch; private boolean mComputedNightMode; + private int mCarModeEnableFlags; int mCurUiMode = 0; private int mSetUiMode = 0; @@ -193,7 +194,7 @@ final class UiModeManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - setCarModeLocked(true); + setCarModeLocked(true, flags); if (mSystemReady) { updateLocked(flags, 0); } @@ -208,7 +209,7 @@ final class UiModeManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - setCarModeLocked(false); + setCarModeLocked(false, 0); if (mSystemReady) { updateLocked(0, flags); } @@ -285,7 +286,8 @@ final class UiModeManagerService extends SystemService { pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); - pw.print(" mComputedNightMode="); pw.println(mComputedNightMode); + pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); + pw.print(" mCarModeEnableFlags="); pw.println(mCarModeEnableFlags); pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); @@ -311,17 +313,18 @@ final class UiModeManagerService extends SystemService { return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; } - void setCarModeLocked(boolean enabled) { + void setCarModeLocked(boolean enabled, int flags) { if (mCarModeEnabled != enabled) { mCarModeEnabled = enabled; } + mCarModeEnableFlags = flags; } private void updateDockState(int newState) { synchronized (mLock) { if (newState != mDockState) { mDockState = newState; - setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR); + setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR, 0); if (mSystemReady) { updateLocked(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME, 0); } @@ -475,7 +478,8 @@ final class UiModeManagerService extends SystemService { // keep screen on when charging and in car mode boolean keepScreenOn = mCharging && - ((mCarModeEnabled && mCarModeKeepsScreenOn) || + ((mCarModeEnabled && mCarModeKeepsScreenOn && + (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_NO_WAKE_LOCK) == 0) || (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn)); if (keepScreenOn != mWakeLock.isHeld()) { if (keepScreenOn) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 9a86136..2a66baf 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -3144,6 +3144,9 @@ public class AccountManagerService DevicePolicyManager dpm = (DevicePolicyManager) mContext .getSystemService(Context.DEVICE_POLICY_SERVICE); String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId); + if (typesArray == null) { + return true; + } for (String forbiddenType : typesArray) { if (forbiddenType.equals(accountType)) { return false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cfdf7cf..9a58c56 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3638,6 +3638,27 @@ public final class ActivityManagerService extends ActivityManagerNative return ret; } + //explicitly remove thd old information in mRecentTasks when removing existing user. + private void removeRecentTasksForUser(int userId) { + if(userId <= 0) { + Slog.i(TAG, "Can't remove recent task on user " + userId); + return; + } + + for (int i = mRecentTasks.size() - 1; i >= 0; --i) { + TaskRecord tr = mRecentTasks.get(i); + if (tr.userId == userId) { + if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr + + " when finishing user" + userId); + tr.disposeThumbnail(); + mRecentTasks.remove(i); + } + } + + // Remove tasks from persistent storage. + mTaskPersister.wakeup(null, true); + } + final void addRecentTaskLocked(TaskRecord task) { int N = mRecentTasks.size(); // Quick case: check if the top-most recent task is the same. @@ -10966,11 +10987,17 @@ public final class ActivityManagerService extends ActivityManagerNative int uid = r != null ? r.info.uid : Binder.getCallingUid(); if (!mController.appCrashed(name, pid, shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) { - Slog.w(TAG, "Force-killing crashed app " + name - + " at watcher's request"); - Process.killProcess(pid); - if (r != null) { - Process.killProcessGroup(uid, pid); + if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")) + && "Native crash".equals(crashInfo.exceptionClassName)) { + Slog.w(TAG, "Skip killing native crashed app " + name + + "(" + pid + ") during testing"); + } else { + Slog.w(TAG, "Force-killing crashed app " + name + + " at watcher's request"); + Process.killProcess(pid); + if (r != null) { + Process.killProcessGroup(uid, pid); + } } return; } @@ -17636,6 +17663,9 @@ public final class ActivityManagerService extends ActivityManagerNative } } + // Explicitly remove the old information in mRecentTasks. + removeRecentTasksForUser(userId); + for (int i=0; i<callbacks.size(); i++) { try { if (stopped) callbacks.get(i).userStopped(userId); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 75df136..c5bc7d3 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1882,6 +1882,10 @@ final class ActivityStack { boolean startIt = true; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { task = mTaskHistory.get(taskNdx); + if (task.getTopActivity() == null) { + // All activities in task are finishing. + continue; + } if (task == r.task) { // Here it is! Now, if this is not yet visible to the // user, then just add it without starting; it will diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index b9dd609..eddf414 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -684,6 +684,11 @@ public class Vpn { if (((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == app.uid)) { return; } + // SystemUI dialogs are also allowed to control VPN. + ApplicationInfo sysUiApp = pm.getApplicationInfo("com.android.systemui", 0); + if (((sysUiApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0) && (appId == sysUiApp.uid)) { + return; + } } catch (Exception e) { // ignore } finally { diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 390d121..bb9355e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -281,7 +281,7 @@ public final class HdmiControlService extends SystemService { // A container for [Logical Address, Local device info]. final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); final SparseIntArray finished = new SparseIntArray(); - mCecController.clearLogicalAddress(); + clearLocalDevices(); for (int type : deviceTypes) { final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); localDevice.init(); @@ -1415,7 +1415,9 @@ public final class HdmiControlService extends SystemService { devices.remove(device); if (devices.isEmpty()) { onStandbyCompleted(); - clearLocalDevices(); + // We will not clear local devices here, since some OEM/SOC will keep passing + // the received packets until the application processor enters to the sleep + // actually. } } }); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a277f91..53006f3 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -50,6 +50,7 @@ import android.media.AudioManager; import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -1273,7 +1274,7 @@ public class NotificationManagerService extends SystemService { final int N = mNotificationList.size(); for (int i=0; i<N; i++) { StatusBarNotification sbn = mNotificationList.get(i).sbn; - if (info.enabledAndUserMatches(sbn.getUserId())) { + if (isVisibleToListener(sbn, info)) { list.add(sbn); } } @@ -1625,7 +1626,6 @@ public class NotificationManagerService extends SystemService { // Make sure we don't lose the foreground service state. notification.flags |= old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; - mNotificationsByKey.remove(old.sbn.getKey()); r.isUpdate = true; } @@ -1643,7 +1643,8 @@ public class NotificationManagerService extends SystemService { mRankingHelper.sort(mNotificationList); if (notification.icon != 0) { - mListeners.notifyPostedLocked(n); + StatusBarNotification oldSbn = (old != null) ? old.sbn : null; + mListeners.notifyPostedLocked(n, oldSbn); } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); if (old != null && !old.isCanceled) { @@ -2154,6 +2155,8 @@ public class NotificationManagerService extends SystemService { break; } + mNotificationsByKey.remove(r.sbn.getKey()); + // Save it for users of getHistoricalNotifications() mArchive.record(r.sbn); } @@ -2196,7 +2199,6 @@ public class NotificationManagerService extends SystemService { } mNotificationList.remove(index); - mNotificationsByKey.remove(r.sbn.getKey()); cancelNotificationLocked(r, sendDelete, reason); cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName); @@ -2272,7 +2274,6 @@ public class NotificationManagerService extends SystemService { return true; } mNotificationList.remove(i); - mNotificationsByKey.remove(r.sbn.getKey()); cancelNotificationLocked(r, false, reason); } if (doit && canceledNotifications != null) { @@ -2312,7 +2313,6 @@ public class NotificationManagerService extends SystemService { if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR)) == 0) { mNotificationList.remove(i); - mNotificationsByKey.remove(r.sbn.getKey()); cancelNotificationLocked(r, true, reason); // Make a note so we can cancel children later. if (canceledNotifications == null) { @@ -2333,7 +2333,7 @@ public class NotificationManagerService extends SystemService { private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid, String listenerName) { Notification n = r.getNotification(); - if (n.getGroup() == null || (n.flags & Notification.FLAG_GROUP_SUMMARY) == 0) { + if (!n.isGroupSummary()) { return; } @@ -2356,7 +2356,6 @@ public class NotificationManagerService extends SystemService { pkg, childSbn.getId(), childSbn.getTag(), userId, 0, 0, REASON_GROUP_SUMMARY_CANCELED, listenerName); mNotificationList.remove(i); - mNotificationsByKey.remove(childR.getKey()); cancelNotificationLocked(childR, false, REASON_GROUP_SUMMARY_CANCELED); } } @@ -2487,7 +2486,7 @@ public class NotificationManagerService extends SystemService { ArrayList<String> interceptedKeys = new ArrayList<String>(N); for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); - if (!info.enabledAndUserMatches(record.sbn.getUserId())) { + if (!isVisibleToListener(record.sbn, info)) { continue; } keys.add(record.sbn.getKey()); @@ -2504,6 +2503,17 @@ public class NotificationManagerService extends SystemService { return new NotificationRankingUpdate(keysAr, interceptedKeysAr, speedBumpIndex); } + private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { + if (!listener.enabledAndUserMatches(sbn.getUserId())) { + return false; + } + Notification n = sbn.getNotification(); + if (listener.targetSdkVersion < Build.VERSION_CODES.L && n.isGroupChild()) { + return false; + } + return true; + } + public class NotificationListeners extends ManagedServices { public NotificationListeners() { @@ -2550,22 +2560,39 @@ public class NotificationManagerService extends SystemService { /** * asynchronously notify all listeners about a new notification + * + * <p> + * Also takes care of removing a notification that has been visible to a listener before, + * but isn't anymore. */ - public void notifyPostedLocked(StatusBarNotification sbn) { + public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { // make a copy in case changes are made to the underlying Notification object final StatusBarNotification sbnClone = sbn.clone(); for (final ManagedServiceInfo info : mServices) { - if (!info.isEnabledForCurrentProfiles()) { + boolean sbnVisible = isVisibleToListener(sbn, info); + boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; + // This notification hasn't been and still isn't visible -> ignore. + if (!oldSbnVisible && !sbnVisible) { continue; } final NotificationRankingUpdate update = makeRankingUpdateLocked(info); - if (update.getOrderedKeys().length == 0) { + + // This notification became invisible -> remove the old one. + if (oldSbnVisible && !sbnVisible) { + final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); + mHandler.post(new Runnable() { + @Override + public void run() { + notifyRemoved(info, oldSbnLightClone, update); + } + }); continue; } + mHandler.post(new Runnable() { @Override public void run() { - notifyPostedIfUserMatch(info, sbnClone, update); + notifyPosted(info, sbnClone, update); } }); } @@ -2580,14 +2607,14 @@ public class NotificationManagerService extends SystemService { // notification final StatusBarNotification sbnLight = sbn.cloneLight(); for (final ManagedServiceInfo info : mServices) { - if (!info.isEnabledForCurrentProfiles()) { + if (!isVisibleToListener(sbn, info)) { continue; } final NotificationRankingUpdate update = makeRankingUpdateLocked(info); mHandler.post(new Runnable() { @Override public void run() { - notifyRemovedIfUserMatch(info, sbnLight, update); + notifyRemoved(info, sbnLight, update); } }); } @@ -2601,8 +2628,7 @@ public class NotificationManagerService extends SystemService { if (!serviceInfo.isEnabledForCurrentProfiles()) { continue; } - final NotificationRankingUpdate update = - makeRankingUpdateLocked(serviceInfo); + final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo); mHandler.post(new Runnable() { @Override public void run() { @@ -2626,11 +2652,8 @@ public class NotificationManagerService extends SystemService { } } - private void notifyPostedIfUserMatch(final ManagedServiceInfo info, + private void notifyPosted(final ManagedServiceInfo info, final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { - if (!info.enabledAndUserMatches(sbn.getUserId())) { - return; - } final INotificationListener listener = (INotificationListener)info.service; try { listener.onNotificationPosted(sbn, rankingUpdate); @@ -2639,7 +2662,7 @@ public class NotificationManagerService extends SystemService { } } - private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn, + private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { if (!info.enabledAndUserMatches(sbn.getUserId())) { return; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 6036bcf..1650768 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -19,7 +19,22 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INSTALL_ALL_USERS; import static android.content.pm.PackageManager.INSTALL_FROM_ADB; import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING; - +import static com.android.internal.util.XmlUtils.readBitmapAttribute; +import static com.android.internal.util.XmlUtils.readBooleanAttribute; +import static com.android.internal.util.XmlUtils.readIntAttribute; +import static com.android.internal.util.XmlUtils.readLongAttribute; +import static com.android.internal.util.XmlUtils.readStringAttribute; +import static com.android.internal.util.XmlUtils.readUriAttribute; +import static com.android.internal.util.XmlUtils.writeBitmapAttribute; +import static com.android.internal.util.XmlUtils.writeBooleanAttribute; +import static com.android.internal.util.XmlUtils.writeIntAttribute; +import static com.android.internal.util.XmlUtils.writeLongAttribute; +import static com.android.internal.util.XmlUtils.writeStringAttribute; +import static com.android.internal.util.XmlUtils.writeUriAttribute; +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.START_TAG; + +import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.IPackageDeleteObserver; @@ -29,9 +44,14 @@ import android.content.pm.IPackageInstallerSession; import android.content.pm.InstallSessionInfo; import android.content.pm.InstallSessionParams; import android.content.pm.PackageManager; +import android.graphics.Bitmap; import android.os.Binder; +import android.os.Environment; import android.os.FileUtils; +import android.os.Handler; import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -40,30 +60,70 @@ import android.os.UserHandle; import android.os.UserManager; import android.system.ErrnoException; import android.system.Os; +import android.text.format.DateUtils; import android.util.ArraySet; +import android.util.AtomicFile; import android.util.ExceptionUtils; +import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.Xml; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.server.IoThread; +import com.android.server.pm.PackageInstallerSession.Snapshot; import com.google.android.collect.Sets; +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Random; public class PackageInstallerService extends IPackageInstaller.Stub { private static final String TAG = "PackageInstaller"; + private static final boolean LOGD = true; - // TODO: destroy sessions with old timestamps // TODO: remove outstanding sessions when installer package goes away // TODO: notify listeners in other users when package has been installed there + /** XML constants used in {@link #mSessionsFile} */ + private static final String TAG_SESSIONS = "sessions"; + private static final String TAG_SESSION = "session"; + private static final String ATTR_SESSION_ID = "sessionId"; + private static final String ATTR_USER_ID = "userId"; + private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName"; + private static final String ATTR_CREATED_MILLIS = "createdMillis"; + private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; + private static final String ATTR_SEALED = "sealed"; + private static final String ATTR_MODE = "mode"; + private static final String ATTR_INSTALL_FLAGS = "installFlags"; + private static final String ATTR_INSTALL_LOCATION = "installLocation"; + private static final String ATTR_SIZE_BYTES = "sizeBytes"; + private static final String ATTR_APP_PACKAGE_NAME = "appPackageName"; + private static final String ATTR_APP_ICON = "appIcon"; + private static final String ATTR_APP_LABEL = "appLabel"; + private static final String ATTR_ORIGINATING_URI = "originatingUri"; + private static final String ATTR_REFERRER_URI = "referrerUri"; + private static final String ATTR_ABI_OVERRIDE = "abiOverride"; + + private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS; + private static final long MAX_ACTIVE_SESSIONS = 1024; + private final Context mContext; private final PackageManagerService mPm; private final AppOpsManager mAppOps; @@ -71,10 +131,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private final File mStagingDir; private final HandlerThread mInstallThread; - private final Callback mCallback = new Callback(); + private final Callbacks mCallbacks; + + /** + * File storing persisted {@link #mSessions}. + */ + private final AtomicFile mSessionsFile; + + private final InternalCallback mInternalCallback = new InternalCallback(); + + /** + * Used for generating session IDs. Since this is created at boot time, + * normal random might be predictable. + */ + private final Random mRandom = new SecureRandom(); - @GuardedBy("mSessions") - private int mNextSessionId; @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); @@ -82,8 +153,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); - private RemoteCallbackList<IPackageInstallerCallback> mCallbacks = new RemoteCallbackList<>(); - private static final FilenameFilter sStageFilter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { @@ -101,6 +170,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { mInstallThread = new HandlerThread(TAG); mInstallThread.start(); + mCallbacks = new Callbacks(mInstallThread.getLooper()); + + mSessionsFile = new AtomicFile( + new File(Environment.getSystemSecureDirectory(), "install_sessions.xml")); + synchronized (mSessions) { readSessionsLocked(); @@ -133,13 +207,140 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } private void readSessionsLocked() { - // TODO: implement persisting + if (LOGD) Slog.v(TAG, "readSessionsLocked()"); + mSessions.clear(); - mNextSessionId = 1; + + FileInputStream fis = null; + try { + fis = mSessionsFile.openRead(); + final XmlPullParser in = Xml.newPullParser(); + in.setInput(fis, null); + + int type; + while ((type = in.next()) != END_DOCUMENT) { + if (type == START_TAG) { + final String tag = in.getName(); + if (TAG_SESSION.equals(tag)) { + final PackageInstallerSession session = readSessionLocked(in); + final long age = System.currentTimeMillis() - session.createdMillis; + + final boolean valid; + if (age >= MAX_AGE_MILLIS) { + Slog.w(TAG, "Abandoning old session first created at " + + session.createdMillis); + valid = false; + } else if (!session.sessionStageDir.exists()) { + Slog.w(TAG, "Abandoning session with missing stage " + + session.sessionStageDir); + valid = false; + } else { + valid = true; + } + + if (valid) { + mSessions.put(session.sessionId, session); + } else { + // Since this is early during boot we don't send + // any observer events about the session, but we + // keep details around for dumpsys. + mHistoricalSessions.put(session.sessionId, session); + } + } + } + } + } catch (FileNotFoundException e) { + // Missing sessions are okay, probably first boot + } catch (IOException e) { + Log.wtf(TAG, "Failed reading install sessions", e); + } catch (XmlPullParserException e) { + Log.wtf(TAG, "Failed reading install sessions", e); + } finally { + IoUtils.closeQuietly(fis); + } + } + + private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException { + final int sessionId = readIntAttribute(in, ATTR_SESSION_ID); + final int userId = readIntAttribute(in, ATTR_USER_ID); + final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME); + final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS); + final File sessionStageDir = new File(readStringAttribute(in, ATTR_SESSION_STAGE_DIR)); + final boolean sealed = readBooleanAttribute(in, ATTR_SEALED); + + final InstallSessionParams params = new InstallSessionParams( + InstallSessionParams.MODE_INVALID); + params.mode = readIntAttribute(in, ATTR_MODE); + params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); + params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); + params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES); + params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME); + params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON); + params.appLabel = readStringAttribute(in, ATTR_APP_LABEL); + params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI); + params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI); + params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE); + + return new PackageInstallerSession(mInternalCallback, mPm, mInstallThread.getLooper(), + sessionId, userId, installerPackageName, params, createdMillis, sessionStageDir, + sealed); } private void writeSessionsLocked() { - // TODO: implement persisting + if (LOGD) Slog.v(TAG, "writeSessionsLocked()"); + + FileOutputStream fos = null; + try { + fos = mSessionsFile.startWrite(); + + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, "utf-8"); + out.startDocument(null, true); + out.startTag(null, TAG_SESSIONS); + final int size = mSessions.size(); + for (int i = 0; i < size; i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + writeSessionLocked(out, session); + } + out.endTag(null, TAG_SESSIONS); + out.endDocument(); + + mSessionsFile.finishWrite(fos); + } catch (IOException e) { + if (fos != null) { + mSessionsFile.failWrite(fos); + } + } + } + + private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session) + throws IOException { + final InstallSessionParams params = session.params; + final Snapshot snapshot = session.snapshot(); + + out.startTag(null, TAG_SESSION); + + writeIntAttribute(out, ATTR_SESSION_ID, session.sessionId); + writeIntAttribute(out, ATTR_USER_ID, session.userId); + writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME, + session.installerPackageName); + writeLongAttribute(out, ATTR_CREATED_MILLIS, session.createdMillis); + writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, + session.sessionStageDir.getAbsolutePath()); + writeBooleanAttribute(out, ATTR_SEALED, snapshot.sealed); + + writeIntAttribute(out, ATTR_MODE, params.mode); + writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags); + writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation); + writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes); + writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName); + writeBitmapAttribute(out, ATTR_APP_ICON, params.appIcon); + writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel); + writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri); + writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri); + writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride); + + out.endTag(null, TAG_SESSION); } private void writeSessionsAsync() { @@ -163,8 +364,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { throw new SecurityException("User restriction prevents installing"); } - if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) { + if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { + installerPackageName = "com.android.shell"; + params.installFlags |= INSTALL_FROM_ADB; + } else { mAppOps.checkPackage(callingUid, installerPackageName); @@ -181,6 +385,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub { throw new IllegalArgumentException("Params must have valid mode set"); } + // Defensively resize giant app icons + if (params.appIcon != null) { + final ActivityManager am = (ActivityManager) mContext.getSystemService( + Context.ACTIVITY_SERVICE); + final int iconSize = am.getLauncherLargeIconSize(); + if ((params.appIcon.getWidth() > iconSize * 2) + || (params.appIcon.getHeight() > iconSize * 2)) { + params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, + true); + } + } + // Sanity check that install could fit if (params.sizeBytes > 0) { try { @@ -193,18 +409,24 @@ public class PackageInstallerService extends IPackageInstaller.Stub { final int sessionId; final PackageInstallerSession session; synchronized (mSessions) { + // Sanity check that installer isn't going crazy + final int activeCount = getSessionCountLocked(callingUid); + if (activeCount >= MAX_ACTIVE_SESSIONS) { + throw new IllegalStateException("Too many active sessions for UID " + callingUid); + } + sessionId = allocateSessionIdLocked(); final long createdMillis = System.currentTimeMillis(); final File sessionStageDir = prepareSessionStageDir(sessionId); - session = new PackageInstallerSession(mCallback, mPm, sessionId, userId, - installerPackageName, callingUid, params, createdMillis, sessionStageDir, - mInstallThread.getLooper()); + session = new PackageInstallerSession(mInternalCallback, mPm, + mInstallThread.getLooper(), sessionId, userId, installerPackageName, params, + createdMillis, sessionStageDir, false); mSessions.put(sessionId, session); } - notifySessionCreated(session.generateInfo()); + mCallbacks.notifySessionCreated(session.sessionId, session.userId); writeSessionsAsync(); return sessionId; } @@ -216,25 +438,34 @@ public class PackageInstallerService extends IPackageInstaller.Stub { if (session == null) { throw new IllegalStateException("Missing session " + sessionId); } - if (Binder.getCallingUid() != session.installerUid) { + if (!isCallingUidOwner(session)) { throw new SecurityException("Caller has no access to session " + sessionId); } + if (session.openCount.getAndIncrement() == 0) { + mCallbacks.notifySessionOpened(sessionId, session.userId); + } return session; } } private int allocateSessionIdLocked() { - if (mSessions.get(mNextSessionId) != null) { - throw new IllegalStateException("Next session already allocated"); - } - return mNextSessionId++; + int n = 0; + int sessionId; + do { + sessionId = mRandom.nextInt(Integer.MAX_VALUE); + if (mSessions.get(sessionId) == null) { + return sessionId; + } + } while (n++ < 32); + + throw new IllegalStateException("Failed to allocate session ID"); } private File prepareSessionStageDir(int sessionId) { final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp"); if (file.exists()) { - throw new IllegalStateException(); + throw new IllegalStateException("Session dir already exists: " + file); } try { @@ -246,7 +477,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } if (!SELinux.restorecon(file)) { - throw new IllegalStateException("Failed to prepare session dir"); + throw new IllegalStateException("Failed to restorecon session dir"); } return file; @@ -256,9 +487,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { public InstallSessionInfo getSessionInfo(int sessionId) { synchronized (mSessions) { final PackageInstallerSession session = mSessions.get(sessionId); - final boolean isOwner = (session != null) - && (session.installerUid == Binder.getCallingUid()); - if (!isOwner) { + if (!isCallingUidOwner(session)) { enforceCallerCanReadSessions(); } return session != null ? session.generateInfo() : null; @@ -323,7 +552,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback"); enforceCallerCanReadSessions(); - mCallbacks.register(callback, new UserHandle(userId)); + mCallbacks.register(callback, userId); } @Override @@ -331,9 +560,24 @@ public class PackageInstallerService extends IPackageInstaller.Stub { mCallbacks.unregister(callback); } - private int getSessionUserId(int sessionId) { - synchronized (mSessions) { - return UserHandle.getUserId(mSessions.get(sessionId).installerUid); + private int getSessionCountLocked(int installerUid) { + int count = 0; + final int size = mSessions.size(); + for (int i = 0; i < size; i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + if (session.installerUid == installerUid) { + count++; + } + } + return count; + } + + private boolean isCallingUidOwner(PackageInstallerSession session) { + final int callingUid = Binder.getCallingUid(); + if (callingUid == Process.ROOT_UID) { + return true; + } else { + return (session != null) && (callingUid == session.installerUid); } } @@ -352,53 +596,87 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } - private void notifySessionCreated(InstallSessionInfo info) { - final int userId = getSessionUserId(info.sessionId); - final int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); - final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); - // TODO: dispatch notifications for slave profiles - if (userId == user.getIdentifier()) { - try { - callback.onSessionCreated(info.sessionId); - } catch (RemoteException ignored) { - } - } + private static class Callbacks extends Handler { + private static final int MSG_SESSION_CREATED = 1; + private static final int MSG_SESSION_OPENED = 2; + private static final int MSG_SESSION_PROGRESS_CHANGED = 3; + private static final int MSG_SESSION_CLOSED = 4; + private static final int MSG_SESSION_FINISHED = 5; + + private final RemoteCallbackList<IPackageInstallerCallback> + mCallbacks = new RemoteCallbackList<>(); + + public Callbacks(Looper looper) { + super(looper); } - mCallbacks.finishBroadcast(); - } - private void notifySessionProgressChanged(int sessionId, float progress) { - final int userId = getSessionUserId(sessionId); - final int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); - final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); - if (userId == user.getIdentifier()) { - try { - callback.onSessionProgressChanged(sessionId, progress); - } catch (RemoteException ignored) { + public void register(IPackageInstallerCallback callback, int userId) { + mCallbacks.register(callback, new UserHandle(userId)); + } + + public void unregister(IPackageInstallerCallback callback) { + mCallbacks.unregister(callback); + } + + @Override + public void handleMessage(Message msg) { + final int userId = msg.arg2; + final int n = mCallbacks.beginBroadcast(); + for (int i = 0; i < n; i++) { + final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); + final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); + // TODO: dispatch notifications for slave profiles + if (userId == user.getIdentifier()) { + try { + invokeCallback(callback, msg); + } catch (RemoteException ignored) { + } } } + mCallbacks.finishBroadcast(); } - mCallbacks.finishBroadcast(); - } - private void notifySessionFinished(int sessionId, boolean success) { - final int userId = getSessionUserId(sessionId); - final int n = mCallbacks.beginBroadcast(); - for (int i = 0; i < n; i++) { - final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); - final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); - if (userId == user.getIdentifier()) { - try { - callback.onSessionFinished(sessionId, success); - } catch (RemoteException ignored) { - } + private void invokeCallback(IPackageInstallerCallback callback, Message msg) + throws RemoteException { + final int sessionId = msg.arg1; + switch (msg.what) { + case MSG_SESSION_CREATED: + callback.onSessionCreated(sessionId); + break; + case MSG_SESSION_OPENED: + callback.onSessionOpened(sessionId); + break; + case MSG_SESSION_PROGRESS_CHANGED: + callback.onSessionProgressChanged(sessionId, (float) msg.obj); + break; + case MSG_SESSION_CLOSED: + callback.onSessionClosed(sessionId); + break; + case MSG_SESSION_FINISHED: + callback.onSessionFinished(sessionId, (boolean) msg.obj); + break; } } - mCallbacks.finishBroadcast(); + + private void notifySessionCreated(int sessionId, int userId) { + obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); + } + + private void notifySessionOpened(int sessionId, int userId) { + obtainMessage(MSG_SESSION_OPENED, sessionId, userId).sendToTarget(); + } + + private void notifySessionProgressChanged(int sessionId, int userId, float progress) { + obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, userId, progress).sendToTarget(); + } + + private void notifySessionClosed(int sessionId, int userId) { + obtainMessage(MSG_SESSION_CLOSED, sessionId, userId).sendToTarget(); + } + + public void notifySessionFinished(int sessionId, int userId, boolean success) { + obtainMessage(MSG_SESSION_FINISHED, sessionId, userId, success).sendToTarget(); + } } void dump(IndentingPrintWriter pw) { @@ -427,13 +705,17 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } - class Callback { + class InternalCallback { public void onSessionProgressChanged(PackageInstallerSession session, float progress) { - notifySessionProgressChanged(session.sessionId, progress); + mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); + } + + public void onSessionClosed(PackageInstallerSession session) { + mCallbacks.notifySessionClosed(session.sessionId, session.userId); } public void onSessionFinished(PackageInstallerSession session, boolean success) { - notifySessionFinished(session.sessionId, success); + mCallbacks.notifySessionFinished(session.sessionId, session.userId, success); synchronized (mSessions) { mSessions.remove(session.sessionId); mHistoricalSessions.put(session.sessionId, session); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 06e1d53..26019db 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; import static android.system.OsConstants.O_CREAT; +import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; import android.content.pm.ApplicationInfo; @@ -40,7 +41,6 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; -import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.system.ErrnoException; @@ -52,6 +52,7 @@ import android.util.ExceptionUtils; import android.util.MathUtils; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -62,33 +63,64 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String TAG = "PackageInstaller"; private static final boolean LOGD = true; + private static final int MSG_COMMIT = 0; + // TODO: enforce INSTALL_ALLOW_TEST // TODO: enforce INSTALL_ALLOW_DOWNGRADE // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL // TODO: treat INHERIT_EXISTING as installExistingPackage() - private final PackageInstallerService.Callback mCallback; + private final PackageInstallerService.InternalCallback mCallback; private final PackageManagerService mPm; private final Handler mHandler; - public final int sessionId; - public final int userId; - public final String installerPackageName; - /** UID not persisted */ - public final int installerUid; - public final InstallSessionParams params; - public final long createdMillis; - public final File sessionStageDir; + final int sessionId; + final int userId; + final String installerPackageName; + final InstallSessionParams params; + final long createdMillis; + final File sessionStageDir; - private static final int MSG_COMMIT = 0; + /** Note that UID is not persisted; it's always derived at runtime. */ + final int installerUid; + + AtomicInteger openCount = new AtomicInteger(); + + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private float mClientProgress = 0; + @GuardedBy("mLock") + private float mProgress = 0; + @GuardedBy("mLock") + private float mReportedProgress = -1; + + @GuardedBy("mLock") + private boolean mSealed = false; + @GuardedBy("mLock") + private boolean mPermissionsConfirmed = false; + @GuardedBy("mLock") + private boolean mDestroyed = false; + + @GuardedBy("mLock") + private ArrayList<FileBridge> mBridges = new ArrayList<>(); - private Handler.Callback mHandlerCallback = new Handler.Callback() { + @GuardedBy("mLock") + private IPackageInstallObserver2 mRemoteObserver; + + /** Fields derived from commit parsing */ + private String mPackageName; + private int mVersionCode; + private Signature[] mSignatures; + + private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { synchronized (mLock) { @@ -114,27 +146,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } }; - private final Object mLock = new Object(); - - private float mClientProgress; - private float mProgress = 0; - - private String mPackageName; - private int mVersionCode; - private Signature[] mSignatures; - - private boolean mMutationsAllowed; - private boolean mPermissionsConfirmed; - private boolean mInvalid; - - private ArrayList<FileBridge> mBridges = new ArrayList<>(); - - private IPackageInstallObserver2 mRemoteObserver; - - public PackageInstallerSession(PackageInstallerService.Callback callback, - PackageManagerService pm, int sessionId, int userId, String installerPackageName, - int installerUid, InstallSessionParams params, long createdMillis, File sessionStageDir, - Looper looper) { + public PackageInstallerSession(PackageInstallerService.InternalCallback callback, + PackageManagerService pm, Looper looper, int sessionId, int userId, + String installerPackageName, InstallSessionParams params, long createdMillis, + File sessionStageDir, boolean sealed) { mCallback = callback; mPm = pm; mHandler = new Handler(looper, mHandlerCallback); @@ -142,24 +157,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { this.sessionId = sessionId; this.userId = userId; this.installerPackageName = installerPackageName; - this.installerUid = installerUid; this.params = params; this.createdMillis = createdMillis; this.sessionStageDir = sessionStageDir; - // Check against any explicitly provided signatures - mSignatures = params.signatures; + mSealed = sealed; - // TODO: splice in flag when restoring persisted session - mMutationsAllowed = true; + // Always derived at runtime + installerUid = mPm.getPackageUid(installerPackageName, userId); - if (pm.checkPermission(android.Manifest.permission.INSTALL_PACKAGES, installerPackageName) - == PackageManager.PERMISSION_GRANTED) { - mPermissionsConfirmed = true; - } - if (installerUid == Process.SHELL_UID || installerUid == 0) { + if (mPm.checkPermission(android.Manifest.permission.INSTALL_PACKAGES, + installerPackageName) == PackageManager.PERMISSION_GRANTED) { mPermissionsConfirmed = true; + } else { + mPermissionsConfirmed = false; } + + computeProgressLocked(); } public InstallSessionInfo generateInfo() { @@ -168,6 +182,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.sessionId = sessionId; info.installerPackageName = installerPackageName; info.progress = mProgress; + info.open = openCount.get() > 0; info.mode = params.mode; info.sizeBytes = params.sizeBytes; @@ -178,16 +193,48 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return info; } + private void assertNotSealed(String cookie) { + synchronized (mLock) { + if (mSealed) { + throw new SecurityException(cookie + " not allowed after commit"); + } + } + } + @Override public void setClientProgress(float progress) { - mClientProgress = progress; - mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f); - mCallback.onSessionProgressChanged(this, mProgress); + synchronized (mLock) { + mClientProgress = progress; + computeProgressLocked(); + } + maybePublishProgress(); } @Override public void addClientProgress(float progress) { - setClientProgress(mClientProgress + progress); + synchronized (mLock) { + mClientProgress += progress; + computeProgressLocked(); + } + maybePublishProgress(); + } + + private void computeProgressLocked() { + mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f); + } + + private void maybePublishProgress() { + // Only publish when meaningful change + if (Math.abs(mProgress - mReportedProgress) > 0.01) { + mReportedProgress = mProgress; + mCallback.onSessionProgressChanged(this, mProgress); + } + } + + @Override + public String[] list() { + assertNotSealed("list"); + return sessionStageDir.list(); } @Override @@ -208,9 +255,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // will block any attempted install transitions. final FileBridge bridge; synchronized (mLock) { - if (!mMutationsAllowed) { - throw new IllegalStateException("Mutations not allowed"); - } + assertNotSealed("openWrite"); bridge = new FileBridge(); mBridges.add(bridge); @@ -252,25 +297,51 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override + public ParcelFileDescriptor openRead(String name) { + try { + return openReadInternal(name); + } catch (IOException e) { + throw ExceptionUtils.wrap(e); + } + } + + private ParcelFileDescriptor openReadInternal(String name) throws IOException { + assertNotSealed("openRead"); + + try { + if (!FileUtils.isValidExtFilename(name)) { + throw new IllegalArgumentException("Invalid name: " + name); + } + final File target = new File(sessionStageDir, name); + + final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0); + return new ParcelFileDescriptor(targetFd); + + } catch (ErrnoException e) { + throw e.rethrowAsIOException(); + } + } + + @Override public void commit(IPackageInstallObserver2 observer) { Preconditions.checkNotNull(observer); mHandler.obtainMessage(MSG_COMMIT, observer).sendToTarget(); } private void commitLocked() throws PackageManagerException { - if (mInvalid) { + if (mDestroyed) { throw new PackageManagerException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session"); } // Verify that all writers are hands-off - if (mMutationsAllowed) { + if (!mSealed) { for (FileBridge bridge : mBridges) { if (!bridge.isClosed()) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, "Files still open"); } } - mMutationsAllowed = false; + mSealed = true; // TODO: persist disabled mutations before going forward, since // beyond this point we may have hardlinks to the valid install @@ -331,6 +402,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void validateInstallLocked() throws PackageManagerException { mPackageName = null; mVersionCode = -1; + mSignatures = null; final File[] files = sessionStageDir.listFiles(); if (ArrayUtils.isEmpty(files)) { @@ -461,7 +533,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void close() { - // Currently ignored + if (openCount.decrementAndGet() == 0) { + mCallback.onSessionClosed(this); + } } @Override @@ -475,7 +549,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void destroyInternal() { synchronized (mLock) { - mInvalid = true; + mSealed = true; + mDestroyed = true; } FileUtils.deleteContents(sessionStageDir); sessionStageDir.delete(); @@ -496,11 +571,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mClientProgress", mClientProgress); pw.printPair("mProgress", mProgress); - pw.printPair("mMutationsAllowed", mMutationsAllowed); + pw.printPair("mSealed", mSealed); pw.printPair("mPermissionsConfirmed", mPermissionsConfirmed); + pw.printPair("mDestroyed", mDestroyed); pw.printPair("mBridges", mBridges.size()); pw.println(); pw.decreaseIndent(); } + + Snapshot snapshot() { + return new Snapshot(this); + } + + static class Snapshot { + final float clientProgress; + final boolean sealed; + + public Snapshot(PackageInstallerSession session) { + clientProgress = session.mClientProgress; + sealed = session.mSealed; + } + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ee6d4d0..2b55bf5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8257,11 +8257,11 @@ public class PackageManagerService extends IPackageManager.Stub { // A restore should be performed at this point if (a) the install // succeeded, (b) the operation is not an update, and (c) the new - // package has a backupAgent defined. + // package has not opted out of backup participation. final boolean update = res.removedInfo.removedPackage != null; - boolean doRestore = (!update - && res.pkg != null - && res.pkg.applicationInfo.backupAgentName != null); + final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags; + boolean doRestore = !update + && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0); // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java index c6213f9..e7dd82d 100644 --- a/services/core/java/com/android/server/tv/TvInputHal.java +++ b/services/core/java/com/android/server/tv/TvInputHal.java @@ -23,6 +23,8 @@ import android.os.HandlerThread; import android.os.Message; import android.view.Surface; import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseIntArray; import java.util.LinkedList; import java.util.Queue; @@ -62,58 +64,70 @@ final class TvInputHal implements Handler.Callback { int generation); private static native void nativeClose(long ptr); + private Object mLock = new Object(); private long mPtr = 0; private final Callback mCallback; private final Handler mHandler; - private int mStreamConfigGeneration = 0; - private TvStreamConfig[] mStreamConfigs; + private SparseIntArray mStreamConfigGenerations = new SparseIntArray(); + private SparseArray<TvStreamConfig[]> mStreamConfigs = new SparseArray<>();; public TvInputHal(Callback callback) { mCallback = callback; mHandler = new Handler(this); } - public synchronized void init() { - mPtr = nativeOpen(); + public void init() { + synchronized (mLock) { + mPtr = nativeOpen(); + } } - public synchronized int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { - if (mPtr == 0) { - return ERROR_NO_INIT; - } - if (mStreamConfigGeneration != streamConfig.getGeneration()) { - return ERROR_STALE_CONFIG; - } - if (nativeAddStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { - return SUCCESS; - } else { - return ERROR_UNKNOWN; + public int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { + synchronized (mLock) { + if (mPtr == 0) { + return ERROR_NO_INIT; + } + int generation = mStreamConfigGenerations.get(deviceId, 0); + if (generation != streamConfig.getGeneration()) { + return ERROR_STALE_CONFIG; + } + if (nativeAddStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { + return SUCCESS; + } else { + return ERROR_UNKNOWN; + } } } - public synchronized int removeStream(int deviceId, TvStreamConfig streamConfig) { - if (mPtr == 0) { - return ERROR_NO_INIT; - } - if (mStreamConfigGeneration != streamConfig.getGeneration()) { - return ERROR_STALE_CONFIG; - } - if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) { - return SUCCESS; - } else { - return ERROR_UNKNOWN; + public int removeStream(int deviceId, TvStreamConfig streamConfig) { + synchronized (mLock) { + if (mPtr == 0) { + return ERROR_NO_INIT; + } + int generation = mStreamConfigGenerations.get(deviceId, 0); + if (generation != streamConfig.getGeneration()) { + return ERROR_STALE_CONFIG; + } + if (nativeRemoveStream(mPtr, deviceId, streamConfig.getStreamId()) == 0) { + return SUCCESS; + } else { + return ERROR_UNKNOWN; + } } } - public synchronized void close() { - if (mPtr != 0l) { - nativeClose(mPtr); + public void close() { + synchronized (mLock) { + if (mPtr != 0l) { + nativeClose(mPtr); + } } } - private synchronized void retrieveStreamConfigs(int deviceId) { - ++mStreamConfigGeneration; - mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration); + private void retrieveStreamConfigsLocked(int deviceId) { + int generation = mStreamConfigGenerations.get(deviceId, 0) + 1; + mStreamConfigs.put(deviceId, nativeGetStreamConfigs(mPtr, deviceId, generation)); + mStreamConfigGenerations.put(deviceId, generation); } // Called from native @@ -145,12 +159,16 @@ final class TvInputHal implements Handler.Callback { public boolean handleMessage(Message msg) { switch (msg.what) { case EVENT_DEVICE_AVAILABLE: { + TvStreamConfig[] configs; TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj; - retrieveStreamConfigs(info.getDeviceId()); - if (DEBUG) { - Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info); + synchronized (mLock) { + retrieveStreamConfigsLocked(info.getDeviceId()); + if (DEBUG) { + Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info); + } + configs = mStreamConfigs.get(info.getDeviceId()); } - mCallback.onDeviceAvailable(info, mStreamConfigs); + mCallback.onDeviceAvailable(info, configs); break; } @@ -164,12 +182,16 @@ final class TvInputHal implements Handler.Callback { } case EVENT_STREAM_CONFIGURATION_CHANGED: { + TvStreamConfig[] configs; int deviceId = msg.arg1; - if (DEBUG) { - Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId); + synchronized (mLock) { + if (DEBUG) { + Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId); + } + retrieveStreamConfigsLocked(deviceId); + configs = mStreamConfigs.get(deviceId); } - retrieveStreamConfigs(deviceId); - mCallback.onStreamConfigurationChanged(deviceId, mStreamConfigs); + mCallback.onStreamConfigurationChanged(deviceId, configs); break; } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 5d34eda..16597c0 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -537,6 +537,24 @@ public final class TvInputManagerService extends SystemService { } @Override + public void onTrackSelectionChanged(List<TvTrackInfo> selectedTracks) { + synchronized (mLock) { + if (DEBUG) { + Slog.d(TAG, "onTrackSelectionChanged(" + selectedTracks + ")"); + } + if (sessionState.mSession == null || sessionState.mClient == null) { + return; + } + try { + sessionState.mClient.onTrackSelectionChanged(selectedTracks, + sessionState.mSeq); + } catch (RemoteException e) { + Slog.e(TAG, "error in onTrackSelectionChanged"); + } + } + } + + @Override public void onVideoAvailable() { synchronized (mLock) { if (DEBUG) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 670ba55..80dfb91 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -19,7 +19,6 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import android.app.admin.DevicePolicyManager; import android.app.AppOpsManager; import android.util.ArraySet; import android.util.TimeUtils; @@ -2455,37 +2454,24 @@ public class WindowManagerService extends IWindowManager.Stub */ boolean isScreenCaptureDisabledLocked(int userId) { Boolean disabled = mScreenCaptureDisabled.get(userId); - if (disabled != null) { - return disabled; - } - - // mScreenCaptureDisabled not set yet, try to update it. - updateScreenCaptureDisabledLocked(userId); - disabled = mScreenCaptureDisabled.get(userId); if (disabled == null) { - // Not able to update, return false by default. return false; - } else { - return disabled; } + return disabled; } /** - * Update mScreenCaptureDisabled for specific user according to the device policy manager. + * Set mScreenCaptureDisabled for specific user */ @Override - public void updateScreenCaptureDisabled(int userId) { - mH.sendMessage(mH.obtainMessage(H.UPDATE_SCRN_CAP, userId, 0 /* unused argument */)); - } + public void setScreenCaptureDisabled(int userId, boolean disabled) { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID) { + throw new SecurityException("Only system can call setScreenCaptureDisabled."); + } - void updateScreenCaptureDisabledLocked(int userId) { - DevicePolicyManager dpm = (DevicePolicyManager) mContext - .getSystemService(Context.DEVICE_POLICY_SERVICE); - if (dpm != null) { - boolean disabled = dpm.getScreenCaptureDisabled(null, userId); + synchronized(mWindowMap) { mScreenCaptureDisabled.put(userId, disabled); - } else { - Slog.e(TAG, "Could not get DevicePolicyManager."); } } @@ -7293,9 +7279,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NEW_ANIMATOR_SCALE = 34; - public static final int UPDATE_SCRN_CAP = 35; - - public static final int SHOW_DISPLAY_MASK = 36; + public static final int SHOW_DISPLAY_MASK = 35; @Override public void handleMessage(Message msg) { @@ -7776,13 +7760,6 @@ public class WindowManagerService extends IWindowManager.Stub } } break; - - case UPDATE_SCRN_CAP: { - synchronized (mWindowMap) { - updateScreenCaptureDisabledLocked(msg.arg1); - } - } - break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "handleMessage: exit"); diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp index c2fccc1..2519ff8 100644 --- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -364,7 +364,9 @@ static void TranslateGeofenceFromGeofenceHardwareRequestParcelable( "()I"); options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition); - // TODO: set data.sources_to_use when available + jmethodID getSourceTechnologies = + env->GetMethodID(geofenceRequestClass, "getSourceTechnologies", "()I"); + options->sources_to_use = env->CallIntMethod(geofenceRequestObject, getSourceTechnologies); env->DeleteLocalRef(geofenceRequestClass); } diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index 41976ff..5eb627b 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -351,6 +351,8 @@ int JTvInputHal::addStream(int deviceId, int streamId, const sp<Surface>& surfac ALOGE("Cannot find a config with given stream ID: %d", streamId); return BAD_VALUE; } + connection.mStreamType = configs[configIndex].type; + tv_stream_t stream; stream.stream_id = configs[configIndex].stream_id; if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 6ab504c..c6730bf 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -791,6 +791,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policyFile.delete(); Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); } + updateScreenCaptureDisabledInWindowManager(userHandle, false /* default value */); } void loadDeviceOwner() { @@ -1367,6 +1368,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { new SetupContentObserver(mHandler).register(mContext.getContentResolver()); // Initialize the user setup state, to handle the upgrade case. updateUserSetupComplete(); + + // Update the screen capture disabled cache in the window manager + List<UserInfo> users = mUserManager.getUsers(true); + final int N = users.size(); + for (int i = 0; i < N; i++) { + int userHandle = users.get(i).id; + updateScreenCaptureDisabledInWindowManager(userHandle, + getScreenCaptureDisabled(null, userHandle)); + } + } private void cleanUpOldUsers() { @@ -3062,11 +3073,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (ap.disableScreenCapture != disabled) { ap.disableScreenCapture = disabled; saveSettingsLocked(userHandle); - try { - getWindowManager().updateScreenCaptureDisabled(userHandle); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify WindowManager.", e); - } + updateScreenCaptureDisabledInWindowManager(userHandle, disabled); } } } @@ -3097,6 +3104,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void updateScreenCaptureDisabledInWindowManager(int userHandle, boolean disabled) { + long ident = Binder.clearCallingIdentity(); + try { + getWindowManager().setScreenCaptureDisabled(userHandle, disabled); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unable to notify WindowManager.", e); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + /** * The system property used to share the state of the camera. The native camera service * is expected to read this property and act accordingly. diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java index 15ec629..0eac1c4 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java @@ -31,6 +31,7 @@ import android.util.Slog; import android.util.SparseArray; import java.util.ArrayList; +import java.util.UUID; /** * Helper for {@link SoundTrigger} APIs. @@ -63,6 +64,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { private final SparseArray<IRecognitionStatusCallback> mActiveListeners; private int mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE; + private UUID mCurrentSoundModelUuid = null; SoundTriggerHelper() { ArrayList <ModuleProperties> modules = new ArrayList<>(); @@ -109,18 +111,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { + ", recognitionConfig=" + recognitionConfig); Slog.d(TAG, "moduleProperties=" + moduleProperties); Slog.d(TAG, "# of current listeners=" + mActiveListeners.size()); - Slog.d(TAG, "mCurrentSoundModelHandle=" + mCurrentSoundModelHandle); + Slog.d(TAG, "current SoundModel handle=" + mCurrentSoundModelHandle); + Slog.d(TAG, "current SoundModel UUID=" + + (mCurrentSoundModelUuid == null ? null : mCurrentSoundModelUuid)); } if (moduleProperties == null || mModule == null) { Slog.w(TAG, "Attempting startRecognition without the capability"); return STATUS_ERROR; } - if (mCurrentSoundModelHandle != INVALID_SOUND_MODEL_HANDLE) { + if (mCurrentSoundModelHandle != INVALID_SOUND_MODEL_HANDLE + && !soundModel.uuid.equals(mCurrentSoundModelUuid)) { Slog.w(TAG, "Unloading previous sound model"); - // TODO: Inspect the return codes here. - mModule.unloadSoundModel(mCurrentSoundModelHandle); + int status = mModule.unloadSoundModel(mCurrentSoundModelHandle); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "unloadSoundModel call failed with " + status); + return status; + } mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE; + mCurrentSoundModelUuid = null; } // If the previous recognition was by a different listener, @@ -136,26 +145,35 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { mActiveListeners.remove(keyphraseId); } - int[] handle = new int[] { INVALID_SOUND_MODEL_HANDLE }; - int status = mModule.loadSoundModel(soundModel, handle); - if (status != SoundTrigger.STATUS_OK) { - Slog.w(TAG, "loadSoundModel call failed with " + status); - return STATUS_ERROR; - } - if (handle[0] == INVALID_SOUND_MODEL_HANDLE) { - Slog.w(TAG, "loadSoundModel call returned invalid sound model handle"); - return STATUS_ERROR; + // Load the sound model if the current one is null. + int soundModelHandle = mCurrentSoundModelHandle; + if (mCurrentSoundModelHandle == INVALID_SOUND_MODEL_HANDLE + || mCurrentSoundModelUuid == null) { + int[] handle = new int[] { INVALID_SOUND_MODEL_HANDLE }; + int status = mModule.loadSoundModel(soundModel, handle); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "loadSoundModel call failed with " + status); + return status; + } + if (handle[0] == INVALID_SOUND_MODEL_HANDLE) { + Slog.w(TAG, "loadSoundModel call returned invalid sound model handle"); + return STATUS_ERROR; + } + soundModelHandle = handle[0]; + } else { + if (DBG) Slog.d(TAG, "Reusing previously loaded sound model"); } // Start the recognition. - status = mModule.startRecognition(handle[0], recognitionConfig); + int status = mModule.startRecognition(soundModelHandle, recognitionConfig); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "startRecognition failed with " + status); - return STATUS_ERROR; + return status; } // Everything went well! - mCurrentSoundModelHandle = handle[0]; + mCurrentSoundModelHandle = soundModelHandle; + mCurrentSoundModelUuid = soundModel.uuid; // Register the new listener. This replaces the old one. // There can only be a maximum of one active listener for a keyphrase // at any given time. @@ -194,14 +212,12 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition"); return STATUS_ERROR; } else if (currentListener.asBinder() != listener.asBinder()) { - // TODO: Figure out if this should match the listener that was passed in during - // startRecognition, or should we allow a different listener to stop the recognition, - // in which case we don't need to pass in a listener here. + // We don't allow a different listener to stop the recognition than the one + // that started it. Slog.w(TAG, "Attempting stopRecognition for another recognition"); return STATUS_ERROR; } else { // Stop recognition if it's the current one, ignore otherwise. - // TODO: Inspect the return codes here. int status = mModule.stopRecognition(mCurrentSoundModelHandle); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "stopRecognition call failed with " + status); @@ -214,6 +230,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE; + mCurrentSoundModelUuid = null; + mActiveListeners.remove(keyphraseId); return STATUS_OK; } @@ -285,6 +303,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { Slog.w(TAG, "RemoteException in onDetectionStopped"); } mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE; + mCurrentSoundModelUuid = null; // Remove all listeners. mActiveListeners.clear(); } diff --git a/telephony/java/android/telephony/IccOpenLogicalChannelResponse.aidl b/telephony/java/android/telephony/IccOpenLogicalChannelResponse.aidl new file mode 100644 index 0000000..fe28c97 --- /dev/null +++ b/telephony/java/android/telephony/IccOpenLogicalChannelResponse.aidl @@ -0,0 +1,20 @@ +/* +** +** Copyright 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.telephony; + +parcelable IccOpenLogicalChannelResponse; diff --git a/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java b/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java new file mode 100644 index 0000000..bb5e277 --- /dev/null +++ b/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java @@ -0,0 +1,121 @@ +/* + * 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.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + + +/** + * Response to the {@link TelephonyManager#iccOpenLogicalChannel} command. + */ +public class IccOpenLogicalChannelResponse implements Parcelable { + // Indicates an invalid channel. + public static int INVALID_CHANNEL = -1; + + // Possible status values. + public static int NO_ERROR = 1; + public static int MISSING_RESOURCE = 2; + public static int NO_SUCH_ELEMENT = 3; + public static int UNKNOWN_ERROR = 4; + + private final int mChannel; + private final int mStatus; + private final byte[] mSelectResponse; + + /** + * Constructor. + * + * @hide + */ + public IccOpenLogicalChannelResponse(int channel, int status, byte[] selectResponse) { + mChannel = channel; + mStatus = status; + mSelectResponse = selectResponse; + } + + /** + * Construct a IccOpenLogicalChannelResponse from a given parcel. + */ + private IccOpenLogicalChannelResponse(Parcel in) { + mChannel = in.readInt(); + mStatus = in.readInt(); + int arrayLength = in.readInt(); + if (arrayLength > 0) { + mSelectResponse = new byte[arrayLength]; + in.readByteArray(mSelectResponse); + } else { + mSelectResponse = null; + } + } + + /** + * @return the channel id. + */ + public int getChannel() { + return mChannel; + } + + /** + * @return the status of the command. + */ + public int getStatus() { + return mStatus; + } + + /** + * @return the select response. + */ + public byte[] getSelectResponse() { + return mSelectResponse; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mChannel); + out.writeInt(mStatus); + if (mSelectResponse != null & mSelectResponse.length > 0) { + out.writeInt(mSelectResponse.length); + out.writeByteArray(mSelectResponse); + } else { + out.writeInt(0); + } + } + + public static final Parcelable.Creator<IccOpenLogicalChannelResponse> CREATOR + = new Parcelable.Creator<IccOpenLogicalChannelResponse>() { + + @Override + public IccOpenLogicalChannelResponse createFromParcel(Parcel in) { + return new IccOpenLogicalChannelResponse(in); + } + + public IccOpenLogicalChannelResponse[] newArray(int size) { + return new IccOpenLogicalChannelResponse[size]; + } + }; + + @Override + public String toString() { + return "Channel: " + mChannel + " Status: " + mStatus; + } +} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 35568cf..0772687 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.util.Log; +import android.util.Pair; import com.android.internal.telecomm.ITelecommService; import com.android.internal.telephony.IPhoneSubInfo; @@ -2348,15 +2349,15 @@ public class TelephonyManager { * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param AID Application id. See ETSI 102.221 and 101.220. - * @return The logical channel id which is negative on error. + * @return an IccOpenLogicalChannelResponse object. */ - public int iccOpenLogicalChannel(String AID) { + public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) { try { return getITelephony().iccOpenLogicalChannel(AID); } catch (RemoteException ex) { } catch (NullPointerException ex) { } - return -1; + return null; } /** @@ -2414,6 +2415,62 @@ public class TelephonyManager { } /** + * Transmit an APDU to the ICC card over the basic channel. + * + * Input parameters equivalent to TS 27.007 AT+CSIM command. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. If an error occurs, an empty string is returned. + */ + public String iccTransmitApduBasicChannel(int cla, + int instruction, int p1, int p2, int p3, String data) { + try { + return getITelephony().iccTransmitApduBasicChannel(cla, + instruction, p1, p2, p3, data); + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return ""; + } + + /** + * Returns the response APDU for a command APDU sent through SIM_IO. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + * @param fileID + * @param command + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. + * @param filePath + * @return The APDU response. + */ + byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, + String filePath) { + try { + return getITelephony().iccExchangeSimIO(fileID, command, p1, p2, + p3, filePath); + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** * Send ENVELOPE to the SIM and return the response. * * <p>Requires Permission: diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 886de40..72b04cf 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -18,9 +18,10 @@ package com.android.internal.telephony; import android.content.Intent; import android.os.Bundle; -import java.util.List; -import android.telephony.NeighboringCellInfo; import android.telephony.CellInfo; +import android.telephony.IccOpenLogicalChannelResponse; +import android.telephony.NeighboringCellInfo; +import java.util.List; /** @@ -499,9 +500,9 @@ interface ITelephony { * Input parameters equivalent to TS 27.007 AT+CCHO command. * * @param AID Application id. See ETSI 102.221 and 101.220. - * @return The logical channel id which is set to -1 on error. + * @return an IccOpenLogicalChannelResponse object. */ - int iccOpenLogicalChannel(String AID); + IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID); /** * Closes a previously opened logical channel to the ICC card. @@ -535,6 +536,38 @@ interface ITelephony { int p1, int p2, int p3, String data); /** + * Transmit an APDU to the ICC card over the basic channel. + * + * Input parameters equivalent to TS 27.007 AT+CSIM command. + * + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @return The APDU response from the ICC card with the status appended at + * the end. If an error occurs, an empty string is returned. + */ + String iccTransmitApduBasicChannel(int cla, int instruction, + int p1, int p2, int p3, String data); + + /** + * Returns the response APDU for a command APDU sent through SIM_IO. + * + * @param fileID + * @param command + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. + * @param filePath + * @return The APDU response. + */ + byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, + String filePath); + + /** * Send ENVELOPE to the SIM and returns the response. * * @param contents String containing SAT/USAT response in hexadecimal diff --git a/tests/SharedLibrary/lib/AndroidManifest.xml b/tests/SharedLibrary/lib/AndroidManifest.xml index 31fac20..bb939dd 100644 --- a/tests/SharedLibrary/lib/AndroidManifest.xml +++ b/tests/SharedLibrary/lib/AndroidManifest.xml @@ -19,7 +19,8 @@ android:versionCode="2"> <application android:label="SharedLibrary"> <library android:name="com.google.android.test.shared_library" /> - <activity android:name="ActivityMain"> + <activity android:name="ActivityMain" + android:icon="@drawable/size_48x48"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/tests/SharedLibrary/lib/res/drawable/size_48x48.jpg b/tests/SharedLibrary/lib/res/drawable/size_48x48.jpg Binary files differnew file mode 100644 index 0000000..5c2291e --- /dev/null +++ b/tests/SharedLibrary/lib/res/drawable/size_48x48.jpg diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index afeb546..755a77a 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -714,7 +714,6 @@ extern char CONSOLE_DATA[2925]; // see EOF int doDump(Bundle* bundle) { status_t result = UNKNOWN_ERROR; - Asset* asset = NULL; if (bundle->getFileSpecCount() < 1) { fprintf(stderr, "ERROR: no dump option specified\n"); @@ -758,12 +757,21 @@ int doDump(Bundle* bundle) const ResTable& res = assets.getResources(false); if (&res == NULL) { fprintf(stderr, "ERROR: dump failed because no resource table was found\n"); - goto bail; + return 1; } else if (res.getError() != NO_ERROR) { fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n"); - goto bail; + return 1; + } + + const DynamicRefTable* dynamicRefTable = res.getDynamicRefTableForCookie(assetsCookie); + if (dynamicRefTable == NULL) { + fprintf(stderr, "ERROR: failed to find dynamic reference table for asset cookie %d\n", + assetsCookie); + return 1; } + Asset* asset = NULL; + if (strcmp("resources", option) == 0) { #ifndef HAVE_ANDROID_OS res.print(bundle->getValues()); @@ -781,8 +789,8 @@ int doDump(Bundle* bundle) for (int i=2; i<bundle->getFileSpecCount(); i++) { const char* resname = bundle->getFileSpecEntry(i); - ResXMLTree tree; - asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); + ResXMLTree tree(dynamicRefTable); + asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); goto bail; @@ -808,13 +816,13 @@ int doDump(Bundle* bundle) for (int i=2; i<bundle->getFileSpecCount(); i++) { const char* resname = bundle->getFileSpecEntry(i); - ResXMLTree tree; - asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER); + asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); goto bail; } + ResXMLTree tree(dynamicRefTable); if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: Resource %s is corrupt\n", resname); @@ -826,14 +834,13 @@ int doDump(Bundle* bundle) } } else { - ResXMLTree tree; - asset = assets.openNonAsset("AndroidManifest.xml", - Asset::ACCESS_BUFFER); + asset = assets.openNonAsset(assetsCookie, "AndroidManifest.xml", Asset::ACCESS_BUFFER); if (asset == NULL) { fprintf(stderr, "ERROR: dump failed because no AndroidManifest.xml found\n"); goto bail; } + ResXMLTree tree(dynamicRefTable); if (tree.setTo(asset->getBuffer(true), asset->getLength()) != NO_ERROR) { fprintf(stderr, "ERROR: AndroidManifest.xml is corrupt\n"); diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 2ffe4a2..09b57fe 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -360,7 +360,7 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void updateScreenCaptureDisabled(int userId) { + public void setScreenCaptureDisabled(int userId, boolean disabled) { // TODO Auto-generated method stub } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java index 0b5fb46..94d5975 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java @@ -78,7 +78,7 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { assert isNeeded(owner, name, desc) && output.length == 3 && opcodeOut.length == 1; opcodeOut[0] = Opcodes.INVOKESTATIC; - output[0] = "com.android.layoutlib.bridge.android.AndroidLocale"; + output[0] = "com/android/layoutlib/bridge/android/AndroidLocale"; output[1] = name; output[2] = "(Ljava/util/Locale;)Ljava/lang/String;"; } diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 67ff868..f0a7f38 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -185,6 +185,14 @@ public class ScanResult implements Parcelable { public static class InformationElement { public int id; public byte[] bytes; + + public InformationElement() { + } + + public InformationElement(InformationElement rhs) { + this.id = rhs.id; + this.bytes = rhs.bytes.clone(); + } } /** information elements found in the beacon diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 4cdbc44..c5c44b5 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -145,6 +145,8 @@ public class WifiScanner { public int periodInMs; /** must have a valid REPORT_EVENT value */ public int reportEvents; + /** defines number of bssids to cache from each scan */ + public int numBssidsPerScan; /** Implement the Parcelable interface {@hide} */ public int describeContents() { @@ -267,13 +269,6 @@ public class WifiScanner { public void onFullResult(ScanResult fullScanResult); } - /** @hide */ - public void scan(ScanSettings settings, ScanListener listener) { - validateChannel(); - settings.periodInMs = 0; - sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings); - } - /** start wifi scan in background * @param settings specifies various parameters for the scan; for more information look at * {@link ScanSettings} @@ -305,7 +300,7 @@ public class WifiScanner { } /** specifies information about an access point of interest */ - public static class HotspotInfo { + public static class BssidInfo { /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */ public String bssid; /** low signal strength threshold; more information at {@link ScanResult#level} */ @@ -324,7 +319,7 @@ public class WifiScanner { public int unchangedSampleSize; /* samples to confirm no change */ public int minApsBreachingThreshold; /* change threshold to trigger event */ public int periodInMs; /* scan period in millisecond */ - public HotspotInfo[] hotspotInfos; + public BssidInfo[] bssidInfos; /** Implement the Parcelable interface {@hide} */ public int describeContents() { @@ -338,10 +333,10 @@ public class WifiScanner { dest.writeInt(unchangedSampleSize); dest.writeInt(minApsBreachingThreshold); dest.writeInt(periodInMs); - if (hotspotInfos != null) { - dest.writeInt(hotspotInfos.length); - for (int i = 0; i < hotspotInfos.length; i++) { - HotspotInfo info = hotspotInfos[i]; + if (bssidInfos != null) { + dest.writeInt(bssidInfos.length); + for (int i = 0; i < bssidInfos.length; i++) { + BssidInfo info = bssidInfos[i]; dest.writeString(info.bssid); dest.writeInt(info.low); dest.writeInt(info.high); @@ -363,14 +358,14 @@ public class WifiScanner { settings.minApsBreachingThreshold = in.readInt(); settings.periodInMs = in.readInt(); int len = in.readInt(); - settings.hotspotInfos = new HotspotInfo[len]; + settings.bssidInfos = new BssidInfo[len]; for (int i = 0; i < len; i++) { - HotspotInfo info = new HotspotInfo(); + BssidInfo info = new BssidInfo(); info.bssid = in.readString(); info.low = in.readInt(); info.high = in.readInt(); info.frequencyHint = in.readInt(); - settings.hotspotInfos[i] = info; + settings.bssidInfos[i] = info; } return settings; } @@ -389,7 +384,7 @@ public class WifiScanner { * @param minApsBreachingThreshold minimum number of access points that need to be * out of range to detect WifiChange * @param periodInMs indicates period of scan to find changes - * @param hotspotInfos access points to watch + * @param bssidInfos access points to watch */ public void configureWifiChange( int rssiSampleSize, /* sample size for RSSI averaging */ @@ -397,7 +392,7 @@ public class WifiScanner { int unchangedSampleSize, /* samples to confirm no change */ int minApsBreachingThreshold, /* change threshold to trigger event */ int periodInMs, /* period of scan */ - HotspotInfo[] hotspotInfos /* signal thresholds to crosss */ + BssidInfo[] bssidInfos /* signal thresholds to crosss */ ) { validateChannel(); @@ -408,7 +403,7 @@ public class WifiScanner { settings.unchangedSampleSize = unchangedSampleSize; settings.minApsBreachingThreshold = minApsBreachingThreshold; settings.periodInMs = periodInMs; - settings.hotspotInfos = hotspotInfos; + settings.bssidInfos = bssidInfos; configureWifiChange(settings); } @@ -455,7 +450,7 @@ public class WifiScanner { } /** interface to receive hotlist events on; use this on {@link #setHotlist} */ - public static interface HotspotListener extends ActionListener { + public static interface BssidListener extends ActionListener { /** indicates that access points were found by on going scans * @param results list of scan results, one for each access point visible currently */ @@ -465,7 +460,7 @@ public class WifiScanner { /** @hide */ @SystemApi public static class HotlistSettings implements Parcelable { - public HotspotInfo[] hotspotInfos; + public BssidInfo[] bssidInfos; public int apLostThreshold; /** Implement the Parcelable interface {@hide} */ @@ -477,10 +472,10 @@ public class WifiScanner { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(apLostThreshold); - if (hotspotInfos != null) { - dest.writeInt(hotspotInfos.length); - for (int i = 0; i < hotspotInfos.length; i++) { - HotspotInfo info = hotspotInfos[i]; + if (bssidInfos != null) { + dest.writeInt(bssidInfos.length); + for (int i = 0; i < bssidInfos.length; i++) { + BssidInfo info = bssidInfos[i]; dest.writeString(info.bssid); dest.writeInt(info.low); dest.writeInt(info.high); @@ -498,14 +493,14 @@ public class WifiScanner { HotlistSettings settings = new HotlistSettings(); settings.apLostThreshold = in.readInt(); int n = in.readInt(); - settings.hotspotInfos = new HotspotInfo[n]; + settings.bssidInfos = new BssidInfo[n]; for (int i = 0; i < n; i++) { - HotspotInfo info = new HotspotInfo(); + BssidInfo info = new BssidInfo(); info.bssid = in.readString(); info.low = in.readInt(); info.high = in.readInt(); info.frequencyHint = in.readInt(); - settings.hotspotInfos[i] = info; + settings.bssidInfos[i] = info; } return settings; } @@ -518,24 +513,24 @@ public class WifiScanner { /** * set interesting access points to find - * @param hotspots access points of interest + * @param bssidInfos access points of interest * @param apLostThreshold number of scans needed to indicate that AP is lost * @param listener object provided to report events on; this object must be unique and must - * also be provided on {@link #stopTrackingHotspots} + * also be provided on {@link #stopTrackingBssids} */ - public void startTrackingHotspots(HotspotInfo[] hotspots, - int apLostThreshold, HotspotListener listener) { + public void startTrackingBssids(BssidInfo[] bssidInfos, + int apLostThreshold, BssidListener listener) { validateChannel(); HotlistSettings settings = new HotlistSettings(); - settings.hotspotInfos = hotspots; + settings.bssidInfos = bssidInfos; sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings); } /** * remove tracking of interesting access points - * @param listener same object provided in {@link #startTrackingHotspots} + * @param listener same object provided in {@link #startTrackingBssids} */ - public void stopTrackingHotspots(HotspotListener listener) { + public void stopTrackingBssids(BssidListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener)); } @@ -802,7 +797,7 @@ public class WifiScanner { ((ScanListener) listener).onPeriodChanged(msg.arg1); return; case CMD_AP_FOUND: - ((HotspotListener) listener).onFound( + ((BssidListener) listener).onFound( ((ParcelableScanResults) msg.obj).getResults()); return; case CMD_WIFI_CHANGE_DETECTED: |