Merge "Show shadow when entity header starts scrolling."
This commit is contained in:
committed by
Android (Google) Code Review
commit
ff9d0f2028
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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 */);
|
||||
|
@@ -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))
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user