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
diff --git a/res/layout-watch/grant_permissions.xml b/res/layout-watch/grant_permissions.xml
index 2d56706..165de29 100644
--- a/res/layout-watch/grant_permissions.xml
+++ b/res/layout-watch/grant_permissions.xml
@@ -15,12 +15,9 @@
 -->
 <FrameLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        xmlns:tools="http://schemas.android.com/tools"
         android:id="@+id/confirmation"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        >
+        android:layout_height="match_parent">
 
     <ScrollView
             android:id="@+id/scrolling_container"
@@ -32,6 +29,7 @@
         <LinearLayout
                 android:id="@+id/content"
                 android:orientation="vertical"
+                android:paddingBottom="@dimen/conf_diag_button_container_height"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
@@ -62,60 +60,62 @@
                     android:gravity="center"
                     android:fontFamily="sans-serif-condensed-light"
                     android:textAppearance="@style/GrantPermissions.TitleText"/>
-
-            <!-- TODO: Change this to use a ViewStub instead of show/hiding the two layouts -->
-            <FrameLayout android:layout_width="match_parent"
-                         android:layout_height="wrap_content"
-                         android:id="@+id/button_bar_container"
-                         android:layout_gravity="bottom"
-                         android:background="#FF606060">
-                <FrameLayout
-                        android:id="@+id/horizontal_button_bar"
-                        android:layout_width="match_parent"
-                        android:layout_height="72dp">
-                    <Button
-                            android:id="@+id/horizontal_deny_button"
-                            android:layout_width="54dp"
-                            android:layout_height="54dp"
-                            android:layout_gravity="top|left"
-                            android:layout_marginLeft="16dp"
-                            android:layout_marginTop="9dp"
-                            android:background="@drawable/cancel_button"/>
-
-                    <Button
-                            android:id="@+id/horizontal_allow_button"
-                            android:layout_width="54dp"
-                            android:layout_height="54dp"
-                            android:layout_gravity="top|right"
-                            android:layout_marginRight="16dp"
-                            android:layout_marginTop="9dp"
-                            android:background="@drawable/confirm_button"/>
-                </FrameLayout>
-
-                <FrameLayout
-                        android:id="@+id/vertical_button_bar"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:visibility="gone">
-                    <LinearLayout
-                            android:id="@+id/buttonPanel"
-                            android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
-                            android:orientation="vertical">
-                        <Button
-                                android:id="@+id/vertical_allow_button"
-                                style="@style/Widget.WearDiag.Button"/>
-
-                        <Button
-                                android:id="@+id/vertical_deny_button"
-                                style="@style/Widget.WearDiag.Button"/>
-
-                        <Button
-                                android:id="@+id/vertical_deny_do_not_ask_again_button"
-                                style="@style/Widget.WearDiag.Button"/>
-                    </LinearLayout>
-                </FrameLayout>
-            </FrameLayout>
         </LinearLayout>
     </ScrollView>
-</FrameLayout>
\ No newline at end of file
+
+    <!-- TODO: Change this to use a ViewStub instead of show/hiding the two layouts -->
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:id="@+id/button_bar_container"
+                 android:layout_gravity="bottom"
+                 android:background="#FF606060">
+        <FrameLayout
+            android:id="@+id/horizontal_button_bar"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/conf_diag_button_container_height">
+            <Button
+                android:id="@+id/horizontal_deny_button"
+                android:layout_width="54dp"
+                android:layout_height="54dp"
+                android:layout_gravity="top|left"
+                android:layout_marginLeft="@dimen/conf_diag_2button_margin_side"
+                android:layout_marginTop="@dimen/conf_diag_2button_margin_top"
+                android:background="@drawable/cancel_button"/>
+
+            <Button
+                android:id="@+id/horizontal_allow_button"
+                android:layout_width="54dp"
+                android:layout_height="54dp"
+                android:layout_gravity="top|right"
+                android:layout_marginRight="@dimen/conf_diag_2button_margin_side"
+                android:layout_marginTop="@dimen/conf_diag_2button_margin_top"
+                android:background="@drawable/confirm_button"/>
+        </FrameLayout>
+
+        <FrameLayout
+            android:id="@+id/vertical_button_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/conf_diag_3button_margin_left"
+            android:layout_marginBottom="@dimen/conf_diag_3button_margin_bottom"
+            android:visibility="gone">
+            <LinearLayout
+                android:id="@+id/buttonPanel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+                <Button
+                    android:id="@+id/vertical_allow_button"
+                    style="@style/Widget.WearDiag.Button"/>
+
+                <Button
+                    android:id="@+id/vertical_deny_button"
+                    style="@style/Widget.WearDiag.Button"/>
+
+                <Button
+                    android:id="@+id/vertical_deny_do_not_ask_again_button"
+                    style="@style/Widget.WearDiag.Button"/>
+            </LinearLayout>
+        </FrameLayout>
+    </FrameLayout>
+</FrameLayout>
diff --git a/res/values-round/dimens.xml b/res/values-round/dimens.xml
new file mode 100644
index 0000000..c41886c
--- /dev/null
+++ b/res/values-round/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+    <!-- Dimensions for the Grant permissions Confirmation Dialog -->
+    <dimen name="conf_diag_button_container_height">96dp</dimen>
+    <dimen name="conf_diag_2button_margin_side">36dp</dimen>
+    <dimen name="conf_diag_2button_margin_top">12dp</dimen>
+    <dimen name="conf_diag_3button_margin_left">36dp</dimen>
+    <dimen name="conf_diag_3button_margin_bottom">12dp</dimen>
+
+</resources>
diff --git a/res/values-watch/colors.xml b/res/values-watch/colors.xml
index 903bfef..d662f25 100644
--- a/res/values-watch/colors.xml
+++ b/res/values-watch/colors.xml
@@ -26,4 +26,7 @@
 
     <!-- Copied from wearable support -->
     <color name="circular_button_disabled">#757575</color>
+
+    <!-- Copied from wearable Clockwork Settings -->
+    <color name="cw_dark_gray">#424242</color>
 </resources>
diff --git a/res/values-watch/dimens.xml b/res/values-watch/dimens.xml
index 29a65fd..9f484d3 100644
--- a/res/values-watch/dimens.xml
+++ b/res/values-watch/dimens.xml
@@ -22,7 +22,12 @@
 
     <dimen name="action_dialog_z">16dp</dimen>
 
-    <!-- Confirmation Dialog -->
+    <!-- Dimensions for the Grant permissions Confirmation Dialog -->
     <dimen name="conf_diag_floating_height">16dp</dimen>
+    <dimen name="conf_diag_button_container_height">72dp</dimen>
+    <dimen name="conf_diag_2button_margin_side">16dp</dimen>
+    <dimen name="conf_diag_2button_margin_top">9dp</dimen>
+    <dimen name="conf_diag_3button_margin_left">16dp</dimen>
+    <dimen name="conf_diag_3button_margin_bottom">9dp</dimen>
 
 </resources>
diff --git a/res/values-watch/themes.xml b/res/values-watch/themes.xml
index 7a27bf7..b392c5c 100644
--- a/res/values-watch/themes.xml
+++ b/res/values-watch/themes.xml
@@ -16,13 +16,14 @@
   -->
 
 <resources>
-    <style name="Settings" parent="Theme.Leanback">
+    <style name="Settings" parent="@android:style/Theme.DeviceDefault.NoActionBar">
         <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Permissions</item>
+        <item name="android:windowBackground">@color/cw_dark_gray</item>
+        <item name="android:colorBackground">@color/cw_dark_gray</item>
     </style>
 
-    <style name="GrantPermissions" parent="Theme.Leanback">
+    <style name="GrantPermissions" parent="Settings">
         <item name="android:windowIsFloating">true</item>
-        <item name="android:windowAnimationStyle">@style/Animation.Snackbar</item>
         <item name="android:windowElevation">@dimen/action_dialog_z</item>
     </style>
 
@@ -39,11 +40,6 @@
         <item name="android:lineSpacingMultiplier">1.221</item>
     </style>
 
-    <style name="Animation.Snackbar" parent="@android:style/Animation">
-        <item name="android:windowEnterAnimation">@anim/snackbar_enter</item>
-        <item name="android:windowExitAnimation">@anim/snackbar_exit</item>
-    </style>
-
     <!-- Copied from WearableSupport lib -->
     <style name="TextAppearance.WearDiag" parent="android:TextAppearance.Medium">
         <item name="android:textColor">#FFFFFF</item>
diff --git a/src/com/android/packageinstaller/DeviceUtils.java b/src/com/android/packageinstaller/DeviceUtils.java
new file mode 100644
index 0000000..8e2d57e
--- /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 d465ee0..a0f23d6 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.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 @@
     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 922f543..bb4dde7 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.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 @@
 
         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 @@
         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 ac573c4..a3d3b80 100644
--- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java
+++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java
@@ -15,14 +15,14 @@
  */
 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 8dacd03..1e58893 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.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 @@
             return;
         }
 
-        boolean isTelevision = Utils.isTelevision(context);
+        boolean isTelevision = DeviceUtils.isTelevision(context);
         PreferenceScreen screen = getPreferenceScreen();
 
         ArraySet<String> preferencesToRemove = new ArraySet<>();
diff --git a/src/com/android/packageinstaller/permission/ui/PermissionConfirmationViewHandler.java b/src/com/android/packageinstaller/permission/ui/PermissionConfirmationViewHandler.java
index 63ed0a4..3e32c7f 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 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 @@
 
     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 @@
         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 @@
         } else {
             mIcon.setVisibility(View.INVISIBLE);
         }
-
         mMessage.setText(getMessage());
 
         switch (getButtonBarMode()) {
@@ -127,6 +150,43 @@
         }
 
         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 @@
                 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 40058f6..35b6f1a 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.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 @@
     @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 7b58fed..976fee1 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.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 @@
             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 2940a72..7ff5c96 100644
--- a/src/com/android/packageinstaller/permission/utils/Utils.java
+++ b/src/com/android/packageinstaller/permission/utils/Utils.java
@@ -132,9 +132,4 @@
         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 e9ea21e..5ce0b9a 100644
--- a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
+++ b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java
@@ -45,6 +45,7 @@
 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 @@
 
     @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 bec697d..dc42075 100644
--- a/src/com/android/packageinstaller/wear/WearPackageUtil.java
+++ b/src/com/android/packageinstaller/wear/WearPackageUtil.java
@@ -147,8 +147,4 @@
         }
         return false;
     }
-
-    public static boolean isWear(final Context context) {
-        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
-    }
 }