From 03dc824d37099b29acb5a0aa28e881d5b05cce0e Mon Sep 17 00:00:00 2001 From: Vinod Krishnan Date: Thu, 10 Sep 2015 09:42:27 -0700 Subject: Changing layout to make button animations work - Fix the Permissions Dialogs for round layout - Show animation for the buttons - Also fixed the names ellipsis issue. - Fixed the theming of the dialogs. Bug: 23118402 Change-Id: I385c827ac41b06222334c36bfda2c70b346232a2 --- src/com/android/packageinstaller/DeviceUtils.java | 32 +++++ .../permission/model/AppPermissions.java | 9 +- .../permission/ui/GrantPermissionsActivity.java | 10 +- .../ui/GrantPermissionsWatchViewHandler.java | 4 +- .../permission/ui/PermissionAppsFragment.java | 3 +- .../ui/PermissionConfirmationViewHandler.java | 132 ++++++++++++++++++++- .../permission/ui/PermissionsFrameFragment.java | 3 +- .../permission/ui/SettingsWithHeader.java | 3 +- .../packageinstaller/permission/utils/Utils.java | 5 - .../wear/WearPackageInstallerService.java | 3 +- .../packageinstaller/wear/WearPackageUtil.java | 4 - 11 files changed, 182 insertions(+), 26 deletions(-) create mode 100644 src/com/android/packageinstaller/DeviceUtils.java (limited to 'src/com/android/packageinstaller') diff --git a/src/com/android/packageinstaller/DeviceUtils.java b/src/com/android/packageinstaller/DeviceUtils.java new file mode 100644 index 00000000..8e2d57ea --- /dev/null +++ b/src/com/android/packageinstaller/DeviceUtils.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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.packageinstaller; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Configuration; + +public class DeviceUtils { + public static boolean isTelevision(Context context) { + int uiMode = context.getResources().getConfiguration().uiMode; + return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION; + } + + public static boolean isWear(final Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); + } +} diff --git a/src/com/android/packageinstaller/permission/model/AppPermissions.java b/src/com/android/packageinstaller/permission/model/AppPermissions.java index d465ee09..a0f23d64 100644 --- a/src/com/android/packageinstaller/permission/model/AppPermissions.java +++ b/src/com/android/packageinstaller/permission/model/AppPermissions.java @@ -23,6 +23,8 @@ import android.text.BidiFormatter; import android.text.TextPaint; import android.text.TextUtils; +import com.android.packageinstaller.DeviceUtils; + import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -165,9 +167,12 @@ public final class AppPermissions { private static CharSequence loadEllipsizedAppLabel(Context context, PackageInfo packageInfo) { String label = packageInfo.applicationInfo.loadLabel( context.getPackageManager()).toString(); - String noNewLineLabel = label.replace("\n", " "); - String ellipsizedLabel = TextUtils.ellipsize(noNewLineLabel, sAppLabelEllipsizePaint, + String ellipsizedLabel = label.replace("\n", " "); + if (!DeviceUtils.isWear(context)) { + // Only ellipsize for non-Wear devices. + ellipsizedLabel = TextUtils.ellipsize(ellipsizedLabel, sAppLabelEllipsizePaint, MAX_APP_LABEL_LENGTH_PIXELS, TextUtils.TruncateAt.END).toString(); + } return BidiFormatter.getInstance().unicodeWrap(ellipsizedLabel); } } diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java index 922f5430..bb4dde7e 100644 --- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java +++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java @@ -38,6 +38,7 @@ import android.view.View; import android.view.Window; import android.view.WindowManager; +import com.android.packageinstaller.DeviceUtils; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.model.AppPermissionGroup; import com.android.packageinstaller.permission.model.AppPermissions; @@ -71,9 +72,9 @@ public class GrantPermissionsActivity extends OverlayTouchActivity setTitle(R.string.permission_request_title); - if (Utils.isTelevision(this)) { + if (DeviceUtils.isTelevision(this)) { mViewHandler = new GrantPermissionsTvViewHandler(this).setResultListener(this); - } else if (isWatch()) { + } else if (DeviceUtils.isWear(this)) { mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this); } else { mViewHandler = new GrantPermissionsDefaultViewHandler(this).setResultListener(this); @@ -361,11 +362,6 @@ public class GrantPermissionsActivity extends OverlayTouchActivity SafetyNetLogger.logPermissionsRequested(mAppPermissions.getPackageInfo(), groups); } - private boolean isWatch() { - PackageManager pm = getPackageManager(); - return pm.hasSystemFeature(pm.FEATURE_WATCH); - } - private static final class GroupState { static final int STATE_UNKNOWN = 0; static final int STATE_ALLOWED = 1; diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java index ac573c43..a3d3b805 100644 --- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java +++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java @@ -15,14 +15,14 @@ import com.android.packageinstaller.R; */ final class GrantPermissionsWatchViewHandler extends PermissionConfirmationViewHandler implements GrantPermissionsViewHandler { - private static final String TAG = "GrantPermissionsViewH"; + private static final String TAG = "GrantPermsWatchViewH"; private static final String ARG_GROUP_NAME = "ARG_GROUP_NAME"; private final Context mContext; private ResultListener mResultListener; - + private String mGroupName; private boolean mShowDoNotAsk; diff --git a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java index 8dacd037..1e588939 100644 --- a/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java +++ b/src/com/android/packageinstaller/permission/ui/PermissionAppsFragment.java @@ -39,6 +39,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.android.packageinstaller.DeviceUtils; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.model.AppPermissionGroup; import com.android.packageinstaller.permission.model.PermissionApps; @@ -185,7 +186,7 @@ public final class PermissionAppsFragment extends PermissionsFrameFragment imple return; } - boolean isTelevision = Utils.isTelevision(context); + boolean isTelevision = DeviceUtils.isTelevision(context); PreferenceScreen screen = getPreferenceScreen(); ArraySet preferencesToRemove = new ArraySet<>(); diff --git a/src/com/android/packageinstaller/permission/ui/PermissionConfirmationViewHandler.java b/src/com/android/packageinstaller/permission/ui/PermissionConfirmationViewHandler.java index 63ed0a45..3e32c7f2 100644 --- a/src/com/android/packageinstaller/permission/ui/PermissionConfirmationViewHandler.java +++ b/src/com/android/packageinstaller/permission/ui/PermissionConfirmationViewHandler.java @@ -1,12 +1,18 @@ package com.android.packageinstaller.permission.ui; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.drawable.Icon; import android.os.Handler; +import android.os.Message; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.Button; import android.widget.ImageView; import android.widget.ScrollView; @@ -15,10 +21,15 @@ import android.widget.TextView; import com.android.packageinstaller.R; public abstract class PermissionConfirmationViewHandler implements - View.OnClickListener { + Handler.Callback, + View.OnClickListener, + ViewTreeObserver.OnScrollChangedListener { public static final int MODE_HORIZONTAL_BUTTONS = 0; public static final int MODE_VERTICAL_BUTTONS = 1; + private static final int MSG_HIDE_BUTTON_BAR = 1001; + private static final long HIDE_ANIM_DURATION = 500; + private View mRoot; private TextView mCurrentPageText; private ImageView mIcon; @@ -34,6 +45,13 @@ public abstract class PermissionConfirmationViewHandler implements private Context mContext; + private Handler mHideHandler; + private Interpolator mInterpolator; + private float mButtonBarFloatingHeight; + private ObjectAnimator mButtonBarAnimator; + private float mCurrentTranslation; + private boolean mHiddenBefore; + // TODO: Move these into a builder public abstract void onAllow(); public abstract void onDeny(); @@ -74,6 +92,12 @@ public abstract class PermissionConfirmationViewHandler implements mVerticalDeny.setOnClickListener(this); mVerticalDenyDoNotAskAgain.setOnClickListener(this); + mInterpolator = AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.fast_out_slow_in); + mButtonBarFloatingHeight = mContext.getResources().getDimension( + R.dimen.conf_diag_floating_height); + mHideHandler = new Handler(this); + return mRoot; } @@ -102,7 +126,6 @@ public abstract class PermissionConfirmationViewHandler implements } else { mIcon.setVisibility(View.INVISIBLE); } - mMessage.setText(getMessage()); switch (getButtonBarMode()) { @@ -127,6 +150,43 @@ public abstract class PermissionConfirmationViewHandler implements } mScrollingContainer.scrollTo(0, 0); + + mScrollingContainer.getViewTreeObserver().addOnScrollChangedListener(this); + + mRoot.getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + // Setup Button animation. + // pop the button bar back to full height, stop all animation + if (mButtonBarAnimator != null) { + mButtonBarAnimator.cancel(); + } + + // In order to fake the buttons peeking at the bottom, need to do set the + // padding properly. + if (mContent.getPaddingBottom() != mButtonBarContainer.getHeight()) { + mContent.setPadding(0, 0, 0, mButtonBarContainer.getHeight()); + } + + // stop any calls to hide the button bar in the future + mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR); + mHiddenBefore = false; + + // determine which mode the scrolling should work at. + if (mContent.getHeight() > mScrollingContainer.getHeight()) { + mButtonBarContainer.setTranslationZ(mButtonBarFloatingHeight); + mHideHandler.sendEmptyMessageDelayed(MSG_HIDE_BUTTON_BAR, 3000); + generateButtonBarAnimator(mButtonBarContainer.getHeight(), 0, 0, + mButtonBarFloatingHeight, 1000); + } else { + mButtonBarContainer.setTranslationY(0); + mButtonBarContainer.setTranslationZ(0); + } + mRoot.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + } @Override @@ -146,4 +206,72 @@ public abstract class PermissionConfirmationViewHandler implements break; } } + + @Override + public boolean handleMessage (Message msg) { + switch (msg.what) { + case MSG_HIDE_BUTTON_BAR: + hideButtonBar(); + return true; + } + return false; + } + + @Override + public void onScrollChanged() { + mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR); + hideButtonBar(); + } + + private void hideButtonBar() { + // get the offset to the top of the button bar + int offset = mScrollingContainer.getHeight() + mButtonBarContainer.getHeight() - + mContent.getHeight() + Math.max(mScrollingContainer.getScrollY(), 0); + int translationY = offset > 0 ? mButtonBarContainer.getHeight() - offset : + mButtonBarContainer.getHeight(); + + if (!mHiddenBefore || mButtonBarAnimator == null) { + // hasn't hidden the bar yet, just hide now to the right height + generateButtonBarAnimator( + mButtonBarContainer.getTranslationY(), translationY, + mButtonBarFloatingHeight, 0, HIDE_ANIM_DURATION); + } else if (mButtonBarAnimator.isRunning()) { + // we are animating the button bar closing, change to animate to the right place + if (Math.abs(mCurrentTranslation - translationY) > 1e-2f) { + mButtonBarAnimator.cancel(); // stop current animation + + if (Math.abs(mButtonBarContainer.getTranslationY() - translationY) > 1e-2f) { + long duration = Math.max((long) ( + (float) HIDE_ANIM_DURATION + * (translationY - mButtonBarContainer.getTranslationY()) + / mButtonBarContainer.getHeight()), 0); + generateButtonBarAnimator( + mButtonBarContainer.getTranslationY(), translationY, + mButtonBarFloatingHeight, 0, duration); + } else { + mButtonBarContainer.setTranslationY(translationY); + mButtonBarContainer.setTranslationZ(0); + } + } + } else { + // not currently animating, have already hidden, snap to the right offset + mButtonBarContainer.setTranslationY(translationY); + mButtonBarContainer.setTranslationZ(0); + } + + mHiddenBefore = true; + } + + private void generateButtonBarAnimator( + float startY, float endY, float startZ, float endZ, long duration) { + mButtonBarAnimator = + ObjectAnimator.ofPropertyValuesHolder( + mButtonBarContainer, + PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, startY, endY), + PropertyValuesHolder.ofFloat(View.TRANSLATION_Z, startZ, endZ)); + mCurrentTranslation = endY; + mButtonBarAnimator.setDuration(duration); + mButtonBarAnimator.setInterpolator(mInterpolator); + mButtonBarAnimator.start(); + } } diff --git a/src/com/android/packageinstaller/permission/ui/PermissionsFrameFragment.java b/src/com/android/packageinstaller/permission/ui/PermissionsFrameFragment.java index 40058f6d..35b6f1af 100644 --- a/src/com/android/packageinstaller/permission/ui/PermissionsFrameFragment.java +++ b/src/com/android/packageinstaller/permission/ui/PermissionsFrameFragment.java @@ -15,6 +15,7 @@ import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.widget.TextView; +import com.android.packageinstaller.DeviceUtils; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.utils.Utils; @@ -117,7 +118,7 @@ public abstract class PermissionsFrameFragment extends PreferenceFragment { @Override public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { - if (Utils.isTelevision(getContext())) { + if (DeviceUtils.isTelevision(getContext())) { mGridView = (VerticalGridView) inflater.inflate( R.layout.leanback_preferences_list, parent, false); mGridView.setWindowAlignmentOffset(0); diff --git a/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java b/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java index 7b58fed1..976fee11 100644 --- a/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java +++ b/src/com/android/packageinstaller/permission/ui/SettingsWithHeader.java @@ -26,6 +26,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.android.packageinstaller.DeviceUtils; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.utils.Utils; @@ -42,7 +43,7 @@ public abstract class SettingsWithHeader extends PermissionsFrameFragment Bundle savedInstanceState) { ViewGroup root = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState); - if (!Utils.isTelevision(getContext())) { + if (!DeviceUtils.isTelevision(getContext())) { mHeader = inflater.inflate(R.layout.header, root, false); getPreferencesContainer().addView(mHeader, 0); updateHeader(); diff --git a/src/com/android/packageinstaller/permission/utils/Utils.java b/src/com/android/packageinstaller/permission/utils/Utils.java index 2940a729..7ff5c965 100644 --- a/src/com/android/packageinstaller/permission/utils/Utils.java +++ b/src/com/android/packageinstaller/permission/utils/Utils.java @@ -132,9 +132,4 @@ public class Utils { return info.isSystemApp() && (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0 && !launcherPkgs.contains(info.packageName); } - - public static boolean isTelevision(Context context) { - int uiMode = context.getResources().getConfiguration().uiMode; - return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION; - } } diff --git a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java index e9ea21e1..5ce0b9a1 100644 --- a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java +++ b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java @@ -45,6 +45,7 @@ import android.os.Process; import android.text.TextUtils; import android.util.Log; +import com.android.packageinstaller.DeviceUtils; import com.android.packageinstaller.PackageUtil; import java.io.ByteArrayOutputStream; @@ -172,7 +173,7 @@ public class WearPackageInstallerService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (!WearPackageUtil.isWear(this)) { + if (!DeviceUtils.isWear(this)) { Log.w(TAG, "Not running on wearable"); return START_NOT_STICKY; } diff --git a/src/com/android/packageinstaller/wear/WearPackageUtil.java b/src/com/android/packageinstaller/wear/WearPackageUtil.java index bec697d9..dc420757 100644 --- a/src/com/android/packageinstaller/wear/WearPackageUtil.java +++ b/src/com/android/packageinstaller/wear/WearPackageUtil.java @@ -147,8 +147,4 @@ public class WearPackageUtil { } return false; } - - public static boolean isWear(final Context context) { - return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); - } } -- cgit v1.2.3