diff options
author | Michael Kwan <mkwan@google.com> | 2016-10-07 15:51:41 -0700 |
---|---|---|
committer | Michael Kwan <mkwan@google.com> | 2016-10-11 14:11:18 -0700 |
commit | a5d853c3bd4e4e84872fc802decd18e9c18408d2 (patch) | |
tree | f00b7ee65175479e9a4f1ee80a8658074da65560 /src | |
parent | 718db932c2ea1ce5b94f1c613adabc898312f789 (diff) | |
download | android_packages_apps_PackageInstaller-a5d853c3bd4e4e84872fc802decd18e9c18408d2.tar.gz android_packages_apps_PackageInstaller-a5d853c3bd4e4e84872fc802decd18e9c18408d2.tar.bz2 android_packages_apps_PackageInstaller-a5d853c3bd4e4e84872fc802decd18e9c18408d2.zip |
Update permissions UI to match new watch UI.
Bug: 29250733
Bug: 31779188
Change-Id: I814db5f94bdb840b04c5e8d9e12b565cfcd5fbc1
Diffstat (limited to 'src')
12 files changed, 618 insertions, 1560 deletions
diff --git a/src/android/support/wearable/view/AcceptDenyDialog.java b/src/android/support/wearable/view/AcceptDenyDialog.java new file mode 100644 index 00000000..8ccccd5d --- /dev/null +++ b/src/android/support/wearable/view/AcceptDenyDialog.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2016 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.support.wearable.view; + +import android.annotation.TargetApi; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.StyleRes; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.Space; +import android.widget.TextView; + +import com.android.packageinstaller.R; + +/** + * A dialog to display a title, a message, and/or an icon with a positive and a negative button. + * + * <p>The buttons are hidden away unless there is a listener attached to the button. Since there's + * no click listener attached by default, the buttons are hidden be default. + */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +public class AcceptDenyDialog extends Dialog implements View.OnClickListener { + /** Icon at the top of the dialog. */ + protected ImageView mIcon; + /** Title at the top of the dialog. */ + protected TextView mTitle; + /** Message content of the dialog. */ + protected TextView mMessage; + /** Panel containing the buttons. */ + protected View mButtonPanel; + /** Positive button in the button panel. */ + protected ImageButton mPositiveButton; + /** Negative button in the button panel. */ + protected ImageButton mNegativeButton; + /** + * Click listener for the positive button. Positive button should hide if this is <code>null + * </code>. + */ + protected DialogInterface.OnClickListener mPositiveButtonListener; + /** + * Click listener for the negative button. Negative button should hide if this is <code>null + * </code>. + */ + protected DialogInterface.OnClickListener mNegativeButtonListener; + /** Spacer between the positive and negative button. Hidden if one button is hidden. */ + protected View mSpacer; + + public AcceptDenyDialog(Context context) { + this(context, 0 /* use default context theme */); + } + + public AcceptDenyDialog(Context context, @StyleRes int themeResId) { + super(context, themeResId); + + setContentView(R.layout.accept_deny_dialog); + + mTitle = (TextView) findViewById(android.R.id.title); + mMessage = (TextView) findViewById(android.R.id.message); + mIcon = (ImageView) findViewById(android.R.id.icon); + mPositiveButton = (ImageButton) findViewById(android.R.id.button1); + mPositiveButton.setOnClickListener(this); + mNegativeButton = (ImageButton) findViewById(android.R.id.button2); + mNegativeButton.setOnClickListener(this); + mSpacer = (Space) findViewById(R.id.spacer); + mButtonPanel = findViewById(R.id.buttonPanel); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case android.R.id.button1: + if (mPositiveButtonListener != null) { + mPositiveButtonListener.onClick(this, DialogInterface.BUTTON_POSITIVE); + } + dismiss(); + break; + case android.R.id.button2: + if (mNegativeButtonListener != null) { + mNegativeButtonListener.onClick(this, DialogInterface.BUTTON_NEGATIVE); + } + dismiss(); + break; + } + } + + public ImageButton getButton(int whichButton) { + switch (whichButton) { + case DialogInterface.BUTTON_POSITIVE: + return mPositiveButton; + case DialogInterface.BUTTON_NEGATIVE: + return mNegativeButton; + default: + return null; + } + } + + public void setIcon(Drawable icon) { + mIcon.setVisibility(icon == null ? View.GONE : View.VISIBLE); + mIcon.setImageDrawable(icon); + } + + /** + * @param resId the resourceId of the drawable to use as the icon or 0 if you don't want an icon. + */ + public void setIcon(int resId) { + mIcon.setVisibility(resId == 0 ? View.GONE : View.VISIBLE); + mIcon.setImageResource(resId); + } + + /** @param message the content message text of the dialog. */ + public void setMessage(CharSequence message) { + mMessage.setText(message); + mMessage.setVisibility(message == null ? View.GONE : View.VISIBLE); + } + + /** @param title the title text of the dialog. */ + @Override + public void setTitle(CharSequence title) { + mTitle.setText(title); + } + + /** + * Sets a click listener for a button. + * + * <p>Will hide button bar if all buttons are hidden (i.e. their click listeners are <code>null + * </code>). + * + * @param whichButton {@link DialogInterface.BUTTON_POSITIVE} or {@link + * DialogInterface.BUTTON_NEGATIVE} + * @param listener the listener to set for the button. Hide button if <code>null</code>. + */ + public void setButton(int whichButton, DialogInterface.OnClickListener listener) { + switch (whichButton) { + case DialogInterface.BUTTON_POSITIVE: + mPositiveButtonListener = listener; + break; + case DialogInterface.BUTTON_NEGATIVE: + mNegativeButtonListener = listener; + break; + default: + return; + } + + mSpacer.setVisibility(mPositiveButtonListener == null || mNegativeButtonListener == null + ? View.GONE : View.INVISIBLE); + mPositiveButton.setVisibility( + mPositiveButtonListener == null ? View.GONE : View.VISIBLE); + mNegativeButton.setVisibility( + mNegativeButtonListener == null ? View.GONE : View.VISIBLE); + mButtonPanel.setVisibility( + mPositiveButtonListener == null && mNegativeButtonListener == null + ? View.GONE : View.VISIBLE); + } + + /** + * Convenience method for <code>setButton(DialogInterface.BUTTON_POSITIVE, listener)</code>. + * + * @param listener the listener for the positive button. + */ + public void setPositiveButton(DialogInterface.OnClickListener listener) { + setButton(DialogInterface.BUTTON_POSITIVE, listener); + } + + /** + * Convenience method for <code>setButton(DialogInterface.BUTTON_NEGATIVE, listener)</code>. + * + * @param listener the listener for the positive button. + */ + public void setNegativeButton(DialogInterface.OnClickListener listener) { + setButton(DialogInterface.BUTTON_NEGATIVE, listener); + } +} diff --git a/src/android/support/wearable/view/WearableDialogHelper.java b/src/android/support/wearable/view/WearableDialogHelper.java new file mode 100644 index 00000000..0bdc1cc9 --- /dev/null +++ b/src/android/support/wearable/view/WearableDialogHelper.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2016 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.support.wearable.view; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.support.annotation.DrawableRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.util.Log; +import android.widget.Button; + +/** + * Helper to add icons to AlertDialog buttons.AlertDialog buttons. + */ +public class WearableDialogHelper { + private static final String TAG = "WearableDialogHelper"; + + private int mPositiveIconId; + private Drawable mPositiveIcon; + + private int mNeutralIconId; + private Drawable mNeutralIcon; + + private int mNegativeIconId; + private Drawable mNegativeIcon; + + @VisibleForTesting /* package */ Resources mResources; + @VisibleForTesting /* package */ Resources.Theme mTheme; + + /** + * Convenience constructor, equivalent to {@code new WearableDialogHelper(context.getResources(), + * context.getTheme())}. + */ + public WearableDialogHelper(@NonNull Context context) { + this(context.getResources(), context.getTheme()); + } + + /** + * @param resources the Resources used to obtain Drawables from resource IDs. + * @param theme the Theme used to properly obtain Drawables from resource IDs. + */ + public WearableDialogHelper(@NonNull Resources resources, @NonNull Resources.Theme theme) { + mResources = resources; + mTheme = theme; + } + + @Nullable + public Drawable getPositiveIcon() { + return resolveDrawable(mPositiveIcon, mPositiveIconId); + } + + @Nullable + public Drawable getNegativeIcon() { + return resolveDrawable(mNegativeIcon, mNegativeIconId); + } + + @Nullable + public Drawable getNeutralIcon() { + return resolveDrawable(mNeutralIcon, mNeutralIconId); + } + + @NonNull + public WearableDialogHelper setPositiveIcon(@DrawableRes int resId) { + mPositiveIconId = resId; + mPositiveIcon = null; + return this; + } + + @NonNull + public WearableDialogHelper setPositiveIcon(@Nullable Drawable icon) { + mPositiveIcon = icon; + mPositiveIconId = 0; + return this; + } + + @NonNull + public WearableDialogHelper setNegativeIcon(@DrawableRes int resId) { + mNegativeIconId = resId; + mNegativeIcon = null; + return this; + } + + @NonNull + public WearableDialogHelper setNegativeIcon(@Nullable Drawable icon) { + mNegativeIcon = icon; + mNegativeIconId = 0; + return this; + } + + @NonNull + public WearableDialogHelper setNeutralIcon(@DrawableRes int resId) { + mNeutralIconId = resId; + mNeutralIcon = null; + return this; + } + + @NonNull + public WearableDialogHelper setNeutralIcon(@Nullable Drawable icon) { + mNeutralIcon = icon; + mNeutralIconId = 0; + return this; + } + + /** + * Applies the button icons setup in the helper to the buttons in the dialog. + * + * <p>Note that this should be called after {@code AlertDialog.create()}, NOT {@code + * AlertDialog.Builder.create()}. Calling {@code AlertDialog.Builder.show()} would also accomplish + * the same thing. + * + * @param dialog the AlertDialog to style with the helper. + */ + public void apply(@NonNull AlertDialog dialog) { + applyButton(dialog.getButton(DialogInterface.BUTTON_POSITIVE), getPositiveIcon()); + applyButton(dialog.getButton(DialogInterface.BUTTON_NEGATIVE), getNegativeIcon()); + applyButton(dialog.getButton(DialogInterface.BUTTON_NEUTRAL), getNeutralIcon()); + } + + /** Applies the specified drawable to the button. */ + @VisibleForTesting + /* package */ void applyButton(@Nullable Button button, @Nullable Drawable drawable) { + if (button != null) { + button.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null); + button.setAllCaps(false); + } else if (drawable != null) { + Log.w(TAG, "non-null drawable used with missing button, did you call AlertDialog.create()?"); + } + } + + /** Obtain a drawable between a drawable and a resource ID. */ + @VisibleForTesting + /* package */ Drawable resolveDrawable(@Nullable Drawable drawable, @DrawableRes int resId) { + return drawable == null && resId != 0 ? mResources.getDrawable(resId, mTheme) : drawable; + } + + /** Convenience builder to generate an AlertDialog with icons in buttons. */ + public static class DialogBuilder extends AlertDialog.Builder { + private final WearableDialogHelper mHelper; + + public DialogBuilder(Context context) { + super(context); + mHelper = new WearableDialogHelper(context.getResources(), context.getTheme()); + } + + public DialogBuilder(Context context, int themeResId) { + super(context, themeResId); + mHelper = new WearableDialogHelper(context.getResources(), context.getTheme()); + } + + public WearableDialogHelper getHelper() { + return mHelper; + } + + public DialogBuilder setPositiveIcon(@DrawableRes int iconId) { + mHelper.setPositiveIcon(iconId); + return this; + } + + public DialogBuilder setPositiveIcon(@Nullable Drawable icon) { + mHelper.setPositiveIcon(icon); + return this; + } + + public DialogBuilder setNegativeIcon(@DrawableRes int iconId) { + mHelper.setNegativeIcon(iconId); + return this; + } + + public DialogBuilder setNegativeIcon(@Nullable Drawable icon) { + mHelper.setNegativeIcon(icon); + return this; + } + + public DialogBuilder setNeutralIcon(@DrawableRes int iconId) { + mHelper.setNeutralIcon(iconId); + return this; + } + + public DialogBuilder setNeutralIcon(@Nullable Drawable icon) { + mHelper.setNeutralIcon(icon); + return this; + } + + @Override + public AlertDialog create() { + final AlertDialog dialog = super.create(); + dialog.create(); + mHelper.apply(dialog); + return dialog; + } + + @Override + public AlertDialog show() { + final AlertDialog dialog = this.create(); + dialog.show(); + return dialog; + } + } +} diff --git a/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java index 21042f00..b50b5d83 100644 --- a/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java +++ b/src/com/android/packageinstaller/permission/ui/GrantPermissionsWatchViewHandler.java @@ -1,30 +1,51 @@ package com.android.packageinstaller.permission.ui; +import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; -import android.graphics.PixelFormat; +import android.content.DialogInterface; +import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; import android.os.Bundle; +import android.support.wearable.view.AcceptDenyDialog; +import android.support.wearable.view.WearableDialogHelper; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ImageSpan; +import android.text.style.TextAppearanceSpan; +import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; +import android.widget.Space; import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.ui.wear.ConfirmationViewHandler; /** * Watch-specific view handler for the grant permissions activity. */ -final class GrantPermissionsWatchViewHandler extends ConfirmationViewHandler - implements GrantPermissionsViewHandler { +final class GrantPermissionsWatchViewHandler implements GrantPermissionsViewHandler, + DialogInterface.OnClickListener { private static final String TAG = "GrantPermsWatchViewH"; - private static final String ARG_GROUP_NAME = "ARG_GROUP_NAME"; + private static final String WATCH_HANDLER_BUNDLE = "watch_handler_bundle"; + private static final String DIALOG_BUNDLE = "dialog_bundle"; + private static final String GROUP_NAME = "group_name"; + private static final String SHOW_DO_NOT_ASK = "show_do_not_ask"; + private static final String ICON = "icon"; + private static final String MESSAGE = "message"; + private static final String CURRENT_PAGE_TEXT = "current_page_text"; private final Context mContext; - + private ResultListener mResultListener; - + + private Dialog mDialog; + private String mGroupName; private boolean mShowDoNotAsk; @@ -33,7 +54,6 @@ final class GrantPermissionsWatchViewHandler extends ConfirmationViewHandler private Icon mIcon; GrantPermissionsWatchViewHandler(Context context) { - super(context); mContext = context; } @@ -45,13 +65,8 @@ final class GrantPermissionsWatchViewHandler extends ConfirmationViewHandler @Override public View createView() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "createView()"); - } - - mShowDoNotAsk = false; - - return super.createView(); + showDialog(null); + return new Space(mContext); } @Override @@ -79,96 +94,121 @@ final class GrantPermissionsWatchViewHandler extends ConfirmationViewHandler mShowDoNotAsk = showDoNotAsk; mMessage = message; mIcon = icon; - mCurrentPageText = (groupCount > 1 ? - mContext.getString(R.string.current_permission_template, groupIndex + 1, groupCount) - : null); + mCurrentPageText = groupCount > 1 + ? mContext.getString(R.string.current_permission_template, + groupIndex + 1, groupCount) + : null; + showDialog(null); + } + + private void showDialog(Bundle savedInstanceState) { + TypedArray a = mContext.obtainStyledAttributes( + new int[] { android.R.attr.textColorPrimary }); + int color = a.getColor(0, mContext.getColor(android.R.color.white)); + a.recycle(); + Drawable drawable = mIcon == null ? null : mIcon.setTint(color).loadDrawable(mContext); + + SpannableStringBuilder ssb = new SpannableStringBuilder(); + if (!TextUtils.isEmpty(mCurrentPageText)) { + ssb.append(mCurrentPageText, new TextAppearanceSpan(mContext, R.style.BreadcrumbText), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append('\n'); + } + if (!TextUtils.isEmpty(mMessage)) { + ssb.append(mMessage, new TextAppearanceSpan(mContext, R.style.TitleText), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } - invalidate(); + if (mShowDoNotAsk) { + if (mDialog instanceof AlertDialog) { + AlertDialog alertDialog = (AlertDialog) mDialog; + alertDialog.setTitle(ssb); + alertDialog.setIcon(drawable); + } else { + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + mDialog = new WearableDialogHelper.DialogBuilder(mContext) + .setPositiveIcon(R.drawable.confirm_button) + .setNeutralIcon(R.drawable.cancel_button) + .setNegativeIcon(R.drawable.deny_button) + .setTitle(ssb) + .setIcon(drawable) + .setPositiveButton(R.string.grant_dialog_button_allow, this) + .setNeutralButton(R.string.grant_dialog_button_deny, this) + .setNegativeButton(R.string.grant_dialog_button_deny_dont_ask_again, this) + .show(); + mDialog.setCancelable(false); + } + } else { + if (mDialog instanceof AcceptDenyDialog) { + AcceptDenyDialog acceptDenyDialog = (AcceptDenyDialog) mDialog; + acceptDenyDialog.setTitle(ssb); + acceptDenyDialog.setIcon(drawable); + } else { + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + + AcceptDenyDialog acceptDenyDialog = new AcceptDenyDialog(mContext); + acceptDenyDialog.setTitle(ssb); + acceptDenyDialog.setIcon(drawable); + acceptDenyDialog.setPositiveButton(this); + acceptDenyDialog.setNegativeButton(this); + acceptDenyDialog.show(); + mDialog = acceptDenyDialog; + mDialog.setCancelable(false); + } + } + + if (savedInstanceState != null) { + mDialog.onRestoreInstanceState(savedInstanceState); + } } @Override public void saveInstanceState(Bundle outState) { - outState.putString(ARG_GROUP_NAME, mGroupName); + Bundle b = new Bundle(); + b.putByte(SHOW_DO_NOT_ASK, (byte) (mShowDoNotAsk ? 1 : 0)); + b.putString(GROUP_NAME, mGroupName); + b.putBundle(DIALOG_BUNDLE, mDialog.onSaveInstanceState()); + + outState.putBundle(WATCH_HANDLER_BUNDLE, b); } @Override public void loadInstanceState(Bundle savedInstanceState) { - mGroupName = savedInstanceState.getString(ARG_GROUP_NAME); + Bundle b = savedInstanceState.getBundle(WATCH_HANDLER_BUNDLE); + mShowDoNotAsk = b.getByte(SHOW_DO_NOT_ASK) == 1; + mGroupName = b.getString(GROUP_NAME); + showDialog(b.getBundle(DIALOG_BUNDLE)); } @Override public void onBackPressed() { - if (mResultListener != null) { - mResultListener.onPermissionGrantResult(mGroupName, false, false); - } + notifyListener(false, false); } - @Override // ConfirmationViewHandler - public void onButton1() { - onClick(true /* granted */, false /* doNotAskAgain */); - } - - @Override // ConfirmationViewHandler - public void onButton2() { - onClick(false /* granted */, false /* doNotAskAgain */); - } - - @Override // ConfirmationViewHandler - public void onButton3() { - onClick(false /* granted */, true /* doNotAskAgain */); - } - - @Override // ConfirmationViewHandler - public CharSequence getCurrentPageText() { - return mCurrentPageText; - } - - @Override // ConfirmationViewHandler - public Icon getPermissionIcon() { - return mIcon; - } - - @Override // ConfirmationViewHandler - public CharSequence getMessage() { - return mMessage; - } - - @Override // ConfirmationViewHandler - public int getButtonBarMode() { - return mShowDoNotAsk ? MODE_VERTICAL_BUTTONS : MODE_HORIZONTAL_BUTTONS; - } - - @Override // ConfirmationViewHandler - public CharSequence getVerticalButton1Text() { - return mContext.getString(R.string.grant_dialog_button_allow); - } - - @Override // ConfirmationViewHandler - public CharSequence getVerticalButton2Text() { - return mContext.getString(R.string.grant_dialog_button_deny); - } - - @Override // ConfirmationViewHandler - public CharSequence getVerticalButton3Text() { - return mContext.getString(R.string.grant_dialog_button_deny_dont_ask_again); - } - - @Override // ConfirmationViewHandler - public Drawable getVerticalButton1Icon(){ - return mContext.getDrawable(R.drawable.confirm_button); - } - - @Override // ConfirmationViewHandler - public Drawable getVerticalButton2Icon(){ - return mContext.getDrawable(R.drawable.cancel_button); - } - - @Override // ConfirmationViewHandler - public Drawable getVerticalButton3Icon(){ - return mContext.getDrawable(R.drawable.deny_button); + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + notifyListener(true, false); + break; + case DialogInterface.BUTTON_NEUTRAL: + notifyListener(false, false); + break; + case DialogInterface.BUTTON_NEGATIVE: + notifyListener(false, + /* In AlertDialog, the negative button is also a don't ask again button. */ + dialog instanceof AlertDialog); + break; + } } - private void onClick(boolean granted, boolean doNotAskAgain) { + private void notifyListener(boolean granted, boolean doNotAskAgain) { if (mResultListener != null) { mResultListener.onPermissionGrantResult(mGroupName, granted, doNotAskAgain); } diff --git a/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java b/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java index db1c94d8..9e821067 100644 --- a/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java +++ b/src/com/android/packageinstaller/permission/ui/wear/AppPermissionsFragmentWear.java @@ -23,7 +23,10 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Bundle; -import android.support.wearable.view.WearableListView; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.preference.SwitchPreference; +import android.support.wearable.view.WearableDialogHelper; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -33,8 +36,6 @@ import android.widget.Toast; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.model.AppPermissionGroup; import com.android.packageinstaller.permission.model.AppPermissions; -import com.android.packageinstaller.permission.ui.wear.settings.PermissionsSettingsAdapter; -import com.android.packageinstaller.permission.ui.wear.settings.SettingsAdapter; import com.android.packageinstaller.permission.utils.LocationUtils; import com.android.packageinstaller.permission.utils.SafetyNetLogger; import com.android.packageinstaller.permission.utils.Utils; @@ -42,16 +43,10 @@ import com.android.packageinstaller.permission.utils.Utils; import java.util.ArrayList; import java.util.List; -public final class AppPermissionsFragmentWear extends TitledSettingsFragment { +public final class AppPermissionsFragmentWear extends PreferenceFragment { + private static final String LOG_TAG = "AppPermFragWear"; - private static final String LOG_TAG = "ManagePermsFragment"; - - private static final int WARNING_CONFIRMATION_REQUEST = 252; - private List<AppPermissionGroup> mToggledGroups; - private AppPermissions mAppPermissions; - private PermissionsSettingsAdapter mAdapter; - - private boolean mHasConfirmedRevoke; + private static final String KEY_NO_PERMISSIONS = "no_permissions"; public static AppPermissionsFragmentWear newInstance(String packageName) { return setPackageName(new AppPermissionsFragmentWear(), packageName); @@ -64,6 +59,11 @@ public final class AppPermissionsFragmentWear extends TitledSettingsFragment { return fragment; } + private List<AppPermissionGroup> mToggledGroups; + private AppPermissions mAppPermissions; + + private boolean mHasConfirmedRevoke; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -86,172 +86,117 @@ public final class AppPermissionsFragmentWear extends TitledSettingsFragment { return; } - mAppPermissions = new AppPermissions(activity, packageInfo, null, true, new Runnable() { - @Override - public void run() { - getActivity().finish(); - } - }); - - mAdapter = new PermissionsSettingsAdapter(getContext()); + mAppPermissions = new AppPermissions( + activity, packageInfo, null, true, () -> getActivity().finish()); + addPreferencesFromResource(R.xml.watch_permissions); initializePermissionGroupList(); } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.settings, container, false); - } - - @Override public void onResume() { super.onResume(); mAppPermissions.refresh(); // Also refresh the UI - final int count = mAdapter.getItemCount(); - for (int i = 0; i < count; ++i) { - updatePermissionGroupSetting(i); + for (final AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { + Preference pref = findPreference(group.getName()); + if (pref instanceof SwitchPreference) { + ((SwitchPreference) pref).setChecked(group.areRuntimePermissionsGranted()); + } } } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - if (mAppPermissions != null) { - initializeLayout(mAdapter); - mHeader.setText(R.string.app_permissions); - mDetails.setText(R.string.no_permissions); - if (mAdapter.getItemCount() == 0) { - mDetails.setVisibility(View.VISIBLE); - mWheel.setVisibility(View.GONE); - } else { - mDetails.setVisibility(View.GONE); - mWheel.setVisibility(View.VISIBLE); - } - } + public void onPause() { + super.onPause(); + logAndClearToggledGroups(); } private void initializePermissionGroupList() { final String packageName = mAppPermissions.getPackageInfo().packageName; List<AppPermissionGroup> groups = mAppPermissions.getPermissionGroups(); - List<SettingsAdapter.Setting<AppPermissionGroup>> nonSystemGroups = new ArrayList<>(); + List<SwitchPreference> nonSystemGroups = new ArrayList<>(); + + if (!groups.isEmpty()) { + getPreferenceScreen().removePreference(findPreference(KEY_NO_PERMISSIONS)); + } - final int count = groups.size(); - for (int i = 0; i < count; ++i) { - final AppPermissionGroup group = groups.get(i); + for (final AppPermissionGroup group : groups) { if (!Utils.shouldShowPermission(group, packageName)) { continue; } boolean isPlatform = group.getDeclaringPackage().equals(Utils.OS_PKG); - SettingsAdapter.Setting<AppPermissionGroup> setting = - new SettingsAdapter.Setting<AppPermissionGroup>( - group.getLabel(), - getPermissionGroupIcon(group), - i); - setting.data = group; + final SwitchPreference pref = new SwitchPreference(getContext()); + pref.setKey(group.getName()); + pref.setTitle(group.getLabel()); + pref.setChecked(group.areRuntimePermissionsGranted()); + + if (group.isPolicyFixed()) { + pref.setEnabled(false); + } else { + pref.setOnPreferenceChangeListener((p, newVal) -> { + if (LocationUtils.isLocationGroupAndProvider( + group.getName(), group.getApp().packageName)) { + LocationUtils.showLocationDialog( + getContext(), mAppPermissions.getAppLabel()); + return false; + } + + if ((Boolean) newVal) { + setPermission(group, pref, true); + } else { + final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); + if (grantedByDefault + || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) { + new WearableDialogHelper.DialogBuilder(getContext()) + .setNegativeIcon(R.drawable.confirm_button) + .setPositiveIcon(R.drawable.cancel_button) + .setNegativeButton(R.string.grant_dialog_button_deny_anyway, + (dialog, which) -> { + setPermission(group, pref, false); + if (!group.hasGrantedByDefaultPermission()) { + mHasConfirmedRevoke = true; + } + }) + .setPositiveButton(R.string.cancel, (dialog, which) -> {}) + .setMessage(grantedByDefault ? + R.string.system_warning : R.string.old_sdk_deny_warning) + .show(); + return false; + } else { + setPermission(group, pref, false); + } + } + + return true; + }); + } // The UI shows System settings first, then non-system settings if (isPlatform) { - mAdapter.addSetting(setting); + getPreferenceScreen().addPreference(pref); } else { - nonSystemGroups.add(setting); + nonSystemGroups.add(pref); } } // Now add the non-system settings to the end of the list - final int nonSystemCount = nonSystemGroups.size(); - for (int i = 0; i < nonSystemCount; ++i) { - final SettingsAdapter.Setting<AppPermissionGroup> setting = nonSystemGroups.get(i); - mAdapter.addSetting(setting); + for (SwitchPreference nonSystemGroup : nonSystemGroups) { + getPreferenceScreen().addPreference(nonSystemGroup); } } - @Override - public void onPause() { - super.onPause(); - logAndClearToggledGroups(); - } - - @Override - public void onClick(WearableListView.ViewHolder view) { - final int index = view.getPosition(); - SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index); - final AppPermissionGroup group = setting.data; - - if (group == null) { - Log.e(LOG_TAG, "Error: AppPermissionGroup is null"); - return; - } - - // The way WearableListView is designed, there is no way to avoid this click handler - // Since the policy is fixed, ignore the click as the user is not able to change the state - // of this permission group - if (group.isPolicyFixed()) { - return; - } - - addToggledGroup(group); - - if (LocationUtils.isLocationGroupAndProvider(group.getName(), group.getApp().packageName)) { - LocationUtils.showLocationDialog(getContext(), mAppPermissions.getAppLabel()); - return; - } - - if (!group.areRuntimePermissionsGranted()) { + private void setPermission(AppPermissionGroup group, SwitchPreference pref, boolean grant) { + if (grant) { group.grantRuntimePermissions(false); } else { - final boolean grantedByDefault = group.hasGrantedByDefaultPermission(); - if (grantedByDefault || (!group.hasRuntimePermission() && !mHasConfirmedRevoke)) { - Intent intent = new Intent(getActivity(), WarningConfirmationActivity.class); - intent.putExtra(WarningConfirmationActivity.EXTRA_WARNING_MESSAGE, - getString(grantedByDefault ? - R.string.system_warning : R.string.old_sdk_deny_warning)); - intent.putExtra(WarningConfirmationActivity.EXTRA_INDEX, index); - startActivityForResult(intent, WARNING_CONFIRMATION_REQUEST); - } else { - group.revokeRuntimePermissions(false); - } - } - - updatePermissionGroupSetting(index); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == WARNING_CONFIRMATION_REQUEST) { - if (resultCode == Activity.RESULT_OK) { - int index = data.getIntExtra(WarningConfirmationActivity.EXTRA_INDEX, -1); - if (index == -1) { - Log.e(LOG_TAG, "Warning confirmation request came back with no index."); - return; - } - - SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index); - final AppPermissionGroup group = setting.data; - group.revokeRuntimePermissions(false); - if (!group.hasGrantedByDefaultPermission()) { - mHasConfirmedRevoke = true; - } - - updatePermissionGroupSetting(index); - } - } else { - super.onActivityResult(requestCode, resultCode, data); + group.revokeRuntimePermissions(false); } - } - - private void updatePermissionGroupSetting(int index) { - SettingsAdapter.Setting<AppPermissionGroup> setting = mAdapter.get(index); - AppPermissionGroup group = setting.data; - mAdapter.updateSetting( - index, - group.getLabel(), - getPermissionGroupIcon(group), - group); + addToggledGroup(group); + pref.setChecked(grant); } private void addToggledGroup(AppPermissionGroup group) { @@ -273,54 +218,4 @@ public final class AppPermissionsFragmentWear extends TitledSettingsFragment { mToggledGroups = null; } } - - private int getPermissionGroupIcon(AppPermissionGroup group) { - String groupName = group.getName(); - boolean isEnabled = group.areRuntimePermissionsGranted(); - int resId; - - switch (groupName) { - case Manifest.permission_group.CALENDAR: - resId = isEnabled ? R.drawable.ic_permission_calendar - : R.drawable.ic_permission_calendardisable; - break; - case Manifest.permission_group.CAMERA: - resId = isEnabled ? R.drawable.ic_permission_camera - : R.drawable.ic_permission_cameradisable; - break; - case Manifest.permission_group.CONTACTS: - resId = isEnabled ? R.drawable.ic_permission_contact - : R.drawable.ic_permission_contactdisable; - break; - case Manifest.permission_group.LOCATION: - resId = isEnabled ? R.drawable.ic_permission_location - : R.drawable.ic_permission_locationdisable; - break; - case Manifest.permission_group.MICROPHONE: - resId = isEnabled ? R.drawable.ic_permission_mic - : R.drawable.ic_permission_micdisable; - break; - case Manifest.permission_group.PHONE: - resId = isEnabled ? R.drawable.ic_permission_call - : R.drawable.ic_permission_calldisable; - break; - case Manifest.permission_group.SENSORS: - resId = isEnabled ? R.drawable.ic_permission_sensor - : R.drawable.ic_permission_sensordisable; - break; - case Manifest.permission_group.SMS: - resId = isEnabled ? R.drawable.ic_permission_sms - : R.drawable.ic_permission_smsdisable; - break; - case Manifest.permission_group.STORAGE: - resId = isEnabled ? R.drawable.ic_permission_storage - : R.drawable.ic_permission_storagedisable; - break; - default: - resId = isEnabled ? R.drawable.ic_permission_shield - : R.drawable.ic_permission_shielddisable; - } - - return resId; - } } diff --git a/src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java b/src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java deleted file mode 100644 index b063ad55..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/ConfirmationViewHandler.java +++ /dev/null @@ -1,384 +0,0 @@ -package com.android.packageinstaller.permission.ui.wear; - -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.text.TextUtils; -import android.util.Log; -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; -import android.widget.TextView; - -import com.android.packageinstaller.R; - -public abstract class ConfirmationViewHandler implements - Handler.Callback, - View.OnClickListener, - ViewTreeObserver.OnScrollChangedListener, - ViewTreeObserver.OnGlobalLayoutListener { - private static final String TAG = "ConfirmationViewHandler"; - - public static final int MODE_HORIZONTAL_BUTTONS = 0; - public static final int MODE_VERTICAL_BUTTONS = 1; - - private static final int MSG_SHOW_BUTTON_BAR = 1001; - private static final int MSG_HIDE_BUTTON_BAR = 1002; - private static final long HIDE_ANIM_DURATION = 500; - - private View mRoot; - private TextView mCurrentPageText; - private ImageView mIcon; - private TextView mMessage; - private ScrollView mScrollingContainer; - private ViewGroup mContent; - private ViewGroup mHorizontalButtonBar; - private ViewGroup mVerticalButtonBar; - private Button mVerticalButton1; - private Button mVerticalButton2; - private Button mVerticalButton3; - private View mButtonBarContainer; - - 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 - /** In the 2 button layout, this is allow button */ - public abstract void onButton1(); - /** In the 2 button layout, this is deny button */ - public abstract void onButton2(); - public abstract void onButton3(); - public abstract CharSequence getVerticalButton1Text(); - public abstract CharSequence getVerticalButton2Text(); - public abstract CharSequence getVerticalButton3Text(); - public abstract Drawable getVerticalButton1Icon(); - public abstract Drawable getVerticalButton2Icon(); - public abstract Drawable getVerticalButton3Icon(); - public abstract CharSequence getCurrentPageText(); - public abstract Icon getPermissionIcon(); - public abstract CharSequence getMessage(); - - public ConfirmationViewHandler(Context context) { - mContext = context; - } - - public View createView() { - mRoot = LayoutInflater.from(mContext).inflate(R.layout.confirmation_dialog, null); - - mMessage = (TextView) mRoot.findViewById(R.id.message); - mCurrentPageText = (TextView) mRoot.findViewById(R.id.current_page_text); - mIcon = (ImageView) mRoot.findViewById(R.id.icon); - mButtonBarContainer = mRoot.findViewById(R.id.button_bar_container); - mContent = (ViewGroup) mRoot.findViewById(R.id.content); - mScrollingContainer = (ScrollView) mRoot.findViewById(R.id.scrolling_container); - mHorizontalButtonBar = (ViewGroup) mRoot.findViewById(R.id.horizontal_button_bar); - mVerticalButtonBar = (ViewGroup) mRoot.findViewById(R.id.vertical_button_bar); - - Button horizontalAllow = (Button) mRoot.findViewById(R.id.permission_allow_button); - Button horizontalDeny = (Button) mRoot.findViewById(R.id.permission_deny_button); - horizontalAllow.setOnClickListener(this); - horizontalDeny.setOnClickListener(this); - - mVerticalButton1 = (Button) mRoot.findViewById(R.id.vertical_button1); - mVerticalButton2 = (Button) mRoot.findViewById(R.id.vertical_button2); - mVerticalButton3 = (Button) mRoot.findViewById(R.id.vertical_button3); - mVerticalButton1.setOnClickListener(this); - mVerticalButton2.setOnClickListener(this); - mVerticalButton3.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(Looper.getMainLooper(), this); - - mScrollingContainer.getViewTreeObserver().addOnScrollChangedListener(this); - mRoot.getViewTreeObserver().addOnGlobalLayoutListener(this); - - return mRoot; - } - - /** - * Child class should override this for other modes. Call invalidate() to update the UI to the - * new button mode. - * @return The current mode the layout should use for the buttons - */ - public int getButtonBarMode() { - return MODE_HORIZONTAL_BUTTONS; - } - - public void invalidate() { - CharSequence currentPageText = getCurrentPageText(); - if (!TextUtils.isEmpty(currentPageText)) { - mCurrentPageText.setText(currentPageText); - mCurrentPageText.setVisibility(View.VISIBLE); - } else { - mCurrentPageText.setVisibility(View.GONE); - } - - Icon icon = getPermissionIcon(); - if (icon != null) { - mIcon.setImageIcon(icon); - mIcon.setVisibility(View.VISIBLE); - } else { - mIcon.setVisibility(View.GONE); - } - - CharSequence messageString = getMessage(); - mMessage.setText(messageString); - mRoot.announceForAccessibility(messageString); - - switch (getButtonBarMode()) { - case MODE_HORIZONTAL_BUTTONS: - mHorizontalButtonBar.setVisibility(View.VISIBLE); - mVerticalButtonBar.setVisibility(View.GONE); - break; - case MODE_VERTICAL_BUTTONS: - mHorizontalButtonBar.setVisibility(View.GONE); - mVerticalButtonBar.setVisibility(View.VISIBLE); - - mVerticalButton1.setText(getVerticalButton1Text()); - mVerticalButton2.setText(getVerticalButton2Text()); - - mVerticalButton1.setCompoundDrawablesWithIntrinsicBounds( - getVerticalButton1Icon(), null, null, null); - mVerticalButton2.setCompoundDrawablesWithIntrinsicBounds( - getVerticalButton2Icon(), null, null, null); - - CharSequence verticalButton3Text = getVerticalButton3Text(); - if (TextUtils.isEmpty(verticalButton3Text)) { - mVerticalButton3.setVisibility(View.GONE); - } else { - mVerticalButton3.setText(getVerticalButton3Text()); - mVerticalButton3.setCompoundDrawablesWithIntrinsicBounds( - getVerticalButton3Icon(), null, null, null); - } - break; - } - - mScrollingContainer.scrollTo(0, 0); - - mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR); - mHideHandler.removeMessages(MSG_SHOW_BUTTON_BAR); - } - - @Override - public void onGlobalLayout() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "onGlobalLayout"); - Log.d(TAG, " contentHeight: " + mContent.getHeight()); - } - - 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(mContent.getPaddingLeft(), mContent.getPaddingTop(), - mContent.getPaddingRight(), mButtonBarContainer.getHeight()); - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, " set mContent.PaddingBottom: " + mButtonBarContainer.getHeight()); - } - } - - mButtonBarContainer.setTranslationY(mButtonBarContainer.getHeight()); - - // Give everything a chance to render - mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR); - mHideHandler.removeMessages(MSG_SHOW_BUTTON_BAR); - mHideHandler.sendEmptyMessageDelayed(MSG_SHOW_BUTTON_BAR, 50); - } - - @Override - public void onClick(View v) { - int id = v.getId(); - switch (id) { - case R.id.permission_allow_button: - case R.id.vertical_button1: - onButton1(); - break; - case R.id.permission_deny_button: - case R.id.vertical_button2: - onButton2(); - break; - case R.id.vertical_button3: - onButton3(); - break; - } - } - - @Override - public boolean handleMessage (Message msg) { - switch (msg.what) { - case MSG_SHOW_BUTTON_BAR: - showButtonBar(); - return true; - case MSG_HIDE_BUTTON_BAR: - hideButtonBar(); - return true; - } - return false; - } - - @Override - public void onScrollChanged () { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "onScrollChanged"); - } - mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR); - hideButtonBar(); - } - - private void showButtonBar() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "showButtonBar"); - } - - // Setup Button animation. - // pop the button bar back to full height, stop all animation - if (mButtonBarAnimator != null) { - mButtonBarAnimator.cancel(); - } - - // stop any calls to hide the button bar in the future - mHideHandler.removeMessages(MSG_HIDE_BUTTON_BAR); - mHiddenBefore = false; - - // Evaluate the max height the button bar can go - final int screenHeight = mRoot.getHeight(); - final int halfScreenHeight = screenHeight / 2; - final int buttonBarHeight = mButtonBarContainer.getHeight(); - final int contentHeight = mContent.getHeight() - buttonBarHeight; - final int buttonBarMaxHeight = - Math.min(buttonBarHeight, halfScreenHeight); - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, " screenHeight: " + screenHeight); - Log.d(TAG, " contentHeight: " + contentHeight); - Log.d(TAG, " buttonBarHeight: " + buttonBarHeight); - Log.d(TAG, " buttonBarMaxHeight: " + buttonBarMaxHeight); - } - - mButtonBarContainer.setTranslationZ(mButtonBarFloatingHeight); - - // Only hide the button bar if it is occluding the content or the button bar is bigger than - // half the screen - if (contentHeight > (screenHeight - buttonBarHeight) - || buttonBarHeight > halfScreenHeight) { - mHideHandler.sendEmptyMessageDelayed(MSG_HIDE_BUTTON_BAR, 3000); - } - - generateButtonBarAnimator(buttonBarHeight, - buttonBarHeight - buttonBarMaxHeight, 0, mButtonBarFloatingHeight, 1000); - } - - private void hideButtonBar() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "hideButtonBar"); - } - - // The desired margin space between the button bar and the bottom of the dialog text - final int topMargin = mContext.getResources().getDimensionPixelSize( - R.dimen.conf_diag_button_container_top_margin); - final int contentHeight = mContent.getHeight() + topMargin; - final int screenHeight = mRoot.getHeight(); - final int buttonBarHeight = mButtonBarContainer.getHeight(); - - final int offset = screenHeight + buttonBarHeight - - contentHeight + Math.max(mScrollingContainer.getScrollY(), 0); - final int translationY = (offset > 0 ? - mButtonBarContainer.getHeight() - offset : mButtonBarContainer.getHeight()); - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, " topMargin: " + topMargin); - Log.d(TAG, " contentHeight: " + contentHeight); - Log.d(TAG, " screenHeight: " + screenHeight); - Log.d(TAG, " offset: " + offset); - Log.d(TAG, " buttonBarHeight: " + buttonBarHeight); - Log.d(TAG, " mContent.getPaddingBottom(): " + mContent.getPaddingBottom()); - Log.d(TAG, " mScrollingContainer.getScrollY(): " + mScrollingContainer.getScrollY()); - Log.d(TAG, " translationY: " + translationY); - } - - if (!mHiddenBefore || mButtonBarAnimator == null) { - // Remove previous call to MSG_SHOW_BUTTON_BAR if the user scrolled or something before - // the animation got a chance to play - mHideHandler.removeMessages(MSG_SHOW_BUTTON_BAR); - - if(mButtonBarAnimator != null) { - mButtonBarAnimator.cancel(); // stop current animation if there is one playing - } - - // 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) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "generateButtonBarAnimator"); - Log.d(TAG, " startY: " + startY); - Log.d(TAG, " endY: " + endY); - Log.d(TAG, " startZ: " + startZ); - Log.d(TAG, " endZ: " + endZ); - Log.d(TAG, " duration: " + 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/wear/TitledSettingsFragment.java b/src/com/android/packageinstaller/permission/ui/wear/TitledSettingsFragment.java deleted file mode 100644 index b673a498..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/TitledSettingsFragment.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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.permission.ui.wear; - -import android.app.Fragment; -import android.content.Context; -import android.os.Bundle; -import android.support.v7.widget.RecyclerView; -import android.support.wearable.view.WearableListView; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowInsets; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.packageinstaller.permission.ui.wear.settings.ViewUtils; -import com.android.packageinstaller.R; - -/** - * Base settings Fragment that shows a title at the top of the page. - */ -public abstract class TitledSettingsFragment extends Fragment implements - View.OnLayoutChangeListener, WearableListView.ClickListener { - - private static final int ITEM_CHANGE_DURATION_MS = 120; - - private static final String TAG = "TitledSettingsFragment"; - private int mInitialHeaderHeight; - - protected TextView mHeader; - protected TextView mDetails; - protected WearableListView mWheel; - - private int mCharLimitShortTitle; - private int mCharLimitLine; - private int mChinOffset; - - private TextWatcher mHeaderTextWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} - - @Override - public void afterTextChanged(Editable editable) { - adjustHeaderSize(); - } - }; - - private void adjustHeaderTranslation() { - int translation = 0; - if (mWheel.getChildCount() > 0) { - translation = mWheel.getCentralViewTop() - mWheel.getChildAt(0).getTop(); - } - - float newTranslation = Math.min(Math.max(-mInitialHeaderHeight, -translation), 0); - - int position = mWheel.getChildAdapterPosition(mWheel.getChildAt(0)); - if (position == 0 || newTranslation < 0) { - mHeader.setTranslationY(newTranslation); - } - } - - @Override - public void onTopEmptyRegionClick() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mCharLimitShortTitle = getResources().getInteger(R.integer.short_title_length); - mCharLimitLine = getResources().getInteger(R.integer.char_limit_per_line); - } - - @Override - public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, - int oldTop, int oldRight, int oldBottom) { - if (view == mHeader) { - mInitialHeaderHeight = bottom - top; - if (ViewUtils.getIsCircular(getContext())) { - // We are adding more margin on circular screens, so we need to account for it and use - // it for hiding the header. - mInitialHeaderHeight += - ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).topMargin; - } - } else if (view == mWheel) { - adjustHeaderTranslation(); - } - } - - protected void initializeLayout(RecyclerView.Adapter adapter) { - View v = getView(); - mWheel = (WearableListView) v.findViewById(R.id.wheel); - - mHeader = (TextView) v.findViewById(R.id.header); - mHeader.addOnLayoutChangeListener(this); - mHeader.addTextChangedListener(mHeaderTextWatcher); - - mDetails = (TextView) v.findViewById(R.id.details); - mDetails.addOnLayoutChangeListener(this); - - mWheel.setAdapter(adapter); - mWheel.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - } - - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - adjustHeaderTranslation(); - } - }); - mWheel.setClickListener(this); - mWheel.addOnLayoutChangeListener(this); - - // Decrease item change animation duration to approximately half of the default duration. - RecyclerView.ItemAnimator itemAnimator = mWheel.getItemAnimator(); - itemAnimator.setChangeDuration(ITEM_CHANGE_DURATION_MS); - - adjustHeaderSize(); - - positionOnCircular(getContext(), mHeader, mDetails, mWheel); - } - - public void positionOnCircular(Context context, View header, View details, - final ViewGroup wheel) { - if (ViewUtils.getIsCircular(context)) { - LinearLayout.LayoutParams params = - (LinearLayout.LayoutParams) header.getLayoutParams(); - params.topMargin = (int) context.getResources().getDimension( - R.dimen.settings_header_top_margin_circular); - // Note that the margins are made symmetrical here. Since they're symmetrical we choose - // the smaller value to maximize usable width. - final int margin = (int) Math.min(context.getResources().getDimension( - R.dimen.round_content_padding_left), context.getResources().getDimension( - R.dimen.round_content_padding_right)); - params.leftMargin = margin; - params.rightMargin = margin; - params.gravity = Gravity.CENTER_HORIZONTAL; - header.setLayoutParams(params); - details.setLayoutParams(params); - - if (header instanceof TextView) { - ((TextView) header).setGravity(Gravity.CENTER); - } - if (details instanceof TextView) { - ((TextView) details).setGravity(Gravity.CENTER); - } - - final int leftPadding = (int) context.getResources().getDimension( - R.dimen.round_content_padding_left); - final int rightPadding = (int) context.getResources().getDimension( - R.dimen.round_content_padding_right); - final int topPadding = (int) context.getResources().getDimension( - R.dimen.settings_wearable_list_view_vertical_padding_round); - final int bottomPadding = (int) context.getResources().getDimension( - R.dimen.settings_wearable_list_view_vertical_padding_round); - wheel.setPadding(leftPadding, topPadding, rightPadding, mChinOffset + bottomPadding); - wheel.setClipToPadding(false); - - wheel.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { - @Override - public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - mChinOffset = insets.getSystemWindowInsetBottom(); - wheel.setPadding(leftPadding, topPadding, rightPadding, - mChinOffset + bottomPadding); - // This listener is invoked after each time we navigate to SettingsActivity and - // it keeps adding padding. We need to disable it after the first update. - v.setOnApplyWindowInsetsListener(null); - return insets.consumeSystemWindowInsets(); - } - }); - } else { - int leftPadding = (int) context.getResources().getDimension( - R.dimen.content_padding_left); - wheel.setPadding(leftPadding, wheel.getPaddingTop(), wheel.getPaddingRight(), - wheel.getPaddingBottom()); - } - } - - private void adjustHeaderSize() { - int length = mHeader.length(); - - if (length <= mCharLimitShortTitle) { - mHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX, - getResources().getDimensionPixelSize( - R.dimen.setting_short_header_text_size)); - } else { - mHeader.setTextSize(TypedValue.COMPLEX_UNIT_PX, - getResources().getDimensionPixelSize( - R.dimen.setting_long_header_text_size)); - } - - boolean singleLine = length <= mCharLimitLine; - - float height = getResources().getDimension(R.dimen.settings_header_base_height); - if (!singleLine) { - height += getResources().getDimension(R.dimen.setting_header_extra_line_height); - } - mHeader.setMinHeight((int) height); - - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mHeader.getLayoutParams(); - final Context context = getContext(); - if (!singleLine) { - // Make the top margin a little bit smaller so there is more space for the title. - if (ViewUtils.getIsCircular(context)) { - params.topMargin = getResources().getDimensionPixelSize( - R.dimen.settings_header_top_margin_circular_multiline); - } else { - params.topMargin = getResources().getDimensionPixelSize( - R.dimen.settings_header_top_margin_multiline); - } - } else { - if (ViewUtils.getIsCircular(context)) { - params.topMargin = getResources().getDimensionPixelSize( - R.dimen.settings_header_top_margin_circular); - } else { - params.topMargin = getResources().getDimensionPixelSize( - R.dimen.settings_header_top_margin); - } - } - mHeader.setLayoutParams(params); - } -} diff --git a/src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java b/src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java deleted file mode 100644 index 0800c14c..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/WarningConfirmationActivity.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -* 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.permission.ui.wear; - -import android.app.Activity; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; -import android.os.Bundle; - -import com.android.packageinstaller.R; - -public final class WarningConfirmationActivity extends Activity { - public final static String EXTRA_WARNING_MESSAGE = "EXTRA_WARNING_MESSAGE"; - // Saved index that will be returned in the onActivityResult() callback - public final static String EXTRA_INDEX = "EXTRA_INDEX"; - - private ConfirmationViewHandler mViewHandler; - private String mMessage; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mMessage = getIntent().getStringExtra(EXTRA_WARNING_MESSAGE); - - mViewHandler = new ConfirmationViewHandler(this) { - @Override // ConfirmationViewHandler - public int getButtonBarMode() { - return MODE_VERTICAL_BUTTONS; - } - - @Override - public void onButton1() { - setResultAndFinish(Activity.RESULT_CANCELED); - } - - @Override - public void onButton2() { - setResultAndFinish(Activity.RESULT_OK); - } - - @Override - public void onButton3() { - // no-op - } - - @Override - public CharSequence getVerticalButton1Text() { - return getString(R.string.cancel); - } - - @Override - public CharSequence getVerticalButton2Text() { - return getString(R.string.grant_dialog_button_deny_anyway); - } - - @Override - public CharSequence getVerticalButton3Text() { - return null; - } - - @Override - public Drawable getVerticalButton1Icon() { - return getDrawable(R.drawable.cancel_button); - } - - @Override - public Drawable getVerticalButton2Icon() { - return getDrawable(R.drawable.confirm_button); - } - - @Override - public Drawable getVerticalButton3Icon() { - return null; - } - - @Override - public CharSequence getCurrentPageText() { - return null; - } - - @Override - public Icon getPermissionIcon() { - return null; - } - - @Override - public CharSequence getMessage() { - return mMessage; - } - }; - - setContentView(mViewHandler.createView()); - mViewHandler.invalidate(); - } - - private void setResultAndFinish(int result) { - Intent intent = new Intent(); - intent.putExtra(EXTRA_INDEX, getIntent().getIntExtra(EXTRA_INDEX, -1)); - setResult(result, intent); - finish(); - } -} diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java b/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java deleted file mode 100644 index 02c203b3..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedOnCenterProximityListener.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.permission.ui.wear.settings; - -import android.support.wearable.view.WearableListView; - -public interface ExtendedOnCenterProximityListener - extends WearableListView.OnCenterProximityListener { - float getProximityMinValue(); - - float getProximityMaxValue(); - - float getCurrentProximityValue(); - - void setScalingAnimatorValue(float value); -} diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java b/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java deleted file mode 100644 index 6b725419..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/settings/ExtendedViewHolder.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.permission.ui.wear.settings; - -import android.animation.ObjectAnimator; -import android.support.wearable.view.WearableListView; -import android.view.View; - - -public class ExtendedViewHolder extends WearableListView.ViewHolder { - public static final long DEFAULT_ANIMATION_DURATION = 150; - - private ObjectAnimator mScalingUpAnimator; - - private ObjectAnimator mScalingDownAnimator; - - private float mMinValue; - - private float mMaxValue; - - public ExtendedViewHolder(View itemView) { - super(itemView); - if (itemView instanceof ExtendedOnCenterProximityListener) { - ExtendedOnCenterProximityListener item = - (ExtendedOnCenterProximityListener) itemView; - mMinValue = item.getProximityMinValue(); - item.setScalingAnimatorValue(mMinValue); - mMaxValue = item.getProximityMaxValue(); - mScalingUpAnimator = ObjectAnimator.ofFloat(item, "scalingAnimatorValue", mMinValue, - mMaxValue); - mScalingUpAnimator.setDuration(DEFAULT_ANIMATION_DURATION); - mScalingDownAnimator = ObjectAnimator.ofFloat(item, "scalingAnimatorValue", - mMaxValue, mMinValue); - mScalingDownAnimator.setDuration(DEFAULT_ANIMATION_DURATION); - } - } - - public void onCenterProximity(boolean isCentralItem, boolean animate) { - if (!(itemView instanceof ExtendedOnCenterProximityListener)) { - return; - } - ExtendedOnCenterProximityListener item = (ExtendedOnCenterProximityListener) itemView; - if (isCentralItem) { - if (animate) { - mScalingDownAnimator.cancel(); - if (!mScalingUpAnimator.isRunning()) { - mScalingUpAnimator.setFloatValues(item.getCurrentProximityValue(), - mMaxValue); - mScalingUpAnimator.start(); - } - } else { - mScalingUpAnimator.cancel(); - item.setScalingAnimatorValue(item.getProximityMaxValue()); - } - } else { - mScalingUpAnimator.cancel(); - if (animate) { - if (!mScalingDownAnimator.isRunning()) { - mScalingDownAnimator.setFloatValues(item.getCurrentProximityValue(), - mMinValue); - mScalingDownAnimator.start(); - } - } else { - mScalingDownAnimator.cancel(); - item.setScalingAnimatorValue(item.getProximityMinValue()); - } - } - super.onCenterProximity(isCentralItem, animate); - } -} diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java b/src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java deleted file mode 100644 index 0e0adcbb..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/settings/PermissionsSettingsAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.permission.ui.wear.settings; - -import android.content.Context; -import android.content.res.Resources; -import android.support.wearable.view.WearableListView; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.android.packageinstaller.R; -import com.android.packageinstaller.permission.model.AppPermissionGroup; - -public final class PermissionsSettingsAdapter extends SettingsAdapter<AppPermissionGroup> { - private Resources mRes; - - public PermissionsSettingsAdapter(Context context) { - super(context, R.layout.permissions_settings_item); - mRes = context.getResources(); - } - - @Override - public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new PermissionsViewHolder(new PermissionsSettingsItem(parent.getContext())); - } - - @Override - public void onBindViewHolder(WearableListView.ViewHolder holder, int position) { - super.onBindViewHolder(holder, position); - PermissionsViewHolder viewHolder = (PermissionsViewHolder) holder; - AppPermissionGroup group = get(position).data; - - if (group.isPolicyFixed()) { - viewHolder.imageView.setEnabled(false); - viewHolder.textView.setEnabled(false); - viewHolder.state.setEnabled(false); - viewHolder.state.setText( - mRes.getString(R.string.permission_summary_enforced_by_policy)); - } else { - viewHolder.imageView.setEnabled(true); - viewHolder.textView.setEnabled(true); - viewHolder.state.setEnabled(true); - - if (group.areRuntimePermissionsGranted()) { - viewHolder.state.setText(R.string.generic_enabled); - } else { - viewHolder.state.setText(R.string.generic_disabled); - } - } - } - - private static final class PermissionsViewHolder extends SettingsAdapter.SettingsItemHolder { - public final TextView state; - - public PermissionsViewHolder(View view) { - super(view); - state = (TextView) view.findViewById(R.id.state); - } - } - - private class PermissionsSettingsItem extends SettingsItem { - private final TextView mState; - private final float mCenteredAlpha = 1.0f; - private final float mNonCenteredAlpha = 0.5f; - - public PermissionsSettingsItem (Context context) { - super(context); - mState = (TextView) findViewById(R.id.state); - } - - @Override - public void onCenterPosition(boolean animate) { - mImage.setAlpha(mImage.isEnabled() ? mCenteredAlpha : mNonCenteredAlpha); - mText.setAlpha(mText.isEnabled() ? mCenteredAlpha : mNonCenteredAlpha); - mState.setAlpha(mState.isEnabled() ? mCenteredAlpha : mNonCenteredAlpha); - } - - @Override - public void onNonCenterPosition(boolean animate) { - mImage.setAlpha(mNonCenteredAlpha); - mText.setAlpha(mNonCenteredAlpha); - mState.setAlpha(mNonCenteredAlpha); - } - } -} - diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java b/src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java deleted file mode 100644 index baf1a2b4..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/settings/SettingsAdapter.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * 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.permission.ui.wear.settings; - -import android.content.Context; -import android.support.wearable.view.CircledImageView; -import android.support.wearable.view.WearableListView; -import android.util.Log; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.TextView; - -import com.android.packageinstaller.R; - -import java.util.ArrayList; - -/** - * Common adapter for settings views. Maintains a list of 'Settings', consisting of a name, - * icon and optional activity-specific data. - */ -public class SettingsAdapter<T> extends WearableListView.Adapter { - private static final String TAG = "SettingsAdapter"; - private final Context mContext; - - public static final class Setting<S> { - public static final int ID_INVALID = -1; - - public final int id; - public int nameResourceId; - public CharSequence name; - public int iconResource; - public boolean inProgress; - public S data; - - public Setting(CharSequence name, int iconResource, S data) { - this(name, iconResource, data, ID_INVALID); - } - - public Setting(CharSequence name, int iconResource, S data, int id) { - this.name = name; - this.iconResource = iconResource; - this.data = data; - this.inProgress = false; - this.id = id; - } - - public Setting(int nameResource, int iconResource, S data, int id) { - this.nameResourceId = nameResource; - this.iconResource = iconResource; - this.data = data; - this.inProgress = false; - this.id = id; - } - - public Setting(int nameResource, int iconResource, int id) { - this.nameResourceId = nameResource; - this.iconResource = iconResource; - this.data = null; - this.inProgress = false; - this.id = id; - } - - public Setting(CharSequence name, int iconResource, int id) { - this(name, iconResource, null, id); - } - - } - - private final int mItemLayoutId; - private final float mDefaultCircleRadiusPercent; - private final float mSelectedCircleRadiusPercent; - - protected ArrayList<Setting<T>> mSettings = new ArrayList<Setting<T>>(); - - public SettingsAdapter(Context context, int itemLayoutId) { - mContext = context; - mItemLayoutId = itemLayoutId; - mDefaultCircleRadiusPercent = context.getResources().getFraction( - R.dimen.default_settings_circle_radius_percent, 1, 1); - mSelectedCircleRadiusPercent = context.getResources().getFraction( - R.dimen.selected_settings_circle_radius_percent, 1, 1); - } - - @Override - public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new SettingsItemHolder(new SettingsItem(parent.getContext())); - } - - @Override - public void onBindViewHolder(WearableListView.ViewHolder holder, int position) { - Setting<T> setting = mSettings.get(position); - if (setting.iconResource == -1) { - ((SettingsItemHolder) holder).imageView.setVisibility(View.GONE); - } else { - ((SettingsItemHolder) holder).imageView.setVisibility(View.VISIBLE); - ((SettingsItemHolder) holder).imageView.setImageResource( - mSettings.get(position).iconResource); - } - Log.d(TAG, "onBindViewHolder " + setting.name + " " + setting.id + " " + setting - .nameResourceId); - if (setting.name == null && setting.nameResourceId != 0) { - setting.name = mContext.getString(setting.nameResourceId); - } - ((SettingsItemHolder) holder).textView.setText(setting.name); - } - - @Override - public int getItemCount() { - return mSettings.size(); - } - - public void addSetting(CharSequence name, int iconResource) { - addSetting(name, iconResource, null); - } - - public void addSetting(CharSequence name, int iconResource, T intent) { - addSetting(mSettings.size(), name, iconResource, intent); - } - - public void addSetting(int index, CharSequence name, int iconResource, T intent) { - addSetting(Setting.ID_INVALID, index, name, iconResource, intent); - } - - public void addSetting(int id, int index, CharSequence name, int iconResource, T intent) { - mSettings.add(index, new Setting<T>(name, iconResource, intent, id)); - notifyItemInserted(index); - } - - public void addSettingDontNotify(Setting<T> setting) { - mSettings.add(setting); - } - - public void addSetting(Setting<T> setting) { - mSettings.add(setting); - notifyItemInserted(mSettings.size() - 1); - } - - public void addSetting(int index, Setting<T> setting) { - mSettings.add(index, setting); - notifyItemInserted(index); - } - - /** - * Returns the index of the setting in the adapter based on the ID supplied when it was - * originally added. - * @param id the setting's id - * @return index in the adapter of the setting. -1 if not found. - */ - public int findSetting(int id) { - for (int i = mSettings.size() - 1; i >= 0; --i) { - Setting setting = mSettings.get(i); - - if (setting.id == id) { - return i; - } - } - - return -1; - } - - /** - * Removes a setting at the given index. - * @param index the index of the setting to be removed - */ - public void removeSetting(int index) { - mSettings.remove(index); - notifyDataSetChanged(); - } - - public void clearSettings() { - mSettings.clear(); - notifyDataSetChanged(); - } - - /** - * Updates a setting in place. - * @param index the index of the setting - * @param name the updated setting name - * @param iconResource the update setting icon - * @param intent the updated intent for the setting - */ - public void updateSetting(int index, CharSequence name, int iconResource, T intent) { - Setting<T> setting = mSettings.get(index); - setting.iconResource = iconResource; - setting.name = name; - setting.data = intent; - notifyItemChanged(index); - } - - public Setting<T> get(int position) { - return mSettings.get(position); - } - - protected static class SettingsItemHolder extends ExtendedViewHolder { - public final CircledImageView imageView; - public final TextView textView; - - public SettingsItemHolder(View itemView) { - super(itemView); - - imageView = ((CircledImageView) itemView.findViewById(R.id.image)); - textView = ((TextView) itemView.findViewById(R.id.text)); - } - } - - protected class SettingsItem extends FrameLayout implements ExtendedOnCenterProximityListener { - - protected final CircledImageView mImage; - protected final TextView mText; - - public SettingsItem(Context context) { - super(context); - View view = View.inflate(context, mItemLayoutId, null); - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT); - params.gravity = Gravity.CENTER_VERTICAL; - addView(view, params); - mImage = (CircledImageView) findViewById(R.id.image); - mText = (TextView) findViewById(R.id.text); - } - - @Override - public float getProximityMinValue() { - return mDefaultCircleRadiusPercent; - } - - @Override - public float getProximityMaxValue() { - return mSelectedCircleRadiusPercent; - } - - @Override - public float getCurrentProximityValue() { - return mImage.getCircleRadiusPressedPercent(); - } - - @Override - public void setScalingAnimatorValue(float value) { - mImage.setCircleRadiusPercent(value); - mImage.setCircleRadiusPressedPercent(value); - } - - @Override - public void onCenterPosition(boolean animate) { - mImage.setAlpha(1f); - mText.setAlpha(1f); - } - - @Override - public void onNonCenterPosition(boolean animate) { - mImage.setAlpha(0.5f); - mText.setAlpha(0.5f); - } - - TextView getTextView() { - return mText; - } - } -} diff --git a/src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java b/src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java deleted file mode 100644 index cf1c0fd0..00000000 --- a/src/com/android/packageinstaller/permission/ui/wear/settings/ViewUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.permission.ui.wear.settings; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; - -/** - * Utility to determine screen shape - */ -public class ViewUtils { - - public static boolean getIsCircular(Context context) { - return context.getResources().getConfiguration().isScreenRound(); - } - - /** - * Set the given {@code view} and all descendants to the given {@code enabled} state. - * - * @param view the parent view of a subtree of components whose enabled state must be set - * @param enabled the new enabled state of the subtree of components - */ - public static void setEnabled(View view, boolean enabled) { - view.setEnabled(enabled); - - if (view instanceof ViewGroup) { - final ViewGroup viewGroup = (ViewGroup) view; - for (int i = 0; i < viewGroup.getChildCount(); i++) { - setEnabled(viewGroup.getChildAt(i), enabled); - } - } - } -} |