diff options
76 files changed, 2568 insertions, 342 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3258585ad583..ce2d80691270 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -71,6 +71,7 @@ import android.os.Trace; import android.os.UserHandle; import android.transition.Scene; import android.transition.TransitionManager; +import android.provider.Settings; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.DisplayMetrics; @@ -110,6 +111,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.net.InetAddress; import java.security.Security; +import java.text.DateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -1103,6 +1105,11 @@ public final class ActivityThread { public void scheduleInstallProvider(ProviderInfo provider) { sendMessage(H.INSTALL_PROVIDER, provider); } + + @Override + public final void updateTimePrefs(boolean is24Hour) { + DateFormat.set24HourTimePref(is24Hour); + } } private class H extends Handler { @@ -1152,6 +1159,7 @@ public final class ActivityThread { public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143; public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144; public static final int INSTALL_PROVIDER = 145; + String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { @@ -4215,6 +4223,11 @@ public final class ActivityThread { Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory"); } } + + + final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24)); + DateFormat.set24HourTimePref(is24Hr); + /** * For system applications on userdebug/eng builds, log stack * traces of disk and network access to dropbox for analysis. diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 20198f9c2034..f1c632e4e727 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -630,6 +630,15 @@ public abstract class ApplicationThreadNative extends Binder reply.writeNoException(); return true; } + + case UPDATE_TIME_PREFS_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + byte is24Hour = data.readByte(); + updateTimePrefs(is24Hour == (byte) 1); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1273,4 +1282,13 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(SCHEDULE_INSTALL_PROVIDER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } + + @Override + public void updateTimePrefs(boolean is24Hour) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeByte(is24Hour ? (byte) 1 : (byte) 0); + mRemote.transact(UPDATE_TIME_PREFS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + data.recycle(); + } } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 1ea9d877bca7..ac8ac8fe827f 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -139,6 +139,7 @@ public interface IApplicationThread extends IInterface { throws RemoteException; void setProcessState(int state) throws RemoteException; void scheduleInstallProvider(ProviderInfo provider) throws RemoteException; + void updateTimePrefs(boolean is24Hour) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -192,4 +193,5 @@ public interface IApplicationThread extends IInterface { int SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+48; int SET_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49; int SCHEDULE_INSTALL_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+50; + int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index cd1fbf6fff61..12a8ff6b9859 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -612,6 +612,13 @@ public class Notification implements Parcelable public static final String EXTRA_AS_HEADS_UP = "headsup"; /** + * Extra added from {@link Notification.Builder} to indicate that the remote views were inflated + * from the builder, as opposed to being created directly from the application. + * @hide + */ + public static final String EXTRA_BUILDER_REMOTE_VIEWS = "android.builderRemoteViews"; + + /** * Value for {@link #EXTRA_AS_HEADS_UP}. * @hide */ @@ -1273,6 +1280,7 @@ public class Notification implements Parcelable private boolean mShowWhen = true; private int mVisibility = VISIBILITY_PRIVATE; private Notification mPublicVersion = null; + private boolean mQuantumTheme; /** * Constructs a new Builder with the defaults: @@ -1300,6 +1308,9 @@ public class Notification implements Parcelable mWhen = System.currentTimeMillis(); mAudioStreamType = STREAM_DEFAULT; mPriority = PRIORITY_DEFAULT; + + // TODO: Decide on targetSdk from calling app whether to use quantum theme. + mQuantumTheme = true; } /** @@ -1807,7 +1818,7 @@ public class Notification implements Parcelable contentView.setImageViewBitmap(R.id.icon, mLargeIcon); smallIconImageViewId = R.id.right_icon; } - if (mPriority < PRIORITY_LOW) { + if (!mQuantumTheme && mPriority < PRIORITY_LOW) { contentView.setInt(R.id.icon, "setBackgroundResource", R.drawable.notification_template_icon_low_bg); contentView.setInt(R.id.status_bar_latest_event_content, @@ -1921,7 +1932,7 @@ public class Notification implements Parcelable if (mContentView != null) { return mContentView; } else { - return applyStandardTemplate(R.layout.notification_template_base, true); // no more special large_icon flavor + return applyStandardTemplate(getBaseLayoutResource(), true); // no more special large_icon flavor } } @@ -1942,21 +1953,21 @@ public class Notification implements Parcelable private RemoteViews makeBigContentView() { if (mActions.size() == 0) return null; - return applyStandardTemplateWithActions(R.layout.notification_template_big_base); + return applyStandardTemplateWithActions(getBigBaseLayoutResource()); } - private RemoteViews makeHEadsUpContentView() { + private RemoteViews makeHeadsUpContentView() { if (mActions.size() == 0) return null; - return applyStandardTemplateWithActions(R.layout.notification_template_big_base); + return applyStandardTemplateWithActions(getBigBaseLayoutResource()); } private RemoteViews generateActionButton(Action action) { final boolean tombstone = (action.actionIntent == null); RemoteViews button = new RemoteViews(mContext.getPackageName(), - tombstone ? R.layout.notification_action_tombstone - : R.layout.notification_action); + tombstone ? getActionTombstoneLayoutResource() + : getActionLayoutResource()); button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0); button.setTextViewText(R.id.action0, action.title); if (!tombstone) { @@ -1992,7 +2003,7 @@ public class Notification implements Parcelable n.defaults = mDefaults; n.flags = mFlags; n.bigContentView = makeBigContentView(); - n.headsUpContentView = makeHEadsUpContentView(); + n.headsUpContentView = makeHeadsUpContentView(); if (mLedOnMs != 0 || mLedOffMs != 0) { n.flags |= FLAG_SHOW_LIGHTS; } @@ -2037,6 +2048,7 @@ public class Notification implements Parcelable extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate); extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer); extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen); + extras.putBoolean(EXTRA_BUILDER_REMOTE_VIEWS, mContentView == null); if (mLargeIcon != null) { extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon); } @@ -2080,6 +2092,49 @@ public class Notification implements Parcelable build().cloneInto(n, true); return n; } + + + private int getBaseLayoutResource() { + return mQuantumTheme + ? R.layout.notification_template_quantum_base + : R.layout.notification_template_base; + } + + private int getBigBaseLayoutResource() { + return mQuantumTheme + ? R.layout.notification_template_quantum_big_base + : R.layout.notification_template_big_base; + } + + private int getBigPictureLayoutResource() { + return mQuantumTheme + ? R.layout.notification_template_quantum_big_picture + : R.layout.notification_template_big_picture; + } + + private int getBigTextLayoutResource() { + return mQuantumTheme + ? R.layout.notification_template_quantum_big_text + : R.layout.notification_template_big_text; + } + + private int getInboxLayoutResource() { + return mQuantumTheme + ? R.layout.notification_template_quantum_inbox + : R.layout.notification_template_inbox; + } + + private int getActionLayoutResource() { + return mQuantumTheme + ? R.layout.notification_quantum_action + : R.layout.notification_action; + } + + private int getActionTombstoneLayoutResource() { + return mQuantumTheme + ? R.layout.notification_quantum_action_tombstone + : R.layout.notification_action_tombstone; + } } /** @@ -2249,7 +2304,7 @@ public class Notification implements Parcelable } private RemoteViews makeBigContentView() { - RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture); + RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource()); contentView.setImageViewBitmap(R.id.big_picture, mPicture); @@ -2348,7 +2403,7 @@ public class Notification implements Parcelable final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null); mBuilder.mContentText = null; - RemoteViews contentView = getStandardView(R.layout.notification_template_big_text); + RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource()); if (hadThreeLines) { // vertical centering @@ -2442,7 +2497,7 @@ public class Notification implements Parcelable private RemoteViews makeBigContentView() { // Remove the content text so line3 disappears unless you have a summary mBuilder.mContentText = null; - RemoteViews contentView = getStandardView(R.layout.notification_template_inbox); + RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource()); contentView.setViewVisibility(R.id.text2, View.GONE); diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index b8b8f5fa92c3..333f825fe474 100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java @@ -79,6 +79,13 @@ public final class BluetoothInputDevice implements BluetoothProfile { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_HANDSHAKE = + "android.bluetooth.input.profile.action.HANDSHAKE"; + + /** + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_REPORT = "android.bluetooth.input.profile.action.REPORT"; @@ -185,6 +192,11 @@ public final class BluetoothInputDevice implements BluetoothProfile { /** * @hide */ + public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS"; + + /** + * @hide + */ public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS"; private Context mContext; @@ -608,7 +620,7 @@ public final class BluetoothInputDevice implements BluetoothProfile { * @hide */ public boolean setReport(BluetoothDevice device, byte reportType, String report) { - if (DBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report); + if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report); if (mService != null && isEnabled() && isValidDevice(device)) { try { return mService.setReport(device, reportType, report); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 3fdb6e722132..f0b7ca80ea18 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3334,6 +3334,15 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; + /** + * Optional boolean extra for {@link #ACTION_TIME_CHANGED} that indicates the + * user has set their time format preferences to the 24 hour format. + * + * @hide for internal use only. + */ + public static final String EXTRA_TIME_PREF_24_HOUR_FORMAT = + "android.intent.extra.TIME_PREF_24_HOUR_FORMAT"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 2893522d17c5..419abf212379 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -315,6 +315,24 @@ public class ColorStateList implements Parcelable { return mDefaultColor; } + /** + * Return the states in this {@link ColorStateList}. + * @return the states in this {@link ColorStateList} + * @hide + */ + public int[][] getStates() { + return mStateSpecs; + } + + /** + * Return the colors in this {@link ColorStateList}. + * @return the colors in this {@link ColorStateList} + * @hide + */ + public int[] getColors() { + return mColors; + } + @Override public String toString() { return "ColorStateList{" + diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index da6ae56d0c60..5c2707206fb5 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1625,7 +1625,7 @@ public class Resources { String locale = null; if (mConfiguration.locale != null) { - locale = localeToLanguageTag(mConfiguration.locale); + locale = adjustLanguageTag(localeToLanguageTag(mConfiguration.locale)); } int width, height; if (mMetrics.widthPixels >= mMetrics.heightPixels) { @@ -1713,6 +1713,41 @@ public class Resources { } /** + * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated) + * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively. + * + * All released versions of android prior to "L" used the deprecated language + * tags, so we will need to support them for backwards compatibility. + * + * Note that this conversion needs to take place *after* the call to + * {@code toLanguageTag} because that will convert all the deprecated codes to + * the new ones, even if they're set manually. + */ + private static String adjustLanguageTag(String languageTag) { + final int separator = languageTag.indexOf('-'); + final String language; + final String remainder; + + if (separator == -1) { + language = languageTag; + remainder = ""; + } else { + language = languageTag.substring(0, separator); + remainder = languageTag.substring(separator); + } + + if ("id".equals(language)) { + return "in" + remainder; + } else if ("yi".equals(language)) { + return "ji" + remainder; + } else if ("he".equals(language)) { + return "iw" + remainder; + } else { + return languageTag; + } + } + + /** * Update the system resources configuration if they have previously * been initialized. * diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 9f1e72dfe7f5..c88b4c03c6e8 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -28,6 +28,7 @@ import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.ViewOverlay; +import android.view.WindowId; import android.widget.ListView; import android.widget.Spinner; @@ -496,7 +497,8 @@ public abstract class Transition implements Cloneable { view = (start != null) ? start.view : null; } if (animator != null) { - AnimationInfo info = new AnimationInfo(view, getName(), infoValues); + AnimationInfo info = new AnimationInfo(view, getName(), + sceneRoot.getWindowId(), infoValues); runningAnimators.put(animator, info); mAnimators.add(animator); } @@ -1199,13 +1201,17 @@ public abstract class Transition implements Cloneable { * * @hide */ - public void pause() { + public void pause(View sceneRoot) { if (!mEnded) { ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators(); int numOldAnims = runningAnimators.size(); + WindowId windowId = sceneRoot.getWindowId(); for (int i = numOldAnims - 1; i >= 0; i--) { - Animator anim = runningAnimators.keyAt(i); - anim.pause(); + AnimationInfo info = runningAnimators.valueAt(i); + if (info.view != null && windowId.equals(info.windowId)) { + Animator anim = runningAnimators.keyAt(i); + anim.pause(); + } } if (mListeners != null && mListeners.size() > 0) { ArrayList<TransitionListener> tmpListeners = @@ -1226,14 +1232,18 @@ public abstract class Transition implements Cloneable { * * @hide */ - public void resume() { + public void resume(View sceneRoot) { if (mPaused) { if (!mEnded) { ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators(); int numOldAnims = runningAnimators.size(); + WindowId windowId = sceneRoot.getWindowId(); for (int i = numOldAnims - 1; i >= 0; i--) { - Animator anim = runningAnimators.keyAt(i); - anim.resume(); + AnimationInfo info = runningAnimators.valueAt(i); + if (info.view != null && windowId.equals(info.windowId)) { + Animator anim = runningAnimators.keyAt(i); + anim.resume(); + } } if (mListeners != null && mListeners.size() > 0) { ArrayList<TransitionListener> tmpListeners = @@ -1644,11 +1654,13 @@ public abstract class Transition implements Cloneable { public View view; String name; TransitionValues values; + WindowId windowId; - AnimationInfo(View view, String name, TransitionValues values) { + AnimationInfo(View view, String name, WindowId windowId, TransitionValues values) { this.view = view; this.name = name; this.values = values; + this.windowId = windowId; } } diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index f3abfb07a8f8..1614d34da09a 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -302,7 +302,7 @@ public class TransitionManager { ArrayList<Transition> runningTransitions = getRunningTransitions().get(mSceneRoot); if (runningTransitions != null && runningTransitions.size() > 0) { for (Transition runningTransition : runningTransitions) { - runningTransition.resume(); + runningTransition.resume(mSceneRoot); } } mTransition.clearValues(true); @@ -335,7 +335,7 @@ public class TransitionManager { mTransition.captureValues(mSceneRoot, false); if (previousRunningTransitions != null) { for (Transition runningTransition : previousRunningTransitions) { - runningTransition.resume(); + runningTransition.resume(mSceneRoot); } } mTransition.playTransition(mSceneRoot); @@ -351,7 +351,7 @@ public class TransitionManager { if (runningTransitions != null && runningTransitions.size() > 0) { for (Transition runningTransition : runningTransitions) { - runningTransition.pause(); + runningTransition.pause(sceneRoot); } } diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java index 4545e3b51fc9..19d6b3d3c393 100644 --- a/core/java/android/transition/TransitionSet.java +++ b/core/java/android/transition/TransitionSet.java @@ -317,21 +317,21 @@ public class TransitionSet extends Transition { /** @hide */ @Override - public void pause() { - super.pause(); + public void pause(View sceneRoot) { + super.pause(sceneRoot); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { - mTransitions.get(i).pause(); + mTransitions.get(i).pause(sceneRoot); } } /** @hide */ @Override - public void resume() { - super.resume(); + public void resume(View sceneRoot) { + super.resume(sceneRoot); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { - mTransitions.get(i).resume(); + mTransitions.get(i).resume(sceneRoot); } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 9b23b3527968..1f211c21f0b0 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -255,8 +255,9 @@ public class SurfaceView extends View { updateWindow(false, false); } + /** @hide */ @Override - protected void onDetachedFromWindow() { + protected void onDetachedFromWindowInternal() { if (mGlobalListenersAdded) { ViewTreeObserver observer = getViewTreeObserver(); observer.removeOnScrollChangedListener(mScrollChangedListener); @@ -278,7 +279,7 @@ public class SurfaceView extends View { mSession = null; mLayout.token = null; - super.onDetachedFromWindow(); + super.onDetachedFromWindowInternal(); } @Override diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index ef0d80d73cde..3cfe5e916937 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -228,10 +228,11 @@ public class TextureView extends View { } } + /** @hide */ @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + protected void onDetachedFromWindowInternal() { destroySurface(); + super.onDetachedFromWindowInternal(); } private void destroySurface() { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index afa63a2a2934..827c4ccd1f1f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13116,6 +13116,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #onAttachedToWindow() */ protected void onDetachedFromWindow() { + } + + /** + * This is a framework-internal mirror of onDetachedFromWindow() that's called + * after onDetachedFromWindow(). + * + * If you override this you *MUST* call super.onDetachedFromWindowInternal()! + * The super method should be called at the end of the overriden method to ensure + * subclasses are destroyed first + * + * @hide + */ + protected void onDetachedFromWindowInternal() { mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; @@ -13303,6 +13316,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } onDetachedFromWindow(); + onDetachedFromWindowInternal(); ListenerInfo li = mListenerInfo; final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 9f2bf3383985..f8160c88f974 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -37,6 +37,7 @@ import android.util.Printer; import android.util.Slog; import android.util.Xml; import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; +import android.view.inputmethod.InputMethodSubtypeArray; import java.io.IOException; import java.util.ArrayList; @@ -86,9 +87,9 @@ public final class InputMethodInfo implements Parcelable { final int mIsDefaultResId; /** - * The array of the subtypes. + * An array-like container of the subtypes. */ - private final ArrayList<InputMethodSubtype> mSubtypes = new ArrayList<InputMethodSubtype>(); + private final InputMethodSubtypeArray mSubtypes; private final boolean mIsAuxIme; @@ -138,6 +139,7 @@ public final class InputMethodInfo implements Parcelable { int isDefaultResId = 0; XmlResourceParser parser = null; + final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>(); try { parser = si.loadXmlMetaData(pm, InputMethod.SERVICE_META_DATA); if (parser == null) { @@ -206,7 +208,7 @@ public final class InputMethodInfo implements Parcelable { if (!subtype.isAuxiliary()) { isAuxIme = false; } - mSubtypes.add(subtype); + subtypes.add(subtype); } } } catch (NameNotFoundException e) { @@ -216,7 +218,7 @@ public final class InputMethodInfo implements Parcelable { if (parser != null) parser.close(); } - if (mSubtypes.size() == 0) { + if (subtypes.size() == 0) { isAuxIme = false; } @@ -225,14 +227,15 @@ public final class InputMethodInfo implements Parcelable { final int N = additionalSubtypes.size(); for (int i = 0; i < N; ++i) { final InputMethodSubtype subtype = additionalSubtypes.get(i); - if (!mSubtypes.contains(subtype)) { - mSubtypes.add(subtype); + if (!subtypes.contains(subtype)) { + subtypes.add(subtype); } else { Slog.w(TAG, "Duplicated subtype definition found: " + subtype.getLocale() + ", " + subtype.getMode()); } } } + mSubtypes = new InputMethodSubtypeArray(subtypes); mSettingsActivityName = settingsActivityComponent; mIsDefaultResId = isDefaultResId; mIsAuxIme = isAuxIme; @@ -246,7 +249,7 @@ public final class InputMethodInfo implements Parcelable { mIsAuxIme = source.readInt() == 1; mSupportsSwitchingToNextInputMethod = source.readInt() == 1; mService = ResolveInfo.CREATOR.createFromParcel(source); - source.readTypedList(mSubtypes, InputMethodSubtype.CREATOR); + mSubtypes = new InputMethodSubtypeArray(source); mForceDefault = false; } @@ -272,9 +275,7 @@ public final class InputMethodInfo implements Parcelable { mSettingsActivityName = settingsActivity; mIsDefaultResId = isDefaultResId; mIsAuxIme = isAuxIme; - if (subtypes != null) { - mSubtypes.addAll(subtypes); - } + mSubtypes = new InputMethodSubtypeArray(subtypes); mForceDefault = forceDefault; mSupportsSwitchingToNextInputMethod = true; } @@ -364,7 +365,7 @@ public final class InputMethodInfo implements Parcelable { * composed of {@link #getPackageName} and the class name returned here. * * <p>A null will be returned if there is no settings activity associated - * with the input method. + * with the input method.</p> */ public String getSettingsActivity() { return mSettingsActivityName; @@ -374,7 +375,7 @@ public final class InputMethodInfo implements Parcelable { * Return the count of the subtypes of Input Method. */ public int getSubtypeCount() { - return mSubtypes.size(); + return mSubtypes.getCount(); } /** @@ -479,7 +480,7 @@ public final class InputMethodInfo implements Parcelable { dest.writeInt(mIsAuxIme ? 1 : 0); dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0); mService.writeToParcel(dest, flags); - dest.writeTypedList(mSubtypes); + mSubtypes.writeToParcel(dest); } /** diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java new file mode 100644 index 000000000000..5bef71fcd73b --- /dev/null +++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2007-2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.view.inputmethod; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AndroidRuntimeException; +import android.util.Slog; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * An array-like container that stores multiple instances of {@link InputMethodSubtype}. + * + * <p>This container is designed to reduce the risk of {@link TransactionTooLargeException} + * when one or more instancess of {@link InputMethodInfo} are transferred through IPC. + * Basically this class does following three tasks.</p> + * <ul> + * <li>Applying compression for the marshalled data</li> + * <li>Lazily unmarshalling objects</li> + * <li>Caching the marshalled data when appropriate</li> + * </ul> + * + * @hide + */ +public class InputMethodSubtypeArray { + private final static String TAG = "InputMethodSubtypeArray"; + + /** + * Create a new instance of {@link InputMethodSubtypeArray} from an existing list of + * {@link InputMethodSubtype}. + * + * @param subtypes A list of {@link InputMethodSubtype} from which + * {@link InputMethodSubtypeArray} will be created. + */ + public InputMethodSubtypeArray(final List<InputMethodSubtype> subtypes) { + if (subtypes == null) { + mCount = 0; + return; + } + mCount = subtypes.size(); + mInstance = subtypes.toArray(new InputMethodSubtype[mCount]); + } + + /** + * Unmarshall an instance of {@link InputMethodSubtypeArray} from a given {@link Parcel} + * object. + * + * @param source A {@link Parcel} object from which {@link InputMethodSubtypeArray} will be + * unmarshalled. + */ + public InputMethodSubtypeArray(final Parcel source) { + mCount = source.readInt(); + if (mCount > 0) { + mDecompressedSize = source.readInt(); + mCompressedData = source.createByteArray(); + } + } + + /** + * Marshall the instance into a given {@link Parcel} object. + * + * <p>This methods may take a bit additional time to compress data lazily when called + * first time.</p> + * + * @param source A {@link Parcel} object to which {@link InputMethodSubtypeArray} will be + * marshalled. + */ + public void writeToParcel(final Parcel dest) { + if (mCount == 0) { + dest.writeInt(mCount); + return; + } + + byte[] compressedData = mCompressedData; + int decompressedSize = mDecompressedSize; + if (compressedData == null && decompressedSize == 0) { + synchronized (mLockObject) { + compressedData = mCompressedData; + decompressedSize = mDecompressedSize; + if (compressedData == null && decompressedSize == 0) { + final byte[] decompressedData = marshall(mInstance); + compressedData = compress(decompressedData); + if (compressedData == null) { + decompressedSize = -1; + Slog.i(TAG, "Failed to compress data."); + } else { + decompressedSize = decompressedData.length; + } + mDecompressedSize = decompressedSize; + mCompressedData = compressedData; + } + } + } + + if (compressedData != null && decompressedSize > 0) { + dest.writeInt(mCount); + dest.writeInt(decompressedSize); + dest.writeByteArray(compressedData); + } else { + Slog.i(TAG, "Unexpected state. Behaving as an empty array."); + dest.writeInt(0); + } + } + + /** + * Return {@link InputMethodSubtype} specified with the given index. + * + * <p>This methods may take a bit additional time to decompress data lazily when called + * first time.</p> + * + * @param index The index of {@link InputMethodSubtype}. + */ + public InputMethodSubtype get(final int index) { + if (index < 0 || mCount <= index) { + throw new ArrayIndexOutOfBoundsException(); + } + InputMethodSubtype[] instance = mInstance; + if (instance == null) { + synchronized (mLockObject) { + instance = mInstance; + if (instance == null) { + final byte[] decompressedData = + decompress(mCompressedData, mDecompressedSize); + // Clear the compressed data until {@link #getMarshalled()} is called. + mCompressedData = null; + mDecompressedSize = 0; + if (decompressedData != null) { + instance = unmarshall(decompressedData); + } else { + Slog.e(TAG, "Failed to decompress data. Returns null as fallback."); + instance = new InputMethodSubtype[mCount]; + } + mInstance = instance; + } + } + } + return instance[index]; + } + + /** + * Return the number of {@link InputMethodSubtype} objects. + */ + public int getCount() { + return mCount; + } + + private final Object mLockObject = new Object(); + private final int mCount; + + private volatile InputMethodSubtype[] mInstance; + private volatile byte[] mCompressedData; + private volatile int mDecompressedSize; + + private static byte[] marshall(final InputMethodSubtype[] array) { + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + parcel.writeTypedArray(array, 0); + return parcel.marshall(); + } finally { + if (parcel != null) { + parcel.recycle(); + parcel = null; + } + } + } + + private static InputMethodSubtype[] unmarshall(final byte[] data) { + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + parcel.unmarshall(data, 0, data.length); + parcel.setDataPosition(0); + return parcel.createTypedArray(InputMethodSubtype.CREATOR); + } finally { + if (parcel != null) { + parcel.recycle(); + parcel = null; + } + } + } + + private static byte[] compress(final byte[] data) { + ByteArrayOutputStream resultStream = null; + GZIPOutputStream zipper = null; + try { + resultStream = new ByteArrayOutputStream(); + zipper = new GZIPOutputStream(resultStream); + zipper.write(data); + } catch(IOException e) { + return null; + } finally { + try { + if (zipper != null) { + zipper.close(); + } + } catch (IOException e) { + zipper = null; + Slog.e(TAG, "Failed to close the stream.", e); + // swallowed, not propagated back to the caller + } + try { + if (resultStream != null) { + resultStream.close(); + } + } catch (IOException e) { + resultStream = null; + Slog.e(TAG, "Failed to close the stream.", e); + // swallowed, not propagated back to the caller + } + } + return resultStream != null ? resultStream.toByteArray() : null; + } + + private static byte[] decompress(final byte[] data, final int expectedSize) { + ByteArrayInputStream inputStream = null; + GZIPInputStream unzipper = null; + try { + inputStream = new ByteArrayInputStream(data); + unzipper = new GZIPInputStream(inputStream); + final byte [] result = new byte[expectedSize]; + int totalReadBytes = 0; + while (totalReadBytes < result.length) { + final int restBytes = result.length - totalReadBytes; + final int readBytes = unzipper.read(result, totalReadBytes, restBytes); + if (readBytes < 0) { + break; + } + totalReadBytes += readBytes; + } + if (expectedSize != totalReadBytes) { + return null; + } + return result; + } catch(IOException e) { + return null; + } finally { + try { + if (unzipper != null) { + unzipper.close(); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to close the stream.", e); + // swallowed, not propagated back to the caller + } + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to close the stream.", e); + // swallowed, not propagated back to the caller + } + } + } +} diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 826bcecd51c9..81d36a4db1ff 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2139,10 +2139,11 @@ public class WebView extends AbsoluteLayout mProvider.getViewDelegate().onAttachedToWindow(); } + /** @hide */ @Override - protected void onDetachedFromWindow() { + protected void onDetachedFromWindowInternal() { mProvider.getViewDelegate().onDetachedFromWindow(); - super.onDetachedFromWindow(); + super.onDetachedFromWindowInternal(); } @Override diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index e5cb16fa65e3..687036ca14ef 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -4729,10 +4729,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mEditor != null) mEditor.onAttachedToWindow(); } + /** @hide */ @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - + protected void onDetachedFromWindowInternal() { if (mPreDrawRegistered) { getViewTreeObserver().removeOnPreDrawListener(this); mPreDrawRegistered = false; @@ -4741,6 +4740,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener resetResolvedDrawables(); if (mEditor != null) mEditor.onDetachedFromWindow(); + + super.onDetachedFromWindowInternal(); } @Override diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 325a27d70a3c..e51345cb619b 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -32,7 +32,9 @@ import com.android.internal.view.IInputMethodClient; * this file. */ interface IInputMethodManager { + // TODO: Use ParceledListSlice instead List<InputMethodInfo> getInputMethodList(); + // TODO: Use ParceledListSlice instead List<InputMethodInfo> getEnabledInputMethodList(); List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId, boolean allowsImplicitlySelectedSubtypes); diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java index 9fefd00c6d30..b479cb1fb6d3 100644 --- a/core/java/com/android/internal/view/RotationPolicy.java +++ b/core/java/com/android/internal/view/RotationPolicy.java @@ -58,7 +58,9 @@ public final class RotationPolicy { PackageManager pm = context.getPackageManager(); return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER) && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT) - && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE); + && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE) + && context.getResources().getBoolean( + com.android.internal.R.bool.config_supportAutoRotation); } /** @@ -184,6 +186,7 @@ public final class RotationPolicy { */ public static abstract class RotationPolicyListener { final ContentObserver mObserver = new ContentObserver(new Handler()) { + @Override public void onChange(boolean selfChange, Uri uri) { RotationPolicyListener.this.onChange(); } diff --git a/core/res/res/drawable/notification_quantum_background.xml b/core/res/res/drawable/notification_quantum_background.xml new file mode 100644 index 000000000000..f33e2e36621c --- /dev/null +++ b/core/res/res/drawable/notification_quantum_background.xml @@ -0,0 +1,21 @@ +<?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 + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#ffffffff" /> + <corners android:radius="2dp" /> +</shape>
\ No newline at end of file diff --git a/core/res/res/drawable/notification_quantum_bg.xml b/core/res/res/drawable/notification_quantum_bg.xml new file mode 100644 index 000000000000..608115e631e9 --- /dev/null +++ b/core/res/res/drawable/notification_quantum_bg.xml @@ -0,0 +1,21 @@ +<?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 + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/notification_quantum_press" /> + <item android:state_pressed="false" android:drawable="@drawable/notification_quantum_background" /> +</selector>
\ No newline at end of file diff --git a/core/res/res/drawable/notification_quantum_press.xml b/core/res/res/drawable/notification_quantum_press.xml new file mode 100644 index 000000000000..4999f55cc0f6 --- /dev/null +++ b/core/res/res/drawable/notification_quantum_press.xml @@ -0,0 +1,21 @@ +<?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 + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#ffcccccc" /> + <corners android:radius="2dp" /> +</shape>
\ No newline at end of file diff --git a/core/res/res/layout/notification_quantum_action.xml b/core/res/res/layout/notification_quantum_action.xml new file mode 100644 index 000000000000..775182f4a699 --- /dev/null +++ b/core/res/res/layout/notification_quantum_action.xml @@ -0,0 +1,31 @@ +<?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 + --> + +<Button xmlns:android="http://schemas.android.com/apk/res/android" + style="?android:attr/borderlessButtonStyle" + android:id="@+id/action0" + android:layout_width="0dp" + android:layout_height="48dp" + android:layout_weight="1" + android:gravity="start|center_vertical" + android:drawablePadding="8dp" + android:paddingStart="8dp" + android:textColor="#555555" + android:textSize="14dp" + android:singleLine="true" + android:ellipsize="end" + /> diff --git a/core/res/res/layout/notification_quantum_action_list.xml b/core/res/res/layout/notification_quantum_action_list.xml new file mode 100644 index 000000000000..a8aef97e48ab --- /dev/null +++ b/core/res/res/layout/notification_quantum_action_list.xml @@ -0,0 +1,30 @@ +<?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/actions" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:visibility="gone" + android:layout_marginBottom="8dp" + android:showDividers="middle" + android:divider="?android:attr/listDivider" + android:dividerPadding="12dp" + > + <!-- actions will be added here --> +</LinearLayout> diff --git a/core/res/res/layout/notification_quantum_action_tombstone.xml b/core/res/res/layout/notification_quantum_action_tombstone.xml new file mode 100644 index 000000000000..9104991585fb --- /dev/null +++ b/core/res/res/layout/notification_quantum_action_tombstone.xml @@ -0,0 +1,33 @@ +<?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 + --> + +<Button xmlns:android="http://schemas.android.com/apk/res/android" + style="?android:attr/borderlessButtonStyle" + android:id="@+id/action0" + android:layout_width="0dp" + android:layout_height="48dp" + android:layout_weight="1" + android:gravity="start|center_vertical" + android:drawablePadding="8dp" + android:paddingStart="8dp" + android:textColor="#555555" + android:textSize="14dp" + android:singleLine="true" + android:ellipsize="end" + android:alpha="0.5" + android:enabled="false" + /> diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_quantum_base.xml new file mode 100644 index 000000000000..3e97b2aecc0c --- /dev/null +++ b/core/res/res/layout/notification_template_quantum_base.xml @@ -0,0 +1,137 @@ +<?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 + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:background="@android:drawable/notification_quantum_bg" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="64dp" + internal:layout_minHeight="64dp" + internal:layout_maxHeight="64dp" + > + <ImageView android:id="@+id/icon" + android:layout_width="@dimen/notification_large_icon_width" + android:layout_height="@dimen/notification_large_icon_height" + android:scaleType="center" + /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + + android:layout_gravity="fill_vertical" + android:layout_marginStart="@dimen/notification_large_icon_width" + android:minHeight="@dimen/notification_large_icon_height" + android:orientation="vertical" + android:paddingEnd="8dp" + android:paddingTop="2dp" + android:paddingBottom="2dp" + android:gravity="top" + > + <LinearLayout + android:id="@+id/line1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="6dp" + android:layout_marginStart="8dp" + android:orientation="horizontal" + > + <TextView android:id="@+id/title" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:layout_weight="1" + /> + <ViewStub android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_time" + /> + <ViewStub android:id="@+id/chronometer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_chronometer" + /> + </LinearLayout> + <TextView android:id="@+id/text2" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="-2dp" + android:layout_marginBottom="-2dp" + android:layout_marginStart="8dp" + android:singleLine="true" + android:fadingEdge="horizontal" + android:ellipsize="marquee" + android:visibility="gone" + /> + <ProgressBar + android:id="@android:id/progress" + android:layout_width="match_parent" + android:layout_height="12dp" + android:layout_marginStart="8dp" + android:visibility="gone" + style="?android:attr/progressBarStyleHorizontal" + /> + <LinearLayout + android:id="@+id/line3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical" + android:layout_marginStart="8dp" + > + <TextView android:id="@+id/text" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="center" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + /> + <TextView android:id="@+id/info" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_weight="0" + android:singleLine="true" + android:gravity="center" + android:paddingStart="8dp" + /> + <ImageView android:id="@+id/right_icon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_gravity="center" + android:layout_weight="0" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:visibility="gone" + android:drawableAlpha="153" + /> + </LinearLayout> + </LinearLayout> +</FrameLayout> diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_quantum_big_base.xml new file mode 100644 index 000000000000..d86004580d0f --- /dev/null +++ b/core/res/res/layout/notification_template_quantum_big_base.xml @@ -0,0 +1,167 @@ +<?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 + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:background="@android:drawable/notification_quantum_bg" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded" + > + <ImageView android:id="@+id/icon" + android:layout_width="@dimen/notification_large_icon_width" + android:layout_height="@dimen/notification_large_icon_height" + android:scaleType="center" + /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_vertical" + android:minHeight="@dimen/notification_large_icon_height" + android:orientation="vertical" + android:gravity="top" + > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_large_icon_width" + android:minHeight="@dimen/notification_large_icon_height" + android:paddingTop="2dp" + android:orientation="vertical" + > + <LinearLayout + android:id="@+id/line1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="6dp" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:orientation="horizontal" + > + <TextView android:id="@+id/title" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:layout_weight="1" + /> + <ViewStub android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_time" + /> + <ViewStub android:id="@+id/chronometer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_chronometer" + /> + </LinearLayout> + <TextView android:id="@+id/text2" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="-2dp" + android:layout_marginBottom="-2dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:fadingEdge="horizontal" + android:ellipsize="marquee" + android:visibility="gone" + /> + <TextView android:id="@+id/big_text" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="false" + android:visibility="gone" + /> + <LinearLayout + android:id="@+id/line3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:orientation="horizontal" + android:gravity="center_vertical" + > + <TextView android:id="@+id/text" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="center" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + /> + <TextView android:id="@+id/info" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_weight="0" + android:singleLine="true" + android:gravity="center" + android:paddingStart="8dp" + /> + <ImageView android:id="@+id/right_icon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_gravity="center" + android:layout_weight="0" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:visibility="gone" + android:drawableAlpha="153" + /> + </LinearLayout> + <ProgressBar + android:id="@android:id/progress" + android:layout_width="match_parent" + android:layout_height="12dp" + android:layout_marginBottom="8dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:visibility="gone" + style="?android:attr/progressBarStyleHorizontal" + /> + </LinearLayout> + <ImageView + android:layout_width="match_parent" + android:layout_height="1dp" + android:id="@+id/action_divider" + android:visibility="gone" + android:background="?android:attr/dividerHorizontal" /> + <include + layout="@layout/notification_quantum_action_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_large_icon_width" + /> + </LinearLayout> +</FrameLayout> diff --git a/core/res/res/layout/notification_template_quantum_big_picture.xml b/core/res/res/layout/notification_template_quantum_big_picture.xml new file mode 100644 index 000000000000..e49c3bd9265f --- /dev/null +++ b/core/res/res/layout/notification_template_quantum_big_picture.xml @@ -0,0 +1,62 @@ +<?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 + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:background="@android:drawable/notification_quantum_bg" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="match_parent" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded" + > + <ImageView + android:id="@+id/big_picture" + android:layout_width="match_parent" + android:layout_height="192dp" + android:layout_marginTop="64dp" + android:layout_gravity="bottom" + android:scaleType="centerCrop" + /> + <ImageView + android:layout_width="match_parent" + android:layout_height="6dp" + android:layout_marginTop="64dp" + android:scaleType="fitXY" + android:src="@drawable/title_bar_shadow" + /> + <include layout="@layout/notification_template_quantum_base" + android:layout_width="match_parent" + android:layout_height="wrap_content" + /> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="208dp" + android:paddingStart="64dp" + android:layout_gravity="bottom" + android:background="#CCEEEEEE" + > + <include + layout="@layout/notification_quantum_action_list" + android:id="@+id/actions" + android:layout_gravity="bottom" + android:layout_width="match_parent" + android:layout_height="wrap_content" + /> + </FrameLayout> +</FrameLayout> diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_quantum_big_text.xml new file mode 100644 index 000000000000..585be8038bd0 --- /dev/null +++ b/core/res/res/layout/notification_template_quantum_big_text.xml @@ -0,0 +1,182 @@ +<?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 + --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:background="@android:drawable/notification_quantum_bg" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded" + > + <ImageView android:id="@+id/icon" + android:layout_width="@dimen/notification_large_icon_width" + android:layout_height="@dimen/notification_large_icon_height" + android:scaleType="center" + /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_vertical" + android:layout_marginStart="@dimen/notification_large_icon_width" + android:orientation="vertical" + android:paddingTop="0dp" + android:paddingBottom="2dp" + android:gravity="top" + > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_large_icon_height" + android:orientation="vertical" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:layout_weight="1" + > + <LinearLayout + android:id="@+id/line1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:orientation="horizontal" + android:layout_gravity="top" + android:layout_weight="0" + > + <TextView android:id="@+id/title" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:layout_weight="1" + /> + <ViewStub android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_time" + /> + <ViewStub android:id="@+id/chronometer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_chronometer" + /> + </LinearLayout> + <TextView android:id="@+id/text2" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="-2dp" + android:layout_marginBottom="-2dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:fadingEdge="horizontal" + android:ellipsize="marquee" + android:layout_weight="0" + android:visibility="gone" + /> + <ProgressBar + android:id="@android:id/progress" + android:layout_width="match_parent" + android:layout_height="12dp" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:visibility="gone" + android:layout_weight="0" + style="?android:attr/progressBarStyleHorizontal" + /> + <TextView android:id="@+id/big_text" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginBottom="10dp" + android:layout_marginEnd="8dp" + android:singleLine="false" + android:visibility="gone" + android:maxLines="8" + android:ellipsize="end" + android:layout_weight="1" + /> + </LinearLayout> + <ImageView + android:layout_width="match_parent" + android:layout_height="1dip" + android:id="@+id/action_divider" + android:visibility="gone" + android:background="?android:attr/dividerHorizontal" /> + <include + layout="@layout/notification_quantum_action_list" + android:layout_width="match_parent" + android:layout_height="0dp" + android:visibility="gone" + android:layout_weight="1" + /> + <ImageView + android:layout_width="match_parent" + android:layout_height="1dp" + android:id="@+id/overflow_divider" + android:layout_marginBottom="8dp" + android:visibility="visible" + android:background="?android:attr/dividerHorizontal" /> + <LinearLayout + android:id="@+id/line3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:orientation="horizontal" + android:layout_weight="0" + android:gravity="center_vertical" + > + <TextView android:id="@+id/text" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="center" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + /> + <TextView android:id="@+id/info" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_weight="0" + android:singleLine="true" + android:gravity="center" + android:paddingStart="8dp" + /> + <ImageView android:id="@+id/right_icon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_gravity="center" + android:layout_weight="0" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:visibility="gone" + android:drawableAlpha="153" + /> + </LinearLayout> + </LinearLayout> +</FrameLayout> diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_quantum_inbox.xml new file mode 100644 index 000000000000..31ed50878f3a --- /dev/null +++ b/core/res/res/layout/notification_template_quantum_inbox.xml @@ -0,0 +1,266 @@ +<?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 + --> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:internal="http://schemas.android.com/apk/prv/res/android" + android:id="@+id/status_bar_latest_event_content" + android:background="@android:drawable/notification_quantum_bg" + android:layout_width="match_parent" + android:layout_height="wrap_content" + internal:layout_minHeight="65dp" + internal:layout_maxHeight="unbounded" + > + <ImageView android:id="@+id/icon" + android:layout_width="@dimen/notification_large_icon_width" + android:layout_height="@dimen/notification_large_icon_height" + android:scaleType="center" + /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="fill_vertical" + android:layout_marginStart="@dimen/notification_large_icon_width" + android:minHeight="@dimen/notification_large_icon_height" + android:orientation="vertical" + android:paddingTop="0dp" + android:paddingBottom="2dp" + android:gravity="top" + > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_large_icon_height" + android:paddingTop="2dp" + android:orientation="vertical" + > + <LinearLayout + android:id="@+id/line1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:paddingTop="6dp" + android:orientation="horizontal" + android:layout_weight="0" + > + <TextView android:id="@+id/title" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:layout_weight="1" + /> + <ViewStub android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_time" + /> + <ViewStub android:id="@+id/chronometer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:visibility="gone" + android:layout="@layout/notification_template_part_chronometer" + /> + </LinearLayout> + <TextView android:id="@+id/text2" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="-2dp" + android:layout_marginBottom="-2dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:fadingEdge="horizontal" + android:ellipsize="marquee" + android:visibility="gone" + android:layout_weight="0" + /> + <ProgressBar + android:id="@android:id/progress" + android:layout_width="match_parent" + android:layout_height="12dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:visibility="gone" + android:layout_weight="0" + style="?android:attr/progressBarStyleHorizontal" + /> + <TextView android:id="@+id/inbox_text0" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_text1" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_text2" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_text3" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_text4" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_text5" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_text6" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + /> + <TextView android:id="@+id/inbox_more" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:singleLine="true" + android:ellipsize="end" + android:visibility="gone" + android:layout_weight="1" + android:text="@android:string/ellipsis" + /> + <FrameLayout + android:id="@+id/inbox_end_pad" + android:layout_width="match_parent" + android:layout_height="8dip" + android:visibility="gone" + android:layout_weight="0" + /> + </LinearLayout> + <ImageView + android:layout_width="match_parent" + android:layout_height="1dip" + android:id="@+id/action_divider" + android:visibility="gone" + android:background="?android:attr/dividerHorizontal" /> + <include + layout="@layout/notification_quantum_action_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="0" + /> + <ImageView + android:layout_width="match_parent" + android:layout_height="1dip" + android:id="@+id/overflow_divider" + android:visibility="visible" + android:background="?android:attr/dividerHorizontal" /> + <LinearLayout + android:id="@+id/line3" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_marginStart="8dp" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:orientation="horizontal" + android:layout_weight="0" + android:gravity="center_vertical" + > + <TextView android:id="@+id/text" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="center" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + /> + <TextView android:id="@+id/info" + android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_weight="0" + android:singleLine="true" + android:gravity="center" + android:paddingStart="8dp" + /> + <ImageView android:id="@+id/right_icon" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_gravity="center" + android:layout_weight="0" + android:layout_marginStart="8dp" + android:scaleType="centerInside" + android:visibility="gone" + android:drawableAlpha="153" + /> + </LinearLayout> + </LinearLayout> +</FrameLayout> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8d68277aff76..cfd4a6399f9c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -370,6 +370,17 @@ <!-- If this is true, key chords can be used to take a screenshot on the device. --> <bool name="config_enableScreenshotChord">true</bool> + <!-- Auto-rotation behavior --> + + <!-- If true, enables auto-rotation features using the accelerometer. + Otherwise, auto-rotation is disabled. Applications may still request + to use specific orientations but the sensor is ignored and sensor-based + orientations are not available. Furthermore, all auto-rotation related + settings are omitted from the system UI. In certain situations we may + still use the accelerometer to determine the orientation, such as when + docked if the dock is configured to enable the accelerometer. --> + <bool name="config_supportAutoRotation">true</bool> + <!-- If true, the screen can be rotated via the accelerometer in all 4 rotations as the default behavior. --> <bool name="config_allowAllRotations">false</bool> @@ -382,31 +393,34 @@ true here reverses that logic. --> <bool name="config_reverseDefaultRotation">false</bool> + <!-- Lid switch behavior --> + <!-- The number of degrees to rotate the display when the keyboard is open. A value of -1 means no change in orientation by default. --> <integer name="config_lidOpenRotation">-1</integer> - <!-- The number of degrees to rotate the display when the device is in a desk dock. - A value of -1 means no change in orientation by default. --> - <integer name="config_deskDockRotation">-1</integer> + <!-- Indicate whether the lid state impacts the accessibility of + the physical keyboard. 0 means it doesn't, 1 means it is accessible + when the lid is open, 2 means it is accessible when the lid is + closed. The default is 0. --> + <integer name="config_lidKeyboardAccessibility">0</integer> - <!-- The number of degrees to rotate the display when the device is in a car dock. - A value of -1 means no change in orientation by default. --> - <integer name="config_carDockRotation">-1</integer> + <!-- Indicate whether the lid state impacts the accessibility of + the navigation buttons. 0 means it doesn't, 1 means it is accessible + when the lid is open, 2 means it is accessible when the lid is + closed. The default is 0. --> + <integer name="config_lidNavigationAccessibility">0</integer> - <!-- The number of degrees to rotate the display when the device has HDMI connected - but is not in a dock. A value of -1 means no change in orientation by default. - Use -1 except on older devices whose Hardware Composer HAL does not - provide full support for multiple displays. --> - <integer name="config_undockedHdmiRotation">-1</integer> + <!-- Indicate whether closing the lid causes the device to go to sleep and opening + it causes the device to wake up. + The default is false. --> + <bool name="config_lidControlsSleep">false</bool> - <!-- Control the default UI mode type to use when there is no other type override - happening. One of the following values (See Configuration.java): - 1 UI_MODE_TYPE_NORMAL - 4 UI_MODE_TYPE_TELEVISION - 5 UI_MODE_TYPE_APPLIANCE - Any other values will have surprising consequences. --> - <integer name="config_defaultUiModeType">1</integer> + <!-- Desk dock behavior --> + + <!-- The number of degrees to rotate the display when the device is in a desk dock. + A value of -1 means no change in orientation by default. --> + <integer name="config_deskDockRotation">-1</integer> <!-- Control whether being in the desk dock (and powered) always keeps the screen on. By default it stays on when plugged in to @@ -414,12 +428,6 @@ in to AC and 2 to stay on when plugged in to USB. (So 3 for both.) --> <integer name="config_deskDockKeepsScreenOn">1</integer> - <!-- Control whether being in the car dock (and powered) always - keeps the screen on. By default it stays on when plugged in to - AC. 0 will not keep it on; or together 1 to stay on when plugged - in to AC and 2 to stay on when plugged in to USB. (So 3 for both.) --> - <integer name="config_carDockKeepsScreenOn">1</integer> - <!-- Control whether being in the desk dock should enable accelerometer based screen orientation. This defaults to true because it is common for desk docks to be sold in a variety of form factors @@ -428,27 +436,39 @@ we rely on gravity to determine the effective orientation. --> <bool name="config_deskDockEnablesAccelerometer">true</bool> + <!-- Car dock behavior --> + + <!-- The number of degrees to rotate the display when the device is in a car dock. + A value of -1 means no change in orientation by default. --> + <integer name="config_carDockRotation">-1</integer> + + <!-- Control whether being in the car dock (and powered) always + keeps the screen on. By default it stays on when plugged in to + AC. 0 will not keep it on; or together 1 to stay on when plugged + in to AC and 2 to stay on when plugged in to USB. (So 3 for both.) --> + <integer name="config_carDockKeepsScreenOn">1</integer> + <!-- Control whether being in the car dock should enable accelerometer based screen orientation. This defaults to true because putting a device in a car dock make the accelerometer more a physical input (like a lid). --> + <bool name="config_carDockEnablesAccelerometer">true</bool> - <!-- Indicate whether the lid state impacts the accessibility of - the physical keyboard. 0 means it doesn't, 1 means it is accessible - when the lid is open, 2 means it is accessible when the lid is - closed. The default is 0. --> - <integer name="config_lidKeyboardAccessibility">0</integer> + <!-- HDMI behavior --> - <!-- Indicate whether the lid state impacts the accessibility of - the navigation buttons. 0 means it doesn't, 1 means it is accessible - when the lid is open, 2 means it is accessible when the lid is - closed. The default is 0. --> - <integer name="config_lidNavigationAccessibility">0</integer> + <!-- The number of degrees to rotate the display when the device has HDMI connected + but is not in a dock. A value of -1 means no change in orientation by default. + Use -1 except on older devices whose Hardware Composer HAL does not + provide full support for multiple displays. --> + <integer name="config_undockedHdmiRotation">-1</integer> - <!-- Indicate whether closing the lid causes the device to go to sleep and opening - it causes the device to wake up. - The default is false. --> - <bool name="config_lidControlsSleep">false</bool> + <!-- Control the default UI mode type to use when there is no other type override + happening. One of the following values (See Configuration.java): + 1 UI_MODE_TYPE_NORMAL + 4 UI_MODE_TYPE_TELEVISION + 5 UI_MODE_TYPE_APPLIANCE + Any other values will have surprising consequences. --> + <integer name="config_defaultUiModeType">1</integer> <!-- Indicate whether to allow the device to suspend when the screen is off due to the proximity sensor. This resource should only be set to true diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index e525ef71190c..be875ffb2b04 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -271,6 +271,33 @@ please see styles_device_defaults.xml. <item name="android:textColor">#CCCCCC</item> </style> + <style name="TextAppearance.StatusBar.Quantum"> + </style> + <style name="TextAppearance.StatusBar.Quantum.EventContent"> + <item name="android:textColor">#888888</item> + <item name="android:textSize">@dimen/notification_text_size</item> + </style> + <style name="TextAppearance.StatusBar.Quantum.EventContent.Title"> + <item name="android:textColor">#000000</item> + <item name="android:fontFamily">sans-serif-light</item> + <item name="android:textSize">@dimen/notification_title_text_size</item> + <item name="android:textStyle">bold</item> + </style> + <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2"> + <item name="android:textSize">@dimen/notification_subtext_size</item> + </style> + <style name="TextAppearance.StatusBar.Quantum.EventContent.Info"> + <item name="android:textSize">@dimen/notification_subtext_size</item> + <item name="android:textColor">#888888</item> + </style> + <style name="TextAppearance.StatusBar.Quantum.EventContent.Time"> + <item name="android:textSize">@dimen/notification_subtext_size</item> + <item name="android:textColor">#888888</item> + </style> + <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis"> + <item name="android:textColor">#555555</item> + </style> + <style name="TextAppearance.Small.CalendarViewWeekDayView"> <item name="android:textStyle">bold</item> </style> diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml index c35bd48187f8..52d90bce3ff9 100644 --- a/core/res/res/values/styles_micro.xml +++ b/core/res/res/values/styles_micro.xml @@ -25,7 +25,7 @@ <item name="android:solidColor">@android:color/transparent</item> <item name="android:selectionDivider">@android:drawable/numberpicker_selection_divider</item> <item name="android:selectionDividerHeight">0dip</item> - <item name="android:selectionDividersDistance">0dip</item> + <item name="android:selectionDividersDistance">104dip</item> <item name="android:internalMinWidth">64dip</item> <item name="android:internalMaxHeight">180dip</item> <item name="virtualButtonPressedDrawable">?android:attr/selectableItemBackground</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a4f97629ae34..6624da438f69 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1303,6 +1303,7 @@ <java-symbol type="bool" name="config_lidControlsSleep" /> <java-symbol type="bool" name="config_reverseDefaultRotation" /> <java-symbol type="bool" name="config_showNavigationBar" /> + <java-symbol type="bool" name="config_supportAutoRotation" /> <java-symbol type="bool" name="target_honeycomb_needs_options_menu" /> <java-symbol type="dimen" name="navigation_bar_height" /> <java-symbol type="dimen" name="navigation_bar_height_landscape" /> @@ -1627,7 +1628,16 @@ <java-symbol type="integer" name="config_maxResolverActivityColumns" /> <java-symbol type="array" name="config_notificationScorers" /> - <!-- From SystemUI --> + <java-symbol type="layout" name="notification_quantum_action" /> + <java-symbol type="layout" name="notification_quantum_action_list" /> + <java-symbol type="layout" name="notification_quantum_action_tombstone" /> + <java-symbol type="layout" name="notification_template_quantum_base" /> + <java-symbol type="layout" name="notification_template_quantum_big_base" /> + <java-symbol type="layout" name="notification_template_quantum_big_picture" /> + <java-symbol type="layout" name="notification_template_quantum_big_text" /> + <java-symbol type="layout" name="notification_template_quantum_inbox" /> + + <!-- From SystemUI --> <java-symbol type="anim" name="push_down_in" /> <java-symbol type="anim" name="push_down_out" /> <java-symbol type="anim" name="push_up_in" /> diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml index e429f96928d6..7c0b7bc1103d 100644 --- a/core/res/res/values/themes_micro.xml +++ b/core/res/res/values/themes_micro.xml @@ -14,7 +14,8 @@ limitations under the License. --> <resources> - <style name="Theme.Micro" parent="Theme.Holo"> + <style name="Theme.Micro" parent="Theme.Holo.NoActionBar"> + <item name="textViewStyle">@android:style/Widget.Micro.TextView</item> <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item> <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item> <item name="windowIsFloating">false</item> diff --git a/core/tests/inputmethodtests/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh index 5e123ec20a2f..b0b119b47004 100755 --- a/core/tests/inputmethodtests/run_core_inputmethod_test.sh +++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh @@ -21,4 +21,4 @@ if [[ $rebuild == true ]]; then $COMMAND fi -adb shell am instrument -w -e class android.os.InputMethodTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner +adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeArrayTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeArrayTest.java new file mode 100644 index 000000000000..1e0a9190558e --- /dev/null +++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeArrayTest.java @@ -0,0 +1,77 @@ +/* + * 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.os; + +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodSubtype; +import android.view.inputmethod.InputMethodSubtypeArray; +import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; + +import java.util.ArrayList; + +public class InputMethodSubtypeArrayTest extends InstrumentationTestCase { + @SmallTest + public void testInstanciate() throws Exception { + final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>(); + subtypes.add(createDummySubtype(0, "en_US")); + subtypes.add(createDummySubtype(1, "en_US")); + subtypes.add(createDummySubtype(2, "ja_JP")); + + final InputMethodSubtypeArray array = new InputMethodSubtypeArray(subtypes); + assertEquals(subtypes.size(), array.getCount()); + assertEquals(subtypes.get(0), array.get(0)); + assertEquals(subtypes.get(1), array.get(1)); + assertEquals(subtypes.get(2), array.get(2)); + + final InputMethodSubtypeArray clonedArray = cloneViaParcel(array); + assertEquals(subtypes.size(), clonedArray.getCount()); + assertEquals(subtypes.get(0), clonedArray.get(0)); + assertEquals(subtypes.get(1), clonedArray.get(1)); + assertEquals(subtypes.get(2), clonedArray.get(2)); + + final InputMethodSubtypeArray clonedClonedArray = cloneViaParcel(clonedArray); + assertEquals(clonedArray.getCount(), clonedClonedArray.getCount()); + assertEquals(clonedArray.get(0), clonedClonedArray.get(0)); + assertEquals(clonedArray.get(1), clonedClonedArray.get(1)); + assertEquals(clonedArray.get(2), clonedClonedArray.get(2)); + } + + InputMethodSubtypeArray cloneViaParcel(final InputMethodSubtypeArray original) { + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + original.writeToParcel(parcel); + parcel.setDataPosition(0); + return new InputMethodSubtypeArray(parcel); + } finally { + if (parcel != null) { + parcel.recycle(); + } + } + } + + private static InputMethodSubtype createDummySubtype(final int id, final String locale) { + final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); + return builder.setSubtypeNameResId(0) + .setSubtypeIconResId(0) + .setSubtypeId(id) + .setSubtypeLocale(locale) + .setIsAsciiCapable(true) + .build(); + } +} diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index c3aa7332a8b1..0f7648698d27 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -109,6 +109,9 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { void DisplayList::setData(DisplayListData* data) { delete mDisplayListData; mDisplayListData = data; + if (mDisplayListData) { + Caches::getInstance().registerFunctors(mDisplayListData->functorCount); + } } /** diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 35327c0a3be7..ed98b9630af7 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -38,6 +38,7 @@ LOCAL_SHARED_LIBRARIES := \ libcamera_client \ libmtp \ libusbhost \ + libjhead \ libexif \ libstagefright_amrnb_common \ diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index d3a8b2256478..a78f16d31e74 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -561,7 +561,7 @@ static jboolean android_media_MediaExtractor_getSampleCryptoInfo( return JNI_FALSE; } - size_t numSubSamples = size / sizeof(size_t); + size_t numSubSamples = size / sizeof(int32_t); if (numSubSamples == 0) { return JNI_FALSE; @@ -571,7 +571,7 @@ static jboolean android_media_MediaExtractor_getSampleCryptoInfo( jboolean isCopy; jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); for (size_t i = 0; i < numSubSamples; ++i) { - dst[i] = ((const size_t *)data)[i]; + dst[i] = ((const int32_t *)data)[i]; } env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0); dst = NULL; @@ -588,7 +588,7 @@ static jboolean android_media_MediaExtractor_getSampleCryptoInfo( jboolean isCopy; jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy); for (size_t i = 0; i < numSubSamples; ++i) { - dst[i] = ((const size_t *)data)[i]; + dst[i] = ((const int32_t *)data)[i]; } env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0); dst = NULL; diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index f3a7ff7f82d3..4e42ae30fb34 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -256,7 +256,7 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, fields.createConfigMethod, SkBitmap::kRGB_565_Config); - size_t width, height; + uint32_t width, height; bool swapWidthAndHeight = false; if (videoFrame->mRotationAngle == 90 || videoFrame->mRotationAngle == 270) { width = videoFrame->mHeight; @@ -287,8 +287,8 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, if (videoFrame->mDisplayWidth != videoFrame->mWidth || videoFrame->mDisplayHeight != videoFrame->mHeight) { - size_t displayWidth = videoFrame->mDisplayWidth; - size_t displayHeight = videoFrame->mDisplayHeight; + uint32_t displayWidth = videoFrame->mDisplayWidth; + uint32_t displayHeight = videoFrame->mDisplayHeight; if (swapWidthAndHeight) { displayWidth = videoFrame->mDisplayHeight; displayHeight = videoFrame->mDisplayWidth; diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 5a2e261fa3a4..a9322b993101 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -595,13 +595,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mDetached = false; } - /** - * This method is used as part of the View class and is not normally - * called or subclassed by clients of GLSurfaceView. - * Must not be called before a renderer has been set. - */ + /** @hide */ @Override - protected void onDetachedFromWindow() { + protected void onDetachedFromWindowInternal() { if (LOG_ATTACH_DETACH) { Log.d(TAG, "onDetachedFromWindow"); } @@ -609,7 +605,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mGLThread.requestExitAndWait(); } mDetached = true; - super.onDetachedFromWindow(); + super.onDetachedFromWindowInternal(); } // ---------------------------------------------------------------------- diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png Binary files differnew file mode 100644 index 000000000000..fe6dc5296dbd --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png Binary files differnew file mode 100644 index 000000000000..0f9dfc7fdcec --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png Binary files differnew file mode 100644 index 000000000000..aea75c105bd1 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png Binary files differnew file mode 100644 index 000000000000..46d2a16c5eee --- /dev/null +++ b/packages/SystemUI/res/drawable-ldpi/ic_qs_color_space_alpha.png diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png Binary files differnew file mode 100644 index 000000000000..704b4ecf79c0 --- /dev/null +++ b/packages/SystemUI/res/drawable-ldpi/ic_qs_contrast_alpha.png diff --git a/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png Binary files differnew file mode 100644 index 000000000000..d56efb5081f4 --- /dev/null +++ b/packages/SystemUI/res/drawable-ldpi/ic_qs_inversion_alpha.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png Binary files differnew file mode 100644 index 000000000000..18b6029649c8 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png Binary files differnew file mode 100644 index 000000000000..a4dd0878879d --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png Binary files differnew file mode 100644 index 000000000000..b6ea14e6dbdb --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png Binary files differnew file mode 100644 index 000000000000..95cf67f008d6 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png Binary files differnew file mode 100644 index 000000000000..9331e529ea20 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png Binary files differnew file mode 100644 index 000000000000..efd8b9ee2201 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png Binary files differnew file mode 100644 index 000000000000..7f441c812b76 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png Binary files differnew file mode 100644 index 000000000000..82c3842ff3d9 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png Binary files differnew file mode 100644 index 000000000000..ce9bae257d8b --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png diff --git a/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml b/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml new file mode 100644 index 000000000000..cf34ba6421dc --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_qs_color_space_alpha" + android:tint="@color/ic_qs_off" /> diff --git a/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml b/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml new file mode 100644 index 000000000000..180668887ea1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_qs_color_space_alpha" + android:tint="@color/ic_qs_on" /> diff --git a/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml b/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml new file mode 100644 index 000000000000..5f65d8aceee4 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_qs_contrast_alpha" + android:tint="@color/ic_qs_off" /> diff --git a/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml b/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml new file mode 100644 index 000000000000..a01892905b75 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_qs_contrast_alpha" + android:tint="@color/ic_qs_on" /> diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml new file mode 100644 index 000000000000..9018a90e34a7 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_qs_inversion_alpha" + android:tint="@color/ic_qs_off" /> diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml new file mode 100644 index 000000000000..91102019fa0a --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/ic_qs_inversion_alpha" + android:tint="@color/ic_qs_on" /> diff --git a/packages/SystemUI/res/drawable/notification_icon_legacy_bg.xml b/packages/SystemUI/res/drawable/notification_icon_legacy_bg.xml new file mode 100644 index 000000000000..4ac67c3e4765 --- /dev/null +++ b/packages/SystemUI/res/drawable/notification_icon_legacy_bg.xml @@ -0,0 +1,22 @@ +<?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 + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <solid + android:color="@color/notification_icon_legacy_bg_color"/> +</shape> diff --git a/packages/SystemUI/res/drawable/notification_icon_legacy_bg_inset.xml b/packages/SystemUI/res/drawable/notification_icon_legacy_bg_inset.xml new file mode 100644 index 000000000000..96c557366189 --- /dev/null +++ b/packages/SystemUI/res/drawable/notification_icon_legacy_bg_inset.xml @@ -0,0 +1,21 @@ +<?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 + --> + +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/notification_icon_legacy_bg" android:insetBottom="8dp" + android:insetLeft="8dp" android:insetRight="8dp" android:insetTop="8dp" + android:visible="true"/> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index e525fbb01bb4..a59dc75989e0 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -39,4 +39,12 @@ <color name="status_bar_clock_color">#FFFFFFFF</color> <drawable name="notification_item_background_color">#ff111111</drawable> <drawable name="notification_item_background_color_pressed">#ff454545</drawable> + <color name="notification_icon_legacy_bg_color">#ff4285F4</color> + <color name="notification_action_legacy_color_filter">#ff555555</color> + + <!-- Tint color for inactive Quick Settings icons. --> + <color name="ic_qs_off">#ff404040</color> + + <!-- Tint color for active Quick Settings icons. --> + <color name="ic_qs_on">#ffffffff</color> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/ImageUtils.java b/packages/SystemUI/src/com/android/systemui/ImageUtils.java new file mode 100644 index 000000000000..540ba20c143a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/ImageUtils.java @@ -0,0 +1,82 @@ +/* + * 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; + +import android.graphics.Bitmap; + +/** + * Utility class for image analysis and processing. + */ +public class ImageUtils { + + // Amount (max is 255) that two channels can differ before the color is no longer "gray". + private static final int TOLERANCE = 20; + + // Alpha amount for which values below are considered transparent. + private static final int ALPHA_TOLERANCE = 50; + + private int[] mTempBuffer; + + /** + * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect + * gray". + */ + public boolean isGrayscale(Bitmap bitmap) { + final int height = bitmap.getHeight(); + final int width = bitmap.getWidth(); + int size = height*width; + + ensureBufferSize(size); + bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); + for (int i = 0; i < size; i++) { + if (!isGrayscale(mTempBuffer[i])) { + return false; + } + } + return true; + } + + /** + * Makes sure that {@code mTempBuffer} has at least length {@code size}. + */ + private void ensureBufferSize(int size) { + if (mTempBuffer == null || mTempBuffer.length < size) { + mTempBuffer = new int[size]; + } + } + + /** + * Classifies a color as grayscale or not. Grayscale here means "very close to a perfect + * gray"; if all three channels are approximately equal, this will return true. + * + * Note that really transparent colors are always grayscale. + */ + public boolean isGrayscale(int color) { + int alpha = 0xFF & (color >> 24); + if (alpha < ALPHA_TOLERANCE) { + return true; + } + + int r = 0xFF & (color >> 16); + int g = 0xFF & (color >> 8); + int b = 0xFF & color; + + return Math.abs(r - g) < TOLERANCE + && Math.abs(r - b) < TOLERANCE + && Math.abs(g - b) < TOLERANCE; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java new file mode 100644 index 000000000000..feec87cc609f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java @@ -0,0 +1,218 @@ +/* + * 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.power; + +import android.app.AlertDialog; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.SystemClock; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Slog; +import android.view.View; +import android.view.WindowManager; +import android.widget.TextView; + +import com.android.systemui.R; + +import java.io.PrintWriter; + +public class PowerDialogWarnings implements PowerUI.WarningsUI { + private static final String TAG = PowerUI.TAG + ".Dialog"; + private static final boolean DEBUG = PowerUI.DEBUG; + + private final Context mContext; + + private int mBatteryLevel; + private int mBucket; + private long mScreenOffTime; + + private AlertDialog mInvalidChargerDialog; + private AlertDialog mLowBatteryDialog; + private TextView mBatteryLevelTextView; + + public PowerDialogWarnings(Context context) { + mContext = context; + } + + @Override + public void dump(PrintWriter pw) { + pw.print("mInvalidChargerDialog="); + pw.println(mInvalidChargerDialog == null ? "null" : mInvalidChargerDialog.toString()); + pw.print("mLowBatteryDialog="); + pw.println(mLowBatteryDialog == null ? "null" : mLowBatteryDialog.toString()); + } + + @Override + public void update(int batteryLevel, int bucket, long screenOffTime) { + mBatteryLevel = batteryLevel; + mBucket = bucket; + mScreenOffTime = screenOffTime; + } + + @Override + public boolean isInvalidChargerWarningShowing() { + return mInvalidChargerDialog != null; + } + + @Override + public void updateLowBatteryWarning() { + if (mBatteryLevelTextView != null) { + showLowBatteryWarning(false /*playSound*/); + } + } + + @Override + public void dismissLowBatteryWarning() { + if (mLowBatteryDialog != null) { + Slog.i(TAG, "closing low battery warning: level=" + mBatteryLevel); + mLowBatteryDialog.dismiss(); + } + } + + @Override + public void showLowBatteryWarning(boolean playSound) { + Slog.i(TAG, + ((mBatteryLevelTextView == null) ? "showing" : "updating") + + " low battery warning: level=" + mBatteryLevel + + " [" + mBucket + "]"); + + CharSequence levelText = mContext.getString( + R.string.battery_low_percent_format, mBatteryLevel); + + if (mBatteryLevelTextView != null) { + mBatteryLevelTextView.setText(levelText); + } else { + View v = View.inflate(mContext, R.layout.battery_low, null); + mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent); + + mBatteryLevelTextView.setText(levelText); + + AlertDialog.Builder b = new AlertDialog.Builder(mContext); + b.setCancelable(true); + b.setTitle(R.string.battery_low_title); + b.setView(v); + b.setIconAttribute(android.R.attr.alertDialogIcon); + b.setPositiveButton(android.R.string.ok, null); + + final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_MULTIPLE_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_NO_HISTORY); + if (intent.resolveActivity(mContext.getPackageManager()) != null) { + b.setNegativeButton(R.string.battery_low_why, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + dismissLowBatteryWarning(); + } + }); + } + + AlertDialog d = b.create(); + d.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + mLowBatteryDialog = null; + mBatteryLevelTextView = null; + } + }); + d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + d.getWindow().getAttributes().privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; + d.show(); + mLowBatteryDialog = d; + if (playSound) { + playLowBatterySound(); + } + } + } + + private void playLowBatterySound() { + final ContentResolver cr = mContext.getContentResolver(); + + final int silenceAfter = Settings.Global.getInt(cr, + Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0); + final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime; + if (silenceAfter > 0 + && mScreenOffTime > 0 + && offTime > silenceAfter) { + Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter + + "ms): not waking up the user with low battery sound"); + return; + } + + if (DEBUG) { + Slog.d(TAG, "playing low battery sound. pick-a-doop!"); // WOMP-WOMP is deprecated + } + + if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) { + final String soundPath = Settings.Global.getString(cr, + Settings.Global.LOW_BATTERY_SOUND); + if (soundPath != null) { + final Uri soundUri = Uri.parse("file://" + soundPath); + if (soundUri != null) { + final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); + if (sfx != null) { + sfx.setStreamType(AudioManager.STREAM_SYSTEM); + sfx.play(); + } + } + } + } + } + + @Override + public void dismissInvalidChargerWarning() { + if (mInvalidChargerDialog != null) { + mInvalidChargerDialog.dismiss(); + } + } + + @Override + public void showInvalidChargerWarning() { + Slog.d(TAG, "showing invalid charger dialog"); + + dismissLowBatteryWarning(); + + AlertDialog.Builder b = new AlertDialog.Builder(mContext); + b.setCancelable(true); + b.setMessage(R.string.invalid_charger); + b.setIconAttribute(android.R.attr.alertDialogIcon); + b.setPositiveButton(android.R.string.ok, null); + + AlertDialog d = b.create(); + d.setOnDismissListener(new DialogInterface.OnDismissListener() { + public void onDismiss(DialogInterface dialog) { + mInvalidChargerDialog = null; + mBatteryLevelTextView = null; + } + }); + + d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + d.show(); + mInvalidChargerDialog = d; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 28c2772f5c9f..0fb0f8b02c65 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -16,29 +16,17 @@ package com.android.systemui.power; -import android.app.AlertDialog; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.media.AudioManager; -import android.media.Ringtone; -import android.media.RingtoneManager; -import android.net.Uri; import android.os.BatteryManager; import android.os.Handler; import android.os.PowerManager; import android.os.SystemClock; -import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; -import android.view.View; -import android.view.WindowManager; -import android.widget.TextView; -import com.android.systemui.R; import com.android.systemui.SystemUI; import java.io.FileDescriptor; @@ -50,19 +38,17 @@ public class PowerUI extends SystemUI { static final boolean DEBUG = false; - Handler mHandler = new Handler(); + private WarningsUI mWarnings; - int mBatteryLevel = 100; - int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; - int mPlugType = 0; - int mInvalidCharger = 0; + private final Handler mHandler = new Handler(); - int mLowBatteryAlertCloseLevel; - int[] mLowBatteryReminderLevels = new int[2]; + private int mBatteryLevel = 100; + private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; + private int mPlugType = 0; + private int mInvalidCharger = 0; - AlertDialog mInvalidChargerDialog; - AlertDialog mLowBatteryDialog; - TextView mBatteryLevelTextView; + private int mLowBatteryAlertCloseLevel; + private final int[] mLowBatteryReminderLevels = new int[2]; private long mScreenOffTime = -1; @@ -77,6 +63,7 @@ public class PowerUI extends SystemUI { final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mScreenOffTime = pm.isScreenOn() ? -1 : SystemClock.elapsedRealtime(); + mWarnings = new PowerDialogWarnings(mContext); // Register for Intent broadcasts for... IntentFilter filter = new IntentFilter(); @@ -145,13 +132,14 @@ public class PowerUI extends SystemUI { Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged); } + mWarnings.update(mBatteryLevel, bucket, mScreenOffTime); if (oldInvalidCharger == 0 && mInvalidCharger != 0) { Slog.d(TAG, "showing invalid charger warning"); - showInvalidChargerDialog(); + mWarnings.showInvalidChargerWarning(); return; } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) { - dismissInvalidChargerDialog(); - } else if (mInvalidChargerDialog != null) { + mWarnings.dismissInvalidChargerWarning(); + } else if (mWarnings.isInvalidChargerWarningShowing()) { // if invalid charger is showing, don't show low battery return; } @@ -160,16 +148,13 @@ public class PowerUI extends SystemUI { && (bucket < oldBucket || oldPlugged) && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN && bucket < 0) { - showLowBatteryWarning(); - // only play SFX when the dialog comes up or the bucket changes - if (bucket != oldBucket || oldPlugged) { - playLowBatterySound(); - } + final boolean playSound = bucket != oldBucket || oldPlugged; + mWarnings.showLowBatteryWarning(playSound); } else if (plugged || (bucket > oldBucket && bucket > 0)) { - dismissLowBatteryWarning(); - } else if (mBatteryLevelTextView != null) { - showLowBatteryWarning(); + mWarnings.dismissLowBatteryWarning(); + } else { + mWarnings.updateLowBatteryWarning(); } } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { mScreenOffTime = SystemClock.elapsedRealtime(); @@ -181,142 +166,11 @@ public class PowerUI extends SystemUI { } }; - void dismissLowBatteryWarning() { - if (mLowBatteryDialog != null) { - Slog.i(TAG, "closing low battery warning: level=" + mBatteryLevel); - mLowBatteryDialog.dismiss(); - } - } - - void showLowBatteryWarning() { - Slog.i(TAG, - ((mBatteryLevelTextView == null) ? "showing" : "updating") - + " low battery warning: level=" + mBatteryLevel - + " [" + findBatteryLevelBucket(mBatteryLevel) + "]"); - - CharSequence levelText = mContext.getString( - R.string.battery_low_percent_format, mBatteryLevel); - - if (mBatteryLevelTextView != null) { - mBatteryLevelTextView.setText(levelText); - } else { - View v = View.inflate(mContext, R.layout.battery_low, null); - mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent); - - mBatteryLevelTextView.setText(levelText); - - AlertDialog.Builder b = new AlertDialog.Builder(mContext); - b.setCancelable(true); - b.setTitle(R.string.battery_low_title); - b.setView(v); - b.setIconAttribute(android.R.attr.alertDialogIcon); - b.setPositiveButton(android.R.string.ok, null); - - final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_MULTIPLE_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_NO_HISTORY); - if (intent.resolveActivity(mContext.getPackageManager()) != null) { - b.setNegativeButton(R.string.battery_low_why, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mContext.startActivityAsUser(intent, UserHandle.CURRENT); - dismissLowBatteryWarning(); - } - }); - } - - AlertDialog d = b.create(); - d.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - mLowBatteryDialog = null; - mBatteryLevelTextView = null; - } - }); - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - d.getWindow().getAttributes().privateFlags |= - WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; - d.show(); - mLowBatteryDialog = d; - } - } - - void playLowBatterySound() { - final ContentResolver cr = mContext.getContentResolver(); - - final int silenceAfter = Settings.Global.getInt(cr, - Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0); - final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime; - if (silenceAfter > 0 - && mScreenOffTime > 0 - && offTime > silenceAfter) { - Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter - + "ms): not waking up the user with low battery sound"); - return; - } - - if (DEBUG) { - Slog.d(TAG, "playing low battery sound. pick-a-doop!"); // WOMP-WOMP is deprecated - } - - if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) { - final String soundPath = Settings.Global.getString(cr, - Settings.Global.LOW_BATTERY_SOUND); - if (soundPath != null) { - final Uri soundUri = Uri.parse("file://" + soundPath); - if (soundUri != null) { - final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); - if (sfx != null) { - sfx.setStreamType(AudioManager.STREAM_SYSTEM); - sfx.play(); - } - } - } - } - } - - void dismissInvalidChargerDialog() { - if (mInvalidChargerDialog != null) { - mInvalidChargerDialog.dismiss(); - } - } - - void showInvalidChargerDialog() { - Slog.d(TAG, "showing invalid charger dialog"); - - dismissLowBatteryWarning(); - - AlertDialog.Builder b = new AlertDialog.Builder(mContext); - b.setCancelable(true); - b.setMessage(R.string.invalid_charger); - b.setIconAttribute(android.R.attr.alertDialogIcon); - b.setPositiveButton(android.R.string.ok, null); - - AlertDialog d = b.create(); - d.setOnDismissListener(new DialogInterface.OnDismissListener() { - public void onDismiss(DialogInterface dialog) { - mInvalidChargerDialog = null; - mBatteryLevelTextView = null; - } - }); - - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - d.show(); - mInvalidChargerDialog = d; - } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print("mLowBatteryAlertCloseLevel="); pw.println(mLowBatteryAlertCloseLevel); pw.print("mLowBatteryReminderLevels="); pw.println(Arrays.toString(mLowBatteryReminderLevels)); - pw.print("mInvalidChargerDialog="); - pw.println(mInvalidChargerDialog == null ? "null" : mInvalidChargerDialog.toString()); - pw.print("mLowBatteryDialog="); - pw.println(mLowBatteryDialog == null ? "null" : mLowBatteryDialog.toString()); pw.print("mBatteryLevel="); pw.println(Integer.toString(mBatteryLevel)); pw.print("mBatteryStatus="); @@ -338,6 +192,18 @@ public class PowerUI extends SystemUI { Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0)); pw.print("bucket: "); pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel))); + mWarnings.dump(pw); + } + + public interface WarningsUI { + void update(int batteryLevel, int bucket, long screenOffTime); + void dismissLowBatteryWarning(); + void showLowBatteryWarning(boolean playSound); + void dismissInvalidChargerWarning(); + void showInvalidChargerWarning(); + void updateLowBatteryWarning(); + boolean isInvalidChargerWarningShowing(); + void dump(PrintWriter pw); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index fb117432db15..eb07d888610b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -28,9 +28,15 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.database.ContentObserver; +import android.graphics.Color; +import android.graphics.PorterDuff; import android.graphics.Rect; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -44,9 +50,13 @@ import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import android.text.style.TextAppearanceSpan; import android.util.Log; import android.util.SparseBooleanArray; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.IWindowManager; import android.view.LayoutInflater; @@ -57,6 +67,7 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupMenu; @@ -67,6 +78,7 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIconList; import com.android.internal.widget.SizeAdaptiveLayout; +import com.android.systemui.ImageUtils; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SearchPanelView; @@ -76,6 +88,7 @@ import com.android.systemui.statusbar.policy.NotificationRowLayout; import java.util.ArrayList; import java.util.Locale; +import java.util.Stack; public abstract class BaseStatusBar extends SystemUI implements CommandQueue.Callbacks { @@ -140,6 +153,8 @@ public abstract class BaseStatusBar extends SystemUI implements // public mode, private notifications, etc private boolean mLockscreenPublicMode = false; private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); + private Context mLightThemeContext; + private ImageUtils mImageUtils = new ImageUtils(); // UI-specific methods @@ -261,6 +276,8 @@ public abstract class BaseStatusBar extends SystemUI implements true, mLockscreenSettingsObserver, UserHandle.USER_ALL); + mLightThemeContext = new RemoteViewsThemeContextWrapper(mContext, + android.R.style.Theme_Holo_Light); mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); @@ -412,6 +429,158 @@ public abstract class BaseStatusBar extends SystemUI implements } } + private void processLegacyHoloNotification(StatusBarNotification sbn, View content) { + + // TODO: Also skip processing if it is a holo-style notification. + // If the notification is custom, we can't process it. + if (!sbn.getNotification().extras.getBoolean(Notification.EXTRA_BUILDER_REMOTE_VIEWS)) { + return; + } + + processLegacyHoloLargeIcon(content); + processLegacyHoloActions(content); + processLegacyNotificationIcon(content); + processLegacyTextViews(content); + } + + /** + * @return the context to be used for the inflation of the specified {@code sbn}; this is + * dependent whether the notification is quantum-style or holo-style + */ + private Context getInflationContext(StatusBarNotification sbn) { + + // TODO: Adjust this logic when we change the theme of the status bar windows. + if (sbn.getNotification().extras.getBoolean(Notification.EXTRA_BUILDER_REMOTE_VIEWS)) { + return mLightThemeContext; + } else { + return mContext; + } + } + + private void processLegacyNotificationIcon(View content) { + View v = content.findViewById(com.android.internal.R.id.right_icon); + if (v != null & v instanceof ImageView) { + ImageView iv = (ImageView) v; + Drawable d = iv.getDrawable(); + if (isMonochrome(d)) { + d.mutate(); + d.setColorFilter(mLightThemeContext.getResources().getColor( + R.color.notification_action_legacy_color_filter), PorterDuff.Mode.MULTIPLY); + } + } + } + + private void processLegacyHoloLargeIcon(View content) { + View v = content.findViewById(com.android.internal.R.id.icon); + if (v != null & v instanceof ImageView) { + ImageView iv = (ImageView) v; + if (isMonochrome(iv.getDrawable())) { + iv.setBackground(mLightThemeContext.getResources().getDrawable( + R.drawable.notification_icon_legacy_bg_inset)); + } + } + } + + private boolean isMonochrome(Drawable d) { + if (d == null) { + return false; + } else if (d instanceof BitmapDrawable) { + BitmapDrawable bd = (BitmapDrawable) d; + return bd.getBitmap() != null && mImageUtils.isGrayscale(bd.getBitmap()); + } else if (d instanceof AnimationDrawable) { + AnimationDrawable ad = (AnimationDrawable) d; + int count = ad.getNumberOfFrames(); + return count > 0 && isMonochrome(ad.getFrame(0)); + } else { + return false; + } + } + + private void processLegacyHoloActions(View content) { + View v = content.findViewById(com.android.internal.R.id.actions); + if (v != null & v instanceof ViewGroup) { + ViewGroup vg = (ViewGroup) v; + int childCount = vg.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = vg.getChildAt(i); + if (child instanceof Button) { + Button button = (Button) child; + Drawable[] compoundDrawables = button.getCompoundDrawablesRelative(); + if (isMonochrome(compoundDrawables[0])) { + Drawable d = compoundDrawables[0]; + d.mutate(); + d.setColorFilter(mLightThemeContext.getResources().getColor( + R.color.notification_action_legacy_color_filter), + PorterDuff.Mode.MULTIPLY); + } + } + } + } + } + + private void processLegacyTextViews(View content) { + Stack<View> viewStack = new Stack<View>(); + viewStack.push(content); + while(!viewStack.isEmpty()) { + View current = viewStack.pop(); + if(current instanceof ViewGroup){ + ViewGroup currentGroup = (ViewGroup) current; + int numChildren = currentGroup.getChildCount(); + for(int i=0;i<numChildren;i++){ + viewStack.push(currentGroup.getChildAt(i)); + } + } + if (current instanceof TextView) { + processLegacyTextView((TextView) current); + } + } + } + + private void processLegacyTextView(TextView textView) { + if (textView.getText() instanceof Spanned) { + Spanned ss = (Spanned) textView.getText(); + Object[] spans = ss.getSpans(0, ss.length(), Object.class); + SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString()); + for (Object span : spans) { + Object resultSpan = span; + if (span instanceof TextAppearanceSpan) { + resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span); + } + builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span), + ss.getSpanFlags(span)); + } + textView.setText(builder); + } + } + + private TextAppearanceSpan processTextAppearanceSpan(TextAppearanceSpan span) { + ColorStateList colorStateList = span.getTextColor(); + if (colorStateList != null) { + int[] colors = colorStateList.getColors(); + boolean changed = false; + for (int i = 0; i < colors.length; i++) { + if (mImageUtils.isGrayscale(colors[i])) { + colors[i] = processColor(colors[i]); + changed = true; + } + } + if (changed) { + return new TextAppearanceSpan( + span.getFamily(), span.getTextStyle(), span.getTextSize(), + new ColorStateList(colorStateList.getStates(), colors), + span.getLinkTextColor()); + } + } + return span; + } + + private int processColor(int color) { + return Color.argb(Color.alpha(color), + 255 - Color.red(color), + 255 - Color.green(color), + 255 - Color.blue(color)); + } + private void startApplicationDetailsActivity(String packageName) { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", packageName, null)); @@ -748,9 +917,11 @@ public abstract class BaseStatusBar extends SystemUI implements View contentViewLocal = null; View bigContentViewLocal = null; try { - contentViewLocal = contentView.apply(mContext, expanded, mOnClickHandler); + contentViewLocal = contentView.apply(getInflationContext(sbn), expanded, + mOnClickHandler); if (bigContentView != null) { - bigContentViewLocal = bigContentView.apply(mContext, expanded, mOnClickHandler); + bigContentViewLocal = bigContentView.apply(getInflationContext(sbn), expanded, + mOnClickHandler); } } catch (RuntimeException e) { @@ -780,7 +951,7 @@ public abstract class BaseStatusBar extends SystemUI implements View publicViewLocal = null; if (publicNotification != null) { try { - publicViewLocal = publicNotification.contentView.apply(mContext, + publicViewLocal = publicNotification.contentView.apply(getInflationContext(sbn), expandedPublic, mOnClickHandler); if (publicViewLocal != null) { @@ -831,6 +1002,13 @@ public abstract class BaseStatusBar extends SystemUI implements row.setDrawingCacheEnabled(true); applyLegacyRowBackground(sbn, content); + processLegacyHoloNotification(sbn, contentViewLocal); + if (bigContentViewLocal != null) { + processLegacyHoloNotification(sbn, bigContentViewLocal); + } + if (publicViewLocal != null) { + processLegacyHoloNotification(sbn, publicViewLocal); + } if (MULTIUSER_DEBUG) { TextView debug = (TextView) row.findViewById(R.id.debug_info); @@ -1245,12 +1423,17 @@ public abstract class BaseStatusBar extends SystemUI implements : null; // Reapply the RemoteViews - contentView.reapply(mContext, entry.expanded, mOnClickHandler); + contentView.reapply(getInflationContext(notification), entry.expanded, mOnClickHandler); + processLegacyHoloNotification(notification, entry.expanded); if (bigContentView != null && entry.getBigContentView() != null) { - bigContentView.reapply(mContext, entry.getBigContentView(), mOnClickHandler); + bigContentView.reapply(getInflationContext(notification), entry.getBigContentView(), + mOnClickHandler); + processLegacyHoloNotification(notification, entry.getBigContentView()); } if (publicContentView != null && entry.getPublicContentView() != null) { - publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler); + publicContentView.reapply(getInflationContext(notification), + entry.getPublicContentView(), mOnClickHandler); + processLegacyHoloNotification(notification, entry.getPublicContentView()); } // update the contentIntent final PendingIntent contentIntent = notification.getNotification().contentIntent; @@ -1330,4 +1513,35 @@ public abstract class BaseStatusBar extends SystemUI implements } mContext.unregisterReceiver(mBroadcastReceiver); } + + /** + * A custom context theme wrapper that applies a platform theme to a created package context. + * This is useful if you want to inflate {@link RemoteViews} with a custom theme (normally, the + * theme used there is the default platform theme). + */ + private static class RemoteViewsThemeContextWrapper extends ContextThemeWrapper { + + private int mThemeRes; + + private RemoteViewsThemeContextWrapper(Context base, int themeres) { + super(base, themeres); + mThemeRes = themeres; + } + + @Override + public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) + throws NameNotFoundException { + Context c = super.createPackageContextAsUser(packageName, flags, user); + c.setTheme(mThemeRes); + return c; + } + + @Override + public Context createPackageContext(String packageName, int flags) + throws NameNotFoundException { + Context c = super.createPackageContext(packageName, flags); + c.setTheme(mThemeRes); + return c; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java index 48ee1ce46865..174cad8c324e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java @@ -996,8 +996,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mInversionState.toggled = enabled; mInversionState.type = type; // TODO: Add real icon assets. - mInversionState.iconId = enabled ? R.drawable.ic_qs_bluetooth_on - : R.drawable.ic_qs_bluetooth_off; + mInversionState.iconId = enabled ? R.drawable.ic_qs_inversion_on + : R.drawable.ic_qs_inversion_off; mInversionState.label = res.getString(R.string.quick_settings_inversion_label); mInversionCallback.refreshView(mInversionTile, mInversionState); } @@ -1026,8 +1026,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mContrastState.contrast = contrast; mContrastState.brightness = brightness; // TODO: Add real icon assets. - mContrastState.iconId = enabled ? R.drawable.ic_qs_bluetooth_on - : R.drawable.ic_qs_bluetooth_off; + mContrastState.iconId = enabled ? R.drawable.ic_qs_contrast_on + : R.drawable.ic_qs_contrast_off; mContrastState.label = res.getString(R.string.quick_settings_contrast_label); mContrastCallback.refreshView(mContrastTile, mContrastState); } @@ -1053,8 +1053,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mColorSpaceState.toggled = enabled; mColorSpaceState.type = type; // TODO: Add real icon assets. - mColorSpaceState.iconId = enabled ? R.drawable.ic_qs_bluetooth_on - : R.drawable.ic_qs_bluetooth_off; + mColorSpaceState.iconId = enabled ? R.drawable.ic_qs_color_space_on + : R.drawable.ic_qs_color_space_off; mColorSpaceState.label = res.getString(R.string.quick_settings_color_space_label); mColorSpaceCallback.refreshView(mColorSpaceTile, mColorSpaceState); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java index c4d2cce3b1b5..fa7f96a205e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java @@ -28,6 +28,8 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.PathShape; +import android.os.AsyncTask; +import android.os.Vibrator; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextPaint; @@ -45,7 +47,6 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.TextView; @@ -79,6 +80,7 @@ public class ZenModeView extends RelativeLayout { private final Rect mLayoutRect = new Rect(); private final UntilPager mUntilPager; private final AlarmWarning mAlarmWarning; + private final int mPopDuration; private float mDownY; private int mDownBottom; @@ -87,6 +89,7 @@ public class ZenModeView extends RelativeLayout { private int mBottom; private int mWidthSpec; private Adapter mAdapter; + private boolean mPopped; public ZenModeView(Context context) { this(context, null); @@ -144,7 +147,6 @@ public class ZenModeView extends RelativeLayout { lp.addRule(RelativeLayout.CENTER_HORIZONTAL); addView(mModeSpinner, lp); - mUntilPager = new UntilPager(mContext, mPathPaint, iconSize); mUntilPager.setId(android.R.id.tabhost); mUntilPager.setAlpha(0); @@ -165,6 +167,8 @@ public class ZenModeView extends RelativeLayout { mHintText.setGravity(Gravity.CENTER); mHintText.setTextColor(GRAY); addView(mHintText, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + + mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms); } private boolean isApplicable() { @@ -180,9 +184,11 @@ public class ZenModeView extends RelativeLayout { public void onAnimationUpdate(ValueAnimator animation) { final float f = animation.getAnimatedFraction(); final int hintBottom = mHintText.getBottom(); - setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max); - if (f == 1) { + final boolean isDone = f == 1; + setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max, isDone); + if (isDone) { mPeekable = true; + mPopped = false; mClosing = false; mModeSpinner.updateState(); if (mAdapter != null) { @@ -335,11 +341,15 @@ public class ZenModeView extends RelativeLayout { return true; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { final float dy = event.getY() - mDownY; - setPeeked(mDownBottom + (int)dy, getExpandedBottom()); + if (!mPopped) { + mPopped = true; + AsyncTask.execute(mPopVibration); + } + setPeeked(mDownBottom + (int)dy, getExpandedBottom(), false); } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { final float dy = event.getY() - mDownY; - setPeeked(mDownBottom + (int)dy, getExpandedBottom()); + setPeeked(mDownBottom + (int)dy, getExpandedBottom(), true); if (mPeekable) { close(); } @@ -347,14 +357,14 @@ public class ZenModeView extends RelativeLayout { return rt; } - private void setPeeked(int peeked, int max) { + private void setPeeked(int peeked, int max, boolean isDone) { if (DEBUG) log("setPeeked=" + peeked); final int min = mHintText.getBottom(); peeked = Math.max(min, Math.min(peeked, max)); - if (mBottom == peeked) { + if (!isDone && mBottom == peeked) { return; } - if (peeked == max) { + if (peeked == max && isDone) { mPeekable = false; mModeSpinner.setEnabled(true); if (mAdapter != null) { @@ -419,6 +429,14 @@ public class ZenModeView extends RelativeLayout { }).start(); } + private final Runnable mPopVibration = new Runnable() { + @Override + public void run() { + Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + v.vibrate(mPopDuration); + } + }; + private final class UntilPager extends RelativeLayout { private final ImageView mPrev; private final ImageView mNext; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index abc3fb1fcc21..17a0e60b2eb8 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -286,6 +286,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mUserRotation = Surface.ROTATION_0; boolean mAccelerometerDefault; + boolean mSupportAutoRotation; int mAllowAllRotations = -1; boolean mCarDockEnablesAccelerometer; boolean mDeskDockEnablesAccelerometer; @@ -372,6 +373,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpNavigationFrame = new Rect(); WindowState mTopFullscreenOpaqueWindowState; + boolean mHideWindowBehindKeyguard; boolean mTopIsFullscreen; boolean mForceStatusBar; boolean mForceStatusBarFromKeyguard; @@ -585,13 +587,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { * screen is switched off. */ boolean needSensorRunningLp() { - if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR - || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR - || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT - || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) { - // If the application has explicitly requested to follow the - // orientation, then we need to turn the sensor or. - return true; + if (mSupportAutoRotation) { + if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR + || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR + || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT + || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) { + // If the application has explicitly requested to follow the + // orientation, then we need to turn the sensor on. + return true; + } } if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) || (mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK @@ -612,7 +616,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // still be turned off when the screen is off.) return false; } - return true; + return mSupportAutoRotation; } /* @@ -877,6 +881,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); + mSupportAutoRotation = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_supportAutoRotation); mLidOpenRotation = readRotation( com.android.internal.R.integer.config_lidOpenRotation); mCarDockRotation = readRotation( @@ -3355,6 +3361,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) { mTopFullscreenOpaqueWindowState = null; + mHideWindowBehindKeyguard = false; mForceStatusBar = false; mForceStatusBarFromKeyguard = false; mForcingShowNavBar = false; @@ -3391,7 +3398,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attrs.type == TYPE_KEYGUARD) { mShowingLockscreen = true; } - boolean applyWindow = attrs.type >= FIRST_APPLICATION_WINDOW + boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW; if (attrs.type == TYPE_DREAM) { // If the lockscreen was showing when the dream started then wait @@ -3399,30 +3406,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mDreamingLockscreen || (win.isVisibleLw() && win.hasDrawnLw())) { mShowingDream = true; - applyWindow = true; + appWindow = true; } } - if (applyWindow - && attrs.x == 0 && attrs.y == 0 - && attrs.width == WindowManager.LayoutParams.MATCH_PARENT - && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) { - if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); - mTopFullscreenOpaqueWindowState = win; - if ((fl & FLAG_SHOW_WHEN_LOCKED) != 0) { - if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win); - mHideLockScreen = true; - mForceStatusBarFromKeyguard = false; - } - if ((fl & FLAG_DISMISS_KEYGUARD) != 0 - && mDismissKeyguard == DISMISS_KEYGUARD_NONE) { - if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win); - mDismissKeyguard = mWinDismissingKeyguard == win ? - DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; - mWinDismissingKeyguard = win; - mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure(); - } - if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { - mAllowLockscreenWhenOn = true; + + final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0; + if (appWindow) { + if (attrs.x == 0 && attrs.y == 0 + && attrs.width == WindowManager.LayoutParams.MATCH_PARENT + && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) { + if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); + mTopFullscreenOpaqueWindowState = win; + if (showWhenLocked && !mHideWindowBehindKeyguard) { + if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win); + mHideLockScreen = true; + mForceStatusBarFromKeyguard = false; + } + if ((fl & FLAG_DISMISS_KEYGUARD) != 0 + && mDismissKeyguard == DISMISS_KEYGUARD_NONE) { + if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win); + mDismissKeyguard = mWinDismissingKeyguard == win ? + DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; + mWinDismissingKeyguard = win; + mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure(); + } + if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { + mAllowLockscreenWhenOn = true; + } + } else if (!showWhenLocked) { + mHideWindowBehindKeyguard = true; } } } @@ -3509,7 +3521,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mKeyguard != null) { if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard=" + mHideLockScreen); - if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardDelegate.isSecure()) { + if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !isKeyguardSecure()) { if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG @@ -4481,6 +4493,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { // Application just wants to remain locked in the last rotation. preferredRotation = lastRotation; + } else if (!mSupportAutoRotation) { + // If we don't support auto-rotation then bail out here and ignore + // the sensor and any rotation lock settings. + preferredRotation = -1; } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED @@ -5297,6 +5313,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu); } + pw.print(prefix); pw.print("mSupportAutoRotation="); pw.println(mSupportAutoRotation); pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode); pw.print(" mDockMode="); pw.print(mDockMode); pw.print(" mCarDockRotation="); pw.print(mCarDockRotation); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 782868edf172..d91086156b9e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1074,6 +1074,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int PERSIST_URI_GRANTS_MSG = 38; static final int REQUEST_ALL_PSS_MSG = 39; static final int START_RELATED_USERS_MSG = 40; + static final int UPDATE_TIME = 41; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1693,6 +1694,21 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } + case UPDATE_TIME: { + synchronized (ActivityManagerService.this) { + for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { + ProcessRecord r = mLruProcesses.get(i); + if (r.thread != null) { + try { + r.thread.updateTimePrefs(msg.arg1 == 0 ? false : true); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to update preferences for: " + r.info.processName); + } + } + } + } + break; + } } } }; @@ -9212,8 +9228,13 @@ public final class ActivityManagerService extends ActivityManagerNative ActivityInfo ai = ris.get(i).activityInfo; ComponentName comp = new ComponentName(ai.packageName, ai.name); if (lastDoneReceivers.contains(comp)) { + // We already did the pre boot receiver for this app with the current + // platform version, so don't do it again... ris.remove(i); i--; + // ...however, do keep it as one that has been done, so we don't + // forget about it when rewriting the file of last done receivers. + doneReceivers.add(comp); } } @@ -13441,11 +13462,20 @@ public final class ActivityManagerService extends ActivityManagerNative * of all currently running processes. This message will get queued up before the broadcast * happens. */ - if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { + if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { mHandler.sendEmptyMessage(UPDATE_TIME_ZONE); } - if (intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) { + /* + * If the user set the time, let all running processes know. + */ + if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) { + final int is24Hour = intent.getBooleanExtra( + Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1 : 0; + mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0)); + } + + if (Intent.ACTION_CLEAR_DNS_CACHE.equals(intent.getAction())) { mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG); } diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 10ea67c34465..4c887dd8e9d1 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -37,11 +37,16 @@ final class CoreSettingsObserver extends ContentObserver { private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName(); // mapping form property name to its type - private static final Map<String, Class<?>> sCoreSettingToTypeMap = new HashMap< + private static final Map<String, Class<?>> sSecureSettingToTypeMap = new HashMap< + String, Class<?>>(); + private static final Map<String, Class<?>> sSystemSettingToTypeMap = new HashMap< String, Class<?>>(); static { - sCoreSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class); - // add other core settings here... + sSecureSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class); + // add other secure settings here... + + sSystemSettingToTypeMap.put(Settings.System.TIME_12_24, String.class); + // add other system settings here... } private final Bundle mCoreSettings = new Bundle(); @@ -67,39 +72,62 @@ final class CoreSettingsObserver extends ContentObserver { } private void sendCoreSettings() { - populateCoreSettings(mCoreSettings); + populateSettings(mCoreSettings, sSecureSettingToTypeMap); + populateSettings(mCoreSettings, sSystemSettingToTypeMap); mActivityManagerService.onCoreSettingsChange(mCoreSettings); } private void beginObserveCoreSettings() { - for (String setting : sCoreSettingToTypeMap.keySet()) { + for (String setting : sSecureSettingToTypeMap.keySet()) { Uri uri = Settings.Secure.getUriFor(setting); mActivityManagerService.mContext.getContentResolver().registerContentObserver( uri, false, this); } + + for (String setting : sSystemSettingToTypeMap.keySet()) { + Uri uri = Settings.System.getUriFor(setting); + mActivityManagerService.mContext.getContentResolver().registerContentObserver( + uri, false, this); + } } - private void populateCoreSettings(Bundle snapshot) { + private void populateSettings(Bundle snapshot, Map<String, Class<?>> map) { Context context = mActivityManagerService.mContext; - for (Map.Entry<String, Class<?>> entry : sCoreSettingToTypeMap.entrySet()) { + for (Map.Entry<String, Class<?>> entry : map.entrySet()) { String setting = entry.getKey(); Class<?> type = entry.getValue(); try { if (type == String.class) { - String value = Settings.Secure.getString(context.getContentResolver(), - setting); + final String value; + if (map == sSecureSettingToTypeMap) { + value = Settings.Secure.getString(context.getContentResolver(), setting); + } else { + value = Settings.System.getString(context.getContentResolver(), setting); + } snapshot.putString(setting, value); } else if (type == int.class) { - int value = Settings.Secure.getInt(context.getContentResolver(), - setting); + final int value; + if (map == sSecureSettingToTypeMap) { + value = Settings.Secure.getInt(context.getContentResolver(), setting); + } else { + value = Settings.System.getInt(context.getContentResolver(), setting); + } snapshot.putInt(setting, value); } else if (type == float.class) { - float value = Settings.Secure.getFloat(context.getContentResolver(), - setting); + final float value; + if (map == sSecureSettingToTypeMap) { + value = Settings.Secure.getFloat(context.getContentResolver(), setting); + } else { + value = Settings.System.getFloat(context.getContentResolver(), setting); + } snapshot.putFloat(setting, value); } else if (type == long.class) { - long value = Settings.Secure.getLong(context.getContentResolver(), - setting); + final long value; + if (map == sSecureSettingToTypeMap) { + value = Settings.Secure.getLong(context.getContentResolver(), setting); + } else { + value = Settings.System.getLong(context.getContentResolver(), setting); + } snapshot.putLong(setting, value); } } catch (SettingNotFoundException snfe) { |