diff options
-rw-r--r-- | core/java/android/widget/Toast.java | 72 | ||||
-rw-r--r-- | core/res/res/anim/toast_bar_enter.xml | 27 | ||||
-rw-r--r-- | core/res/res/anim/toast_bar_exit.xml | 26 | ||||
-rw-r--r-- | core/res/res/drawable-hdpi/toast_bar_bg.9.png | bin | 0 -> 599 bytes | |||
-rw-r--r-- | core/res/res/drawable-mdpi/toast_bar_bg.9.png | bin | 0 -> 374 bytes | |||
-rw-r--r-- | core/res/res/drawable-xhdpi/toast_bar_bg.9.png | bin | 0 -> 814 bytes | |||
-rw-r--r-- | core/res/res/layout/toast_bar.xml | 70 | ||||
-rw-r--r-- | core/res/res/values/styles.xml | 6 | ||||
-rw-r--r-- | core/res/res/values/symbols.xml | 3 | ||||
-rw-r--r-- | packages/SystemUI/res/values/strings.xml | 9 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java | 4 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java | 90 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java | 2 | ||||
-rw-r--r-- | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 1 | ||||
-rw-r--r-- | services/java/com/android/server/NotificationManagerService.java | 12 |
15 files changed, 312 insertions, 10 deletions
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 1d85126..aaa1adaa 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -29,6 +29,7 @@ import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -74,6 +75,9 @@ public class Toast { */ public static final int LENGTH_LONG = 1; + /** @hide */ + public static final int LENGTH_INFINITE = 2; + final Context mContext; final TN mTN; int mDuration; @@ -288,6 +292,61 @@ public class Toast { tv.setText(s); } + /** @hide */ + public static Toast makeBar(Context context, int resId, int duration) { + return makeBar(context, context.getResources().getText(resId), duration); + } + + /** @hide */ + public static Toast makeBar(Context context, CharSequence text, int duration) { + Toast result = new Toast(context); + + LayoutInflater inflate = (LayoutInflater) + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View v = inflate.inflate(com.android.internal.R.layout.toast_bar, null); + ((TextView)v.findViewById(android.R.id.message)).setText(text); + v.findViewById(android.R.id.button1).setVisibility(View.GONE); + + result.mNextView = v; + result.mDuration = duration; + result.mTN.mParams.alpha = 0.9f; + result.mTN.mParams.windowAnimations = com.android.internal.R.style.Animation_ToastBar; + + return result; + } + + /** @hide */ + public Toast setAction(int resId, Runnable action) { + return setAction(mContext.getResources().getText(resId), action); + } + + /** @hide */ + public Toast setAction(CharSequence actionText, final Runnable action) { + if (mNextView != null) { + TextView text1 = (TextView)mNextView.findViewById(android.R.id.text1); + View button1 = mNextView.findViewById(android.R.id.button1); + if (text1 != null && button1 != null) { + text1.setText(actionText); + button1.setVisibility(View.VISIBLE); + button1.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (action != null) { + action.run(); + } + }}); + return setInteractive(true); + } + } + throw new RuntimeException("This Toast was not created with Toast.makeBar()"); + } + + /** @hide */ + public Toast setInteractive(boolean interactive) { + mTN.setInteractive(interactive); + return this; + } + // ======================================================================================= // All the gunk below is the interaction with the Notification Service, which handles // the proper ordering of these system-wide. @@ -340,13 +399,20 @@ public class Toast { final WindowManager.LayoutParams params = mParams; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; - params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE - | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; params.format = PixelFormat.TRANSLUCENT; params.windowAnimations = com.android.internal.R.style.Animation_Toast; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.setTitle("Toast"); + setInteractive(false); + } + + private void setInteractive(boolean interactive) { + mParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | (interactive + ? (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH) + : WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); } /** diff --git a/core/res/res/anim/toast_bar_enter.xml b/core/res/res/anim/toast_bar_enter.xml new file mode 100644 index 0000000..5c0dfcf --- /dev/null +++ b/core/res/res/anim/toast_bar_enter.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + <translate android:fromYDelta="10%" android:toYDelta="0" + android:interpolator="@interpolator/decelerate_quint" + android:duration="@android:integer/config_shortAnimTime"/> + <alpha android:fromAlpha="0.5" android:toAlpha="1.0" + android:interpolator="@interpolator/decelerate_cubic" + android:duration="@android:integer/config_shortAnimTime" /> +</set> diff --git a/core/res/res/anim/toast_bar_exit.xml b/core/res/res/anim/toast_bar_exit.xml new file mode 100644 index 0000000..4e3b7da --- /dev/null +++ b/core/res/res/anim/toast_bar_exit.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + <translate android:fromYDelta="0" android:toYDelta="10%" + android:interpolator="@interpolator/accelerate_quint" + android:duration="@android:integer/config_shortAnimTime"/> + <alpha android:fromAlpha="1.0" android:toAlpha="0.0" + android:interpolator="@interpolator/accelerate_cubic" + android:duration="@android:integer/config_shortAnimTime"/> +</set> diff --git a/core/res/res/drawable-hdpi/toast_bar_bg.9.png b/core/res/res/drawable-hdpi/toast_bar_bg.9.png Binary files differnew file mode 100644 index 0000000..2396b26 --- /dev/null +++ b/core/res/res/drawable-hdpi/toast_bar_bg.9.png diff --git a/core/res/res/drawable-mdpi/toast_bar_bg.9.png b/core/res/res/drawable-mdpi/toast_bar_bg.9.png Binary files differnew file mode 100644 index 0000000..291a936 --- /dev/null +++ b/core/res/res/drawable-mdpi/toast_bar_bg.9.png diff --git a/core/res/res/drawable-xhdpi/toast_bar_bg.9.png b/core/res/res/drawable-xhdpi/toast_bar_bg.9.png Binary files differnew file mode 100644 index 0000000..1dc4927 --- /dev/null +++ b/core/res/res/drawable-xhdpi/toast_bar_bg.9.png diff --git a/core/res/res/layout/toast_bar.xml b/core/res/res/layout/toast_bar.xml new file mode 100644 index 0000000..b7443d5 --- /dev/null +++ b/core/res/res/layout/toast_bar.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2013 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:background="@drawable/toast_bar_bg" + android:layout_height="50dp" + android:layout_width="match_parent"> + + <TextView + android:id="@android:id/message" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:ellipsize="end" + android:gravity="center_vertical" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:singleLine="true" + android:textColor="@android:color/white" + android:textSize="16sp" /> + + <LinearLayout + android:id="@android:id/button1" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:clickable="true"> + + <View + android:layout_width="1dp" + android:layout_height="match_parent" + android:layout_marginBottom="10dp" + android:layout_marginRight="12dp" + android:layout_marginTop="10dp" + android:background="#aaaaaa" /> + + <TextView + android:id="@android:id/text1" + android:textSize="12sp" + android:textColor="#aaaaaa" + android:textStyle="bold" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:paddingLeft="8dp" + android:paddingRight="20dp" + android:textAllCaps="true" /> + </LinearLayout> + + </LinearLayout> + +</FrameLayout> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index f494d8c..bd82f35 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -138,6 +138,12 @@ please see styles_device_defaults.xml. <item name="windowExitAnimation">@anim/submenu_exit</item> </style> + <!-- {@hide} --> + <style name="Animation.ToastBar"> + <item name="windowEnterAnimation">@anim/toast_bar_enter</item> + <item name="windowExitAnimation">@anim/toast_bar_exit</item> + </style> + <style name="Animation.TypingFilter"> <item name="windowEnterAnimation">@anim/grow_fade_in_center</item> <item name="windowExitAnimation">@anim/shrink_fade_out_center</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9c2ab03..3718220 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -991,6 +991,7 @@ <java-symbol type="drawable" name="text_select_handle_left" /> <java-symbol type="drawable" name="text_select_handle_middle" /> <java-symbol type="drawable" name="text_select_handle_right" /> + <java-symbol type="drawable" name="toast_bar_bg" /> <java-symbol type="drawable" name="unknown_image" /> <java-symbol type="drawable" name="unlock_default" /> <java-symbol type="drawable" name="unlock_halo" /> @@ -1079,6 +1080,7 @@ <java-symbol type="layout" name="textview_hint" /> <java-symbol type="layout" name="time_picker" /> <java-symbol type="layout" name="time_picker_dialog" /> + <java-symbol type="layout" name="toast_bar" /> <java-symbol type="layout" name="transient_notification" /> <java-symbol type="layout" name="volume_adjust" /> <java-symbol type="layout" name="volume_adjust_item" /> @@ -1132,6 +1134,7 @@ <java-symbol type="style" name="Animation.DropDownUp" /> <java-symbol type="style" name="Animation.DropDownDown" /> <java-symbol type="style" name="Animation.PopupWindow" /> + <java-symbol type="style" name="Animation.ToastBar" /> <java-symbol type="style" name="Animation.TypingFilter" /> <java-symbol type="style" name="Animation.TypingFilterRestore" /> <java-symbol type="style" name="Animation.Dream" /> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index f3db062..d003a09 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -516,4 +516,13 @@ <string name="status_bar_help_title">Notifications appear here</string> <!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] --> <string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</string> + + <!-- Toast bar message when hiding the navigation bar on bottom --> + <string name="hideybar_confirmation_message_bottom">Swipe up from bottom of screen to reveal system bar</string> + + <!-- Shorter version of toast bar message when hiding the navigation bar on bottom --> + <string name="hideybar_confirmation_message_bottom_short">Swipe bottom of screen to reveal bar</string> + + <!-- Toast bar message when hiding the navigation bar on right --> + <string name="hideybar_confirmation_message_right">Swipe from right of screen to reveal system bar</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 54c4666..fd36da6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -382,6 +382,10 @@ public class NavigationBarView extends LinearLayout { mCurrentView = mRotatedViews[Surface.ROTATION_0]; } + public boolean isVertical() { + return mVertical; + } + public void reorient() { final int rot = mDisplay.getRotation(); for (int i=0; i<4; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index e8d4e1f..98b0930 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -61,6 +61,7 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; +import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewPropertyAnimator; @@ -75,6 +76,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; +import android.widget.Toast; import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.EventLogTags; @@ -309,6 +311,37 @@ public class PhoneStatusBar extends BaseStatusBar { } }; + private Toast mHideybarConfirmation; + private boolean mHideybarConfirmationDismissed; + + private final View.OnTouchListener mDismissHideybarConfirmationOnTouchOutside = + new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) { + dismissHideybarConfirmation(); + } + return false; + } + }; + + private final Runnable mHideybarConfirmationAction = new Runnable() { + @Override + public void run() { + if (mHideybarConfirmation != null) { + final boolean isGloballyConfirmed = Prefs.read(mContext) + .getBoolean(Prefs.HIDEYBAR_CONFIRMED, false); + if (!isGloballyConfirmed) { + // user pressed button, consider this a confirmation + Prefs.edit(mContext) + .putBoolean(Prefs.HIDEYBAR_CONFIRMED, true) + .apply(); + } + dismissHideybarConfirmation(); + } + } + }; + private boolean mAutohideSuspended; private final Runnable mAutohide = new Runnable() { @@ -322,6 +355,7 @@ public class PhoneStatusBar extends BaseStatusBar { public void start() { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); + mDisplay.getSize(mCurrentDisplaySize); mDreamManager = IDreamManager.Stub.asInterface( ServiceManager.checkService(DreamService.DREAM_SERVICE)); @@ -1855,7 +1889,11 @@ public class PhoneStatusBar extends BaseStatusBar { final int oldVal = mSystemUiVisibility; final int newVal = (oldVal&~mask) | (vis&mask); final int diff = newVal ^ oldVal; - + if (DEBUG) Slog.d(TAG, String.format( + "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", + Integer.toHexString(vis), Integer.toHexString(mask), + Integer.toHexString(oldVal), Integer.toHexString(newVal), + Integer.toHexString(diff))); if (diff != 0) { mSystemUiVisibility = newVal; @@ -1892,10 +1930,60 @@ public class PhoneStatusBar extends BaseStatusBar { cancelAutohide(); } } + if (mNavigationBarView != null) { + int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_OVERLAY; + boolean oldVisible = (oldVal & flags) == flags; + boolean newVisible = (newVal & flags) == flags; + if (!oldVisible && newVisible) { + mHideybarConfirmationDismissed = false; + } + setHideybarConfirmationVisible(newVisible); + } notifyUiVisibilityChanged(mSystemUiVisibility); } } + private void dismissHideybarConfirmation() { + if (mHideybarConfirmation != null) { + mHideybarConfirmationDismissed = true; + mHideybarConfirmation.cancel(); + mHideybarConfirmation = null; + } + } + + private void setHideybarConfirmationVisible(boolean visible) { + if (DEBUG) Slog.d(TAG, "setHideybarConfirmationVisible " + visible); + if (visible && mHideybarConfirmation == null && !mHideybarConfirmationDismissed) { + // create the confirmation toast bar with the correct message for this config + float widthDp = mCurrentDisplaySize.x / + (mDisplayMetrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT); + int msg = mNavigationBarView.isVertical() ? + R.string.hideybar_confirmation_message_right : + widthDp < 600 ? R.string.hideybar_confirmation_message_bottom_short : + R.string.hideybar_confirmation_message_bottom; + mHideybarConfirmation = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE) + .setAction(com.android.internal.R.string.ok, mHideybarConfirmationAction); + View v = mHideybarConfirmation.getView(); + boolean isGloballyConfirmed = Prefs.read(mContext) + .getBoolean(Prefs.HIDEYBAR_CONFIRMED, false); + if (isGloballyConfirmed) { + // dismiss on outside touch if globally confirmed + v.setOnTouchListener(mDismissHideybarConfirmationOnTouchOutside); + } + // position at the bottom like normal toasts, but use top gravity + // to avoid jumping around when showing/hiding the nav bar + v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + int offsetY = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.toast_y_offset); + mHideybarConfirmation.setGravity(Gravity.TOP, 0, + mCurrentDisplaySize.y - v.getMeasuredHeight() / 2 - offsetY); + // show the confirmation + mHideybarConfirmation.show(); + } else if (!visible) { + dismissHideybarConfirmation(); + } + } + @Override public void resumeAutohide() { if (mAutohideSuspended) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java index 5d2198e..a759bba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java @@ -29,6 +29,8 @@ public class Prefs { public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help"; public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help"; + public static final String HIDEYBAR_CONFIRMED = "hideybar_confirmed"; + public static SharedPreferences read(Context context) { return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE); } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 85121fe..dae195a 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1345,7 +1345,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (attrs.type) { case TYPE_SYSTEM_OVERLAY: case TYPE_SECURE_SYSTEM_OVERLAY: - case TYPE_TOAST: // These types of windows can't receive input events. attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 04773db..f4065ed 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -1476,7 +1476,7 @@ public class NotificationManagerService extends INotificationManager.Stub if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); try { record.callback.show(); - scheduleTimeoutLocked(record, false); + scheduleTimeoutLocked(record); return; } catch (RemoteException e) { Slog.w(TAG, "Object died trying to show notification " + record.callback @@ -1516,12 +1516,14 @@ public class NotificationManagerService extends INotificationManager.Stub } } - private void scheduleTimeoutLocked(ToastRecord r, boolean immediate) + private void scheduleTimeoutLocked(ToastRecord r) { - Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); - long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY); mHandler.removeCallbacksAndMessages(r); - mHandler.sendMessageDelayed(m, delay); + if (r.duration != Toast.LENGTH_INFINITE) { + Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r); + long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; + mHandler.sendMessageDelayed(m, delay); + } } private void handleTimeout(ToastRecord record) |