Merge "Show shadow when entity header starts scrolling."

This commit is contained in:
TreeHugger Robot
2017-05-23 02:01:41 +00:00
committed by Android (Google) Code Review
18 changed files with 277 additions and 57 deletions

View File

@@ -109,7 +109,7 @@ public class AccountDetailDashboardFragment extends DashboardFragment {
mRemoveAccountController = new RemoveAccountPreferenceController(context, this);
controllers.add(mRemoveAccountController);
controllers.add(new AccountHeaderPreferenceController(
context, getActivity(), this, getArguments()));
context, getLifecycle(), getActivity(), this, getArguments()));
return controllers;
}

View File

@@ -18,10 +18,10 @@ package com.android.settings.accounts;
import android.accounts.Account;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
@@ -29,6 +29,7 @@ import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.PreferenceController;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.core.lifecycle.Lifecycle;
import static com.android.settings.accounts.AccountDetailDashboardFragment.KEY_ACCOUNT;
import static com.android.settings.accounts.AccountDetailDashboardFragment.KEY_USER_HANDLE;
@@ -38,15 +39,17 @@ public class AccountHeaderPreferenceController extends PreferenceController {
private static final String KEY_ACCOUNT_HEADER = "account_header";
private final Activity mActivity;
private final Fragment mHost;
private final PreferenceFragment mHost;
private final Account mAccount;
private final UserHandle mUserHandle;
private final Lifecycle mLifecycle;
public AccountHeaderPreferenceController(Context context, Activity activity, Fragment host,
Bundle args) {
public AccountHeaderPreferenceController(Context context, Lifecycle lifecycle,
Activity activity, PreferenceFragment host, Bundle args) {
super(context);
mActivity = activity;
mHost = host;
mLifecycle = lifecycle;
if (args != null && args.containsKey(KEY_ACCOUNT)) {
mAccount = args.getParcelable(KEY_ACCOUNT);
} else {
@@ -80,6 +83,7 @@ public class AccountHeaderPreferenceController extends PreferenceController {
EntityHeaderController
.newInstance(mActivity, mHost, headerPreference.findViewById(R.id.entity_header))
.setRecyclerView(mHost.getListView(), mLifecycle)
.setLabel(mAccount.name)
.setIcon(helper.getDrawableForType(mContext, mAccount.type))
.done(mActivity, true /* rebindButtons */);

View File

@@ -43,6 +43,7 @@ public abstract class AppInfoWithHeader extends AppInfoBase {
final Activity activity = getActivity();
final Preference pref = EntityHeaderController
.newInstance(activity, this, null /* header */)
.setRecyclerView(getListView(), getLifecycle())
.setIcon(IconDrawableFactory.newInstance(activity)
.getBadgedIcon(mPackageInfo.applicationInfo))
.setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))

View File

@@ -408,6 +408,7 @@ public class InstalledAppDetails extends AppInfoBase
mHeader = (LayoutPreference) findPreference(KEY_HEADER);
mActionButtons = (LayoutPreference) findPreference(KEY_ACTION_BUTTONS);
EntityHeaderController.newInstance(activity, this, mHeader.findViewById(R.id.entity_header))
.setRecyclerView(getListView(), getLifecycle())
.setPackageName(mPackageName)
.setButtonActions(EntityHeaderController.ActionType.ACTION_APP_PREFERENCE,
EntityHeaderController.ActionType.ACTION_NONE)
@@ -585,11 +586,11 @@ public class InstalledAppDetails extends AppInfoBase
final CharSequence summary =
isInstantApp ? null : getString(Utils.getInstallationStatus(mAppEntry.info));
EntityHeaderController.newInstance(activity, this, appSnippet)
.setLabel(mAppEntry)
.setIcon(mAppEntry)
.setSummary(summary)
.setIsInstantApp(isInstantApp)
.done(activity, false /* rebindActions */);
.setLabel(mAppEntry)
.setIcon(mAppEntry)
.setSummary(summary)
.setIsInstantApp(isInstantApp)
.done(activity, false /* rebindActions */);
mVersionPreference.setSummary(getString(R.string.version_text, pkgInfo.versionName));
}

View File

@@ -128,16 +128,17 @@ public class ProcessStatsDetail extends SettingsPreferenceFragment {
final Activity activity = getActivity();
final Preference pref = EntityHeaderController
.newInstance(activity, this, null /* appHeader */)
.setIcon(mApp.mUiTargetApp != null
? IconDrawableFactory.newInstance(activity).getBadgedIcon(mApp.mUiTargetApp)
: new ColorDrawable(0))
.setLabel(mApp.mUiLabel)
.setPackageName(mApp.mPackage)
.setUid(mApp.mUiTargetApp != null
? mApp.mUiTargetApp.uid
: UserHandle.USER_NULL)
.setButtonActions(ActionType.ACTION_APP_INFO, ActionType.ACTION_NONE)
.done(activity, getPrefContext());
.setRecyclerView(getListView(), getLifecycle())
.setIcon(mApp.mUiTargetApp != null
? IconDrawableFactory.newInstance(activity).getBadgedIcon(mApp.mUiTargetApp)
: new ColorDrawable(0))
.setLabel(mApp.mUiLabel)
.setPackageName(mApp.mPackage)
.setUid(mApp.mUiTargetApp != null
? mApp.mUiTargetApp.uid
: UserHandle.USER_NULL)
.setButtonActions(ActionType.ACTION_APP_INFO, ActionType.ACTION_NONE)
.done(activity, getPrefContext());
getPreferenceScreen().addPreference(pref);
}

View File

@@ -327,6 +327,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
final Activity activity = getActivity();
final Preference pref = EntityHeaderController
.newInstance(activity, this, null /* header */)
.setRecyclerView(getListView(), getLifecycle())
.setButtonActions(showInfoButton
? EntityHeaderController.ActionType.ACTION_APP_INFO
: EntityHeaderController.ActionType.ACTION_NONE,

View File

@@ -184,6 +184,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
final Bundle bundle = getArguments();
EntityHeaderController controller = EntityHeaderController
.newInstance(context, this, appSnippet)
.setRecyclerView(getListView(), getLifecycle())
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);

View File

@@ -132,6 +132,7 @@ public class AppNotificationSettings extends NotificationSettingsBase {
final Activity activity = getActivity();
final Preference pref = EntityHeaderController
.newInstance(activity, this /* fragment */, null /* header */)
.setRecyclerView(getListView(), getLifecycle())
.setIcon(mAppRow.icon)
.setLabel(mAppRow.label)
.setPackageName(mAppRow.pkg)

View File

@@ -112,6 +112,7 @@ public class ChannelNotificationSettings extends NotificationSettingsBase {
final Activity activity = getActivity();
final Preference pref = EntityHeaderController
.newInstance(activity, this /* fragment */, null /* header */)
.setRecyclerView(getListView(), getLifecycle())
.setIcon(mAppRow.icon)
.setLabel(mChannel.getName())
.setSummary(mAppRow.label)

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2017 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.settings.widget;
import android.app.ActionBar;
import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
public class ActionBarShadowController implements LifecycleObserver, OnStart, OnStop {
private ScrollChangeWatcher mScrollChangeWatcher;
private RecyclerView mRecyclerView;
private boolean isScrollWatcherAttached;
public static ActionBarShadowController attachToRecyclerView(Activity activity,
Lifecycle lifecycle, RecyclerView recyclerView) {
return new ActionBarShadowController(activity, lifecycle, recyclerView);
}
private ActionBarShadowController(Activity activity, Lifecycle lifecycle,
RecyclerView recyclerView) {
mScrollChangeWatcher = new ScrollChangeWatcher(activity);
mRecyclerView = recyclerView;
attachScrollWatcher();
lifecycle.addObserver(this);
}
@Override
public void onStop() {
detachScrollWatcher();
}
private void detachScrollWatcher() {
mRecyclerView.removeOnScrollListener(mScrollChangeWatcher);
isScrollWatcherAttached = false;
}
@Override
public void onStart() {
attachScrollWatcher();
}
private void attachScrollWatcher() {
if (!isScrollWatcherAttached) {
isScrollWatcherAttached = true;
mRecyclerView.addOnScrollListener(mScrollChangeWatcher);
mScrollChangeWatcher.updateDropShadow(mRecyclerView);
}
}
/**
* Update the drop shadow as the scrollable entity is scrolled.
*/
private final class ScrollChangeWatcher extends RecyclerView.OnScrollListener {
private Activity mActivity;
public ScrollChangeWatcher(Activity activity) {
mActivity = activity;
}
// RecyclerView scrolled.
@Override
public void onScrolled(RecyclerView view, int dx, int dy) {
updateDropShadow(view);
}
public void updateDropShadow(View view) {
final boolean shouldShowShadow = view.canScrollVertically(-1);
final ActionBar actionBar = mActivity.getActionBar();
if (actionBar != null) {
actionBar.setElevation(shouldShowShadow ? 8 : 0);
}
}
}
}

View File

@@ -30,6 +30,7 @@ import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.support.annotation.IntDef;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -46,6 +47,7 @@ import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -68,11 +70,13 @@ public class EntityHeaderController {
private static final String TAG = "AppDetailFeature";
private final Context mContext;
private final Context mAppContext;
private final Activity mActivity;
private final Fragment mFragment;
private final int mMetricsCategory;
private final View mHeader;
private Lifecycle mLifecycle;
private RecyclerView mRecyclerView;
private Drawable mIcon;
private CharSequence mLabel;
private CharSequence mSummary;
@@ -93,15 +97,16 @@ public class EntityHeaderController {
* @param fragment The fragment that header will be placed in.
* @param header Optional: header view if it's already created.
*/
public static EntityHeaderController newInstance(Context context, Fragment fragment,
public static EntityHeaderController newInstance(Activity activity, Fragment fragment,
View header) {
return new EntityHeaderController(context.getApplicationContext(), fragment, header);
return new EntityHeaderController(activity, fragment, header);
}
private EntityHeaderController(Context context, Fragment fragment, View header) {
mContext = context;
private EntityHeaderController(Activity activity, Fragment fragment, View header) {
mActivity = activity;
mAppContext = activity.getApplicationContext();
mFragment = fragment;
mMetricsCategory = FeatureFactory.getFactory(context).getMetricsFeatureProvider()
mMetricsCategory = FeatureFactory.getFactory(mAppContext).getMetricsFeatureProvider()
.getMetricsCategory(fragment);
if (header != null) {
mHeader = header;
@@ -111,16 +116,22 @@ public class EntityHeaderController {
}
}
public EntityHeaderController setRecyclerView(RecyclerView recyclerView, Lifecycle lifecycle) {
mRecyclerView = recyclerView;
mLifecycle = lifecycle;
return this;
}
public EntityHeaderController setIcon(Drawable icon) {
if (icon != null) {
mIcon = icon.getConstantState().newDrawable(mContext.getResources());
mIcon = icon.getConstantState().newDrawable(mAppContext.getResources());
}
return this;
}
public EntityHeaderController setIcon(ApplicationsState.AppEntry appEntry) {
if (appEntry.icon != null) {
mIcon = appEntry.icon.getConstantState().newDrawable(mContext.getResources());
mIcon = appEntry.icon.getConstantState().newDrawable(mAppContext.getResources());
}
return this;
}
@@ -233,6 +244,9 @@ public class EntityHeaderController {
actionBar.setBackgroundDrawable(
new ColorDrawable(Utils.getColorAttr(activity, android.R.attr.colorSecondary)));
actionBar.setElevation(0);
if (mRecyclerView != null && mLifecycle != null) {
ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView);
}
return this;
}
@@ -257,7 +271,7 @@ public class EntityHeaderController {
button.setVisibility(View.GONE);
} else {
button.setContentDescription(
mContext.getString(R.string.application_info_label));
mAppContext.getString(R.string.application_info_label));
button.setImageResource(com.android.settings.R.drawable.ic_info);
button.setOnClickListener(new View.OnClickListener() {
@Override
@@ -311,7 +325,7 @@ public class EntityHeaderController {
}
private Intent resolveIntent(Intent i) {
ResolveInfo result = mContext.getPackageManager().resolveActivity(i, 0);
ResolveInfo result = mAppContext.getPackageManager().resolveActivity(i, 0);
if (result != null) {
return new Intent(i.getAction())
.setClassName(result.activityInfo.packageName, result.activityInfo.name);