Loading core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +108 −9 Original line number Diff line number Diff line Loading @@ -15,15 +15,25 @@ */ package com.android.internal.app; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.StringRes; import android.app.AppGlobals; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.ResolveInfo; import android.os.UserHandle; import android.os.UserManager; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.PagerAdapter; import com.android.internal.widget.ViewPager; Loading Loading @@ -213,26 +223,115 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { abstract @Nullable ViewGroup getInactiveAdapterView(); boolean rebuildActiveTab(boolean post) { return rebuildTab(getActiveListAdapter(), post); /** * Rebuilds the tab that is currently visible to the user. * <p>Returns {@code true} if rebuild has completed. */ boolean rebuildActiveTab(boolean doPostProcessing) { return rebuildTab(getActiveListAdapter(), doPostProcessing); } boolean rebuildInactiveTab(boolean post) { /** * Rebuilds the tab that is not currently visible to the user, if such one exists. * <p>Returns {@code true} if rebuild has completed. */ boolean rebuildInactiveTab(boolean doPostProcessing) { if (getItemCount() == 1) { return false; } return rebuildTab(getInactiveListAdapter(), post); return rebuildTab(getInactiveListAdapter(), doPostProcessing); } private int userHandleToPageIndex(UserHandle userHandle) { if (userHandle == getPersonalListAdapter().mResolverListController.getUserHandle()) { return PROFILE_PERSONAL; } else { return PROFILE_WORK; } } private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) { UserHandle listUserHandle = activeListAdapter.getUserHandle(); if (UserHandle.myUserId() != listUserHandle.getIdentifier() && !hasAppsInOtherProfile(activeListAdapter)) { // TODO(arangelov): Show empty state UX here UserManager userManager = mContext.getSystemService(UserManager.class); if (listUserHandle == mWorkProfileUserHandle && userManager.isQuietModeEnabled(mWorkProfileUserHandle)) { showEmptyState(activeListAdapter, R.drawable.ic_work_apps_off, R.string.resolver_turn_on_work_apps, R.string.resolver_turn_on_work_apps_explanation, (View.OnClickListener) v -> userManager.requestQuietModeEnabled(false, mWorkProfileUserHandle)); return false; } if (UserHandle.myUserId() != listUserHandle.getIdentifier()) { if (!hasCrossProfileIntents(activeListAdapter.getIntents(), UserHandle.myUserId(), listUserHandle.getIdentifier())) { if (listUserHandle == mPersonalProfileUserHandle) { showEmptyState(activeListAdapter, R.drawable.ic_sharing_disabled, R.string.resolver_cant_share_with_personal_apps, R.string.resolver_cant_share_cross_profile_explanation); } else { showEmptyState(activeListAdapter, R.drawable.ic_sharing_disabled, R.string.resolver_cant_share_with_work_apps, R.string.resolver_cant_share_cross_profile_explanation); } return false; } } return activeListAdapter.rebuildList(doPostProcessing); } void showEmptyState(ResolverListAdapter listAdapter) { UserHandle listUserHandle = listAdapter.getUserHandle(); if (UserHandle.myUserId() == listUserHandle.getIdentifier() || !hasAppsInOtherProfile(listAdapter)) { showEmptyState(listAdapter, R.drawable.ic_no_apps, R.string.resolver_no_apps_available, R.string.resolver_no_apps_available_explanation); } } private void showEmptyState(ResolverListAdapter activeListAdapter, @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes) { showEmptyState(activeListAdapter, iconRes, titleRes, subtitleRes, /* buttonOnClick */ null); } private void showEmptyState(ResolverListAdapter activeListAdapter, @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes, View.OnClickListener buttonOnClick) { ProfileDescriptor descriptor = getItem( userHandleToPageIndex(activeListAdapter.getUserHandle())); descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.GONE); View emptyStateView = descriptor.rootView.findViewById(R.id.resolver_empty_state); emptyStateView.setVisibility(View.VISIBLE); ImageView icon = emptyStateView.findViewById(R.id.resolver_empty_state_icon); icon.setImageResource(iconRes); TextView title = emptyStateView.findViewById(R.id.resolver_empty_state_title); title.setText(titleRes); TextView subtitle = emptyStateView.findViewById(R.id.resolver_empty_state_subtitle); subtitle.setText(subtitleRes); Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button); button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE); button.setOnClickListener(buttonOnClick); } private boolean hasCrossProfileIntents(List<Intent> intents, int source, int target) { IPackageManager packageManager = AppGlobals.getPackageManager(); ContentResolver contentResolver = mContext.getContentResolver(); for (Intent intent : intents) { if (IntentForwarderActivity.canForward(intent, source, target, packageManager, contentResolver) != null) { return true; } } return false; } private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) { Loading core/java/com/android/internal/app/ChooserActivity.java +91 −25 Original line number Diff line number Diff line Loading @@ -373,7 +373,11 @@ public class ChooserActivity extends ResolverActivity implements Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load" + " within " + mImageLoadTimeoutMillis + "ms."); collapseParentView(); hideContentPreview(); if (hasWorkProfile() && ENABLE_TABBED_VIEW) { hideStickyContentPreview(); } else if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) { mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().hideContentPreview(); } mHideParentOnFail = false; } } Loading Loading @@ -829,7 +833,12 @@ public class ChooserActivity extends ResolverActivity implements @Override protected boolean postRebuildList(boolean rebuildCompleted) { updateContentPreview(); updateStickyContentPreview(); if (shouldShowStickyContentPreview() || mChooserMultiProfilePagerAdapter .getCurrentRootAdapter().getContentPreviewRowCount() != 0) { logActionShareWithPreview(); } return postRebuildListInternal(rebuildCompleted); } Loading Loading @@ -978,6 +987,8 @@ public class ChooserActivity extends ResolverActivity implements updateLayoutWidth(R.id.content_preview_text_layout, width, parent); updateLayoutWidth(R.id.content_preview_title_layout, width, parent); updateLayoutWidth(R.id.content_preview_file_layout, width, parent); findViewById(R.id.content_preview_container) .setVisibility(shouldShowStickyContentPreview() ? View.VISIBLE : View.GONE); } private void updateLayoutWidth(int layoutResourceId, int width, View parent) { Loading Loading @@ -2413,14 +2424,14 @@ public class ChooserActivity extends ResolverActivity implements // still zero? then use a default height and leave, which // can happen when there are no targets to show if (rowsToShow == 0 && !shouldShowContentPreview()) { if (rowsToShow == 0 && !shouldShowStickyContentPreview()) { offset += getResources().getDimensionPixelSize( R.dimen.chooser_max_collapsed_height); mResolverDrawerLayout.setCollapsibleHeightReserved(offset); return; } if (shouldShowContentPreview()) { if (shouldShowStickyContentPreview()) { offset += findViewById(R.id.content_preview_container).getHeight(); } Loading Loading @@ -2552,7 +2563,7 @@ public class ChooserActivity extends ResolverActivity implements } private void setupScrollListener() { if (mResolverDrawerLayout == null) { if (mResolverDrawerLayout == null || (hasWorkProfile() && ENABLE_TABBED_VIEW)) { return; } final View chooserHeader = mResolverDrawerLayout.findViewById(R.id.chooser_header); Loading Loading @@ -2597,28 +2608,36 @@ public class ChooserActivity extends ResolverActivity implements return false; } private boolean shouldShowContentPreview() { return mMultiProfilePagerAdapter.getActiveListAdapter().getCount() > 0 && isSendAction(getTargetIntent()); } private void updateContentPreview() { if (shouldShowContentPreview()) { showContentPreview(); /** * The sticky content preview is shown only when we have a tabbed view. It's shown above * the tabs so it is not part of the scrollable list. If we are not in tabbed view, * we instead show the content preview as a regular list item. */ private boolean shouldShowStickyContentPreview() { return hasWorkProfile() && ENABLE_TABBED_VIEW && mMultiProfilePagerAdapter.getListAdapterForUserHandle( UserHandle.of(UserHandle.myUserId())).getCount() > 0 && isSendAction(getTargetIntent()) && getResources().getBoolean(R.bool.sharesheet_show_content_preview); } private void updateStickyContentPreview() { if (shouldShowStickyContentPreview()) { showStickyContentPreview(); } else { hideContentPreview(); hideStickyContentPreview(); } } private void showContentPreview() { private void showStickyContentPreview() { ViewGroup contentPreviewContainer = findViewById(R.id.content_preview_container); contentPreviewContainer.setVisibility(View.VISIBLE); ViewGroup contentPreviewView = createContentPreviewView(contentPreviewContainer); contentPreviewContainer.addView(contentPreviewView); logActionShareWithPreview(); } private void hideContentPreview() { private void hideStickyContentPreview() { ViewGroup contentPreviewContainer = findViewById(R.id.content_preview_container); contentPreviewContainer.removeAllViews(); contentPreviewContainer.setVisibility(View.GONE); Loading @@ -2634,6 +2653,7 @@ public class ChooserActivity extends ResolverActivity implements /** * Used to bind types of individual item including * {@link ChooserGridAdapter#VIEW_TYPE_NORMAL}, * {@link ChooserGridAdapter#VIEW_TYPE_CONTENT_PREVIEW}, * {@link ChooserGridAdapter#VIEW_TYPE_PROFILE}, * and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}. */ Loading Loading @@ -2695,16 +2715,18 @@ public class ChooserActivity extends ResolverActivity implements private int mChooserTargetWidth = 0; private boolean mShowAzLabelIfPoss; private boolean mHideContentPreview = false; private boolean mLayoutRequested = false; private int mFooterHeight = 0; private static final int VIEW_TYPE_DIRECT_SHARE = 0; private static final int VIEW_TYPE_NORMAL = 1; private static final int VIEW_TYPE_PROFILE = 2; private static final int VIEW_TYPE_AZ_LABEL = 3; private static final int VIEW_TYPE_CALLER_AND_RANK = 4; private static final int VIEW_TYPE_FOOTER = 5; private static final int VIEW_TYPE_CONTENT_PREVIEW = 2; private static final int VIEW_TYPE_PROFILE = 3; private static final int VIEW_TYPE_AZ_LABEL = 4; private static final int VIEW_TYPE_CALLER_AND_RANK = 5; private static final int VIEW_TYPE_FOOTER = 6; private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4; private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8; Loading Loading @@ -2765,6 +2787,17 @@ public class ChooserActivity extends ResolverActivity implements return maxTargets; } /** * Hides the list item content preview. * <p>Not to be confused with the sticky content preview which is above the * personal and work tabs. */ public void hideContentPreview() { mHideContentPreview = true; mLayoutRequested = true; notifyDataSetChanged(); } public boolean consumeLayoutRequest() { boolean oldValue = mLayoutRequested; mLayoutRequested = false; Loading @@ -2773,7 +2806,8 @@ public class ChooserActivity extends ResolverActivity implements public int getRowCount() { return (int) ( getProfileRowCount() getContentPreviewRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + getAzLabelRowCount() Loading @@ -2783,7 +2817,33 @@ public class ChooserActivity extends ResolverActivity implements ); } /** * Returns either {@code 0} or {@code 1} depending on whether we want to show the list item * content preview. Not to be confused with the sticky content preview which is above the * personal and work tabs. */ public int getContentPreviewRowCount() { // For the tabbed case we show the sticky content preview above the tabs, // please refer to shouldShowStickyContentPreview if (hasWorkProfile() && ENABLE_TABBED_VIEW) { return 0; } if (!isSendAction(getTargetIntent())) { return 0; } if (mHideContentPreview || mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) { return 0; } return 1; } public int getProfileRowCount() { if (hasWorkProfile() && ENABLE_TABBED_VIEW) { return 0; } return mChooserListAdapter.getOtherProfile() == null ? 0 : 1; } Loading Loading @@ -2815,7 +2875,8 @@ public class ChooserActivity extends ResolverActivity implements @Override public int getItemCount() { return (int) ( getProfileRowCount() getContentPreviewRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + getAzLabelRowCount() Loading @@ -2827,6 +2888,8 @@ public class ChooserActivity extends ResolverActivity implements @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_CONTENT_PREVIEW: return new ItemViewHolder(createContentPreviewView(parent), false); case VIEW_TYPE_PROFILE: return new ItemViewHolder(createProfileView(parent), false); case VIEW_TYPE_AZ_LABEL: Loading Loading @@ -2866,7 +2929,10 @@ public class ChooserActivity extends ResolverActivity implements public int getItemViewType(int position) { int count; int countSum = (count = getProfileRowCount()); int countSum = (count = getContentPreviewRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW; countSum += (count = getProfileRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_PROFILE; countSum += (count = getServiceTargetRowCount()); Loading Loading @@ -3082,7 +3148,7 @@ public class ChooserActivity extends ResolverActivity implements } int getListPosition(int position) { position -= getProfileRowCount(); position -= getContentPreviewRowCount() + getProfileRowCount(); final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount Loading core/java/com/android/internal/app/IntentForwarderActivity.java +9 −6 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; Loading Loading @@ -108,7 +109,8 @@ public class IntentForwarderActivity extends Activity { } final int callingUserId = getUserId(); final Intent newIntent = canForward(intentReceived, targetUserId); final Intent newIntent = canForward(intentReceived, getUserId(), targetUserId, mInjector.getIPackageManager(), getContentResolver()); if (newIntent != null) { if (Intent.ACTION_CHOOSER.equals(newIntent.getAction())) { Intent innerIntent = newIntent.getParcelableExtra(Intent.EXTRA_INTENT); Loading Loading @@ -191,7 +193,8 @@ public class IntentForwarderActivity extends Activity { * Check whether the intent can be forwarded to target user. Return the intent used for * forwarding if it can be forwarded, {@code null} otherwise. */ Intent canForward(Intent incomingIntent, int targetUserId) { static Intent canForward(Intent incomingIntent, int sourceUserId, int targetUserId, IPackageManager packageManager, ContentResolver contentResolver) { Intent forwardIntent = new Intent(incomingIntent); forwardIntent.addFlags( Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); Loading Loading @@ -220,11 +223,11 @@ public class IntentForwarderActivity extends Activity { if (forwardIntent.getSelector() != null) { intentToCheck = forwardIntent.getSelector(); } String resolvedType = intentToCheck.resolveTypeIfNeeded(getContentResolver()); String resolvedType = intentToCheck.resolveTypeIfNeeded(contentResolver); sanitizeIntent(intentToCheck); try { if (mInjector.getIPackageManager(). canForwardTo(intentToCheck, resolvedType, getUserId(), targetUserId)) { if (packageManager.canForwardTo( intentToCheck, resolvedType, sourceUserId, targetUserId)) { return forwardIntent; } } catch (RemoteException e) { Loading Loading @@ -267,7 +270,7 @@ public class IntentForwarderActivity extends Activity { /** * Sanitize the intent in place. */ private void sanitizeIntent(Intent intent) { private static void sanitizeIntent(Intent intent) { // Apps should not be allowed to target a specific package/ component in the target user. intent.setPackage(null); intent.setComponent(null); Loading core/java/com/android/internal/app/ResolverActivity.java +17 −14 Original line number Diff line number Diff line Loading @@ -387,6 +387,11 @@ public class ResolverActivity extends Activity implements | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); rdl.setMaxCollapsedHeight(hasWorkProfile() && ENABLE_TABBED_VIEW ? getResources().getDimensionPixelSize( R.dimen.resolver_empty_state_height_with_tabs) : getResources().getDimensionPixelSize(R.dimen.resolver_empty_state_height)); mResolverDrawerLayout = rdl; } Loading Loading @@ -548,13 +553,6 @@ public class ResolverActivity extends Activity implements applyFooterView(mSystemWindowInsets.bottom); } View emptyView = findViewById(R.id.empty); if (emptyView != null) { emptyView.setPadding(0, 0, 0, mSystemWindowInsets.bottom + getResources().getDimensionPixelSize( R.dimen.chooser_edge_margin_normal) * 2); } return insets.consumeSystemWindowInsets(); } Loading Loading @@ -941,10 +939,13 @@ public class ResolverActivity extends Activity implements } @Override // ResolverListCommunicator public void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing) { public final void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing) { if (isAutolaunching() || maybeAutolaunchActivity()) { return; } if (shouldShowEmptyState(listAdapter)) { mMultiProfilePagerAdapter.showEmptyState(listAdapter); } if (doPostProcessing) { if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() == UserHandle.myUserId()) { Loading Loading @@ -1497,13 +1498,15 @@ public class ResolverActivity extends Activity implements } private void setupViewVisibilities() { int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount(); boolean shouldShowEmptyState = count == 0 && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0; //TODO(arangelov): Handle empty state if (!shouldShowEmptyState) { addUseDifferentAppLabelIfNecessary(mMultiProfilePagerAdapter.getActiveListAdapter()); ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter(); if (!shouldShowEmptyState(activeListAdapter)) { addUseDifferentAppLabelIfNecessary(activeListAdapter); } } private boolean shouldShowEmptyState(ResolverListAdapter listAdapter) { int count = listAdapter.getUnfilteredCount(); return count == 0 && listAdapter.getPlaceholderCount() == 0; } /** Loading core/java/com/android/internal/app/ResolverListAdapter.java +4 −0 Original line number Diff line number Diff line Loading @@ -607,6 +607,10 @@ public class ResolverListAdapter extends BaseAdapter { mIntents, userHandle); } protected List<Intent> getIntents() { return mIntents; } /** * Necessary methods to communicate between {@link ResolverListAdapter} * and {@link ResolverActivity}. Loading Loading
core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +108 −9 Original line number Diff line number Diff line Loading @@ -15,15 +15,25 @@ */ package com.android.internal.app; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.StringRes; import android.app.AppGlobals; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.ResolveInfo; import android.os.UserHandle; import android.os.UserManager; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.PagerAdapter; import com.android.internal.widget.ViewPager; Loading Loading @@ -213,26 +223,115 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { abstract @Nullable ViewGroup getInactiveAdapterView(); boolean rebuildActiveTab(boolean post) { return rebuildTab(getActiveListAdapter(), post); /** * Rebuilds the tab that is currently visible to the user. * <p>Returns {@code true} if rebuild has completed. */ boolean rebuildActiveTab(boolean doPostProcessing) { return rebuildTab(getActiveListAdapter(), doPostProcessing); } boolean rebuildInactiveTab(boolean post) { /** * Rebuilds the tab that is not currently visible to the user, if such one exists. * <p>Returns {@code true} if rebuild has completed. */ boolean rebuildInactiveTab(boolean doPostProcessing) { if (getItemCount() == 1) { return false; } return rebuildTab(getInactiveListAdapter(), post); return rebuildTab(getInactiveListAdapter(), doPostProcessing); } private int userHandleToPageIndex(UserHandle userHandle) { if (userHandle == getPersonalListAdapter().mResolverListController.getUserHandle()) { return PROFILE_PERSONAL; } else { return PROFILE_WORK; } } private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) { UserHandle listUserHandle = activeListAdapter.getUserHandle(); if (UserHandle.myUserId() != listUserHandle.getIdentifier() && !hasAppsInOtherProfile(activeListAdapter)) { // TODO(arangelov): Show empty state UX here UserManager userManager = mContext.getSystemService(UserManager.class); if (listUserHandle == mWorkProfileUserHandle && userManager.isQuietModeEnabled(mWorkProfileUserHandle)) { showEmptyState(activeListAdapter, R.drawable.ic_work_apps_off, R.string.resolver_turn_on_work_apps, R.string.resolver_turn_on_work_apps_explanation, (View.OnClickListener) v -> userManager.requestQuietModeEnabled(false, mWorkProfileUserHandle)); return false; } if (UserHandle.myUserId() != listUserHandle.getIdentifier()) { if (!hasCrossProfileIntents(activeListAdapter.getIntents(), UserHandle.myUserId(), listUserHandle.getIdentifier())) { if (listUserHandle == mPersonalProfileUserHandle) { showEmptyState(activeListAdapter, R.drawable.ic_sharing_disabled, R.string.resolver_cant_share_with_personal_apps, R.string.resolver_cant_share_cross_profile_explanation); } else { showEmptyState(activeListAdapter, R.drawable.ic_sharing_disabled, R.string.resolver_cant_share_with_work_apps, R.string.resolver_cant_share_cross_profile_explanation); } return false; } } return activeListAdapter.rebuildList(doPostProcessing); } void showEmptyState(ResolverListAdapter listAdapter) { UserHandle listUserHandle = listAdapter.getUserHandle(); if (UserHandle.myUserId() == listUserHandle.getIdentifier() || !hasAppsInOtherProfile(listAdapter)) { showEmptyState(listAdapter, R.drawable.ic_no_apps, R.string.resolver_no_apps_available, R.string.resolver_no_apps_available_explanation); } } private void showEmptyState(ResolverListAdapter activeListAdapter, @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes) { showEmptyState(activeListAdapter, iconRes, titleRes, subtitleRes, /* buttonOnClick */ null); } private void showEmptyState(ResolverListAdapter activeListAdapter, @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes, View.OnClickListener buttonOnClick) { ProfileDescriptor descriptor = getItem( userHandleToPageIndex(activeListAdapter.getUserHandle())); descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.GONE); View emptyStateView = descriptor.rootView.findViewById(R.id.resolver_empty_state); emptyStateView.setVisibility(View.VISIBLE); ImageView icon = emptyStateView.findViewById(R.id.resolver_empty_state_icon); icon.setImageResource(iconRes); TextView title = emptyStateView.findViewById(R.id.resolver_empty_state_title); title.setText(titleRes); TextView subtitle = emptyStateView.findViewById(R.id.resolver_empty_state_subtitle); subtitle.setText(subtitleRes); Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button); button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE); button.setOnClickListener(buttonOnClick); } private boolean hasCrossProfileIntents(List<Intent> intents, int source, int target) { IPackageManager packageManager = AppGlobals.getPackageManager(); ContentResolver contentResolver = mContext.getContentResolver(); for (Intent intent : intents) { if (IntentForwarderActivity.canForward(intent, source, target, packageManager, contentResolver) != null) { return true; } } return false; } private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) { Loading
core/java/com/android/internal/app/ChooserActivity.java +91 −25 Original line number Diff line number Diff line Loading @@ -373,7 +373,11 @@ public class ChooserActivity extends ResolverActivity implements Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load" + " within " + mImageLoadTimeoutMillis + "ms."); collapseParentView(); hideContentPreview(); if (hasWorkProfile() && ENABLE_TABBED_VIEW) { hideStickyContentPreview(); } else if (mChooserMultiProfilePagerAdapter.getCurrentRootAdapter() != null) { mChooserMultiProfilePagerAdapter.getCurrentRootAdapter().hideContentPreview(); } mHideParentOnFail = false; } } Loading Loading @@ -829,7 +833,12 @@ public class ChooserActivity extends ResolverActivity implements @Override protected boolean postRebuildList(boolean rebuildCompleted) { updateContentPreview(); updateStickyContentPreview(); if (shouldShowStickyContentPreview() || mChooserMultiProfilePagerAdapter .getCurrentRootAdapter().getContentPreviewRowCount() != 0) { logActionShareWithPreview(); } return postRebuildListInternal(rebuildCompleted); } Loading Loading @@ -978,6 +987,8 @@ public class ChooserActivity extends ResolverActivity implements updateLayoutWidth(R.id.content_preview_text_layout, width, parent); updateLayoutWidth(R.id.content_preview_title_layout, width, parent); updateLayoutWidth(R.id.content_preview_file_layout, width, parent); findViewById(R.id.content_preview_container) .setVisibility(shouldShowStickyContentPreview() ? View.VISIBLE : View.GONE); } private void updateLayoutWidth(int layoutResourceId, int width, View parent) { Loading Loading @@ -2413,14 +2424,14 @@ public class ChooserActivity extends ResolverActivity implements // still zero? then use a default height and leave, which // can happen when there are no targets to show if (rowsToShow == 0 && !shouldShowContentPreview()) { if (rowsToShow == 0 && !shouldShowStickyContentPreview()) { offset += getResources().getDimensionPixelSize( R.dimen.chooser_max_collapsed_height); mResolverDrawerLayout.setCollapsibleHeightReserved(offset); return; } if (shouldShowContentPreview()) { if (shouldShowStickyContentPreview()) { offset += findViewById(R.id.content_preview_container).getHeight(); } Loading Loading @@ -2552,7 +2563,7 @@ public class ChooserActivity extends ResolverActivity implements } private void setupScrollListener() { if (mResolverDrawerLayout == null) { if (mResolverDrawerLayout == null || (hasWorkProfile() && ENABLE_TABBED_VIEW)) { return; } final View chooserHeader = mResolverDrawerLayout.findViewById(R.id.chooser_header); Loading Loading @@ -2597,28 +2608,36 @@ public class ChooserActivity extends ResolverActivity implements return false; } private boolean shouldShowContentPreview() { return mMultiProfilePagerAdapter.getActiveListAdapter().getCount() > 0 && isSendAction(getTargetIntent()); } private void updateContentPreview() { if (shouldShowContentPreview()) { showContentPreview(); /** * The sticky content preview is shown only when we have a tabbed view. It's shown above * the tabs so it is not part of the scrollable list. If we are not in tabbed view, * we instead show the content preview as a regular list item. */ private boolean shouldShowStickyContentPreview() { return hasWorkProfile() && ENABLE_TABBED_VIEW && mMultiProfilePagerAdapter.getListAdapterForUserHandle( UserHandle.of(UserHandle.myUserId())).getCount() > 0 && isSendAction(getTargetIntent()) && getResources().getBoolean(R.bool.sharesheet_show_content_preview); } private void updateStickyContentPreview() { if (shouldShowStickyContentPreview()) { showStickyContentPreview(); } else { hideContentPreview(); hideStickyContentPreview(); } } private void showContentPreview() { private void showStickyContentPreview() { ViewGroup contentPreviewContainer = findViewById(R.id.content_preview_container); contentPreviewContainer.setVisibility(View.VISIBLE); ViewGroup contentPreviewView = createContentPreviewView(contentPreviewContainer); contentPreviewContainer.addView(contentPreviewView); logActionShareWithPreview(); } private void hideContentPreview() { private void hideStickyContentPreview() { ViewGroup contentPreviewContainer = findViewById(R.id.content_preview_container); contentPreviewContainer.removeAllViews(); contentPreviewContainer.setVisibility(View.GONE); Loading @@ -2634,6 +2653,7 @@ public class ChooserActivity extends ResolverActivity implements /** * Used to bind types of individual item including * {@link ChooserGridAdapter#VIEW_TYPE_NORMAL}, * {@link ChooserGridAdapter#VIEW_TYPE_CONTENT_PREVIEW}, * {@link ChooserGridAdapter#VIEW_TYPE_PROFILE}, * and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}. */ Loading Loading @@ -2695,16 +2715,18 @@ public class ChooserActivity extends ResolverActivity implements private int mChooserTargetWidth = 0; private boolean mShowAzLabelIfPoss; private boolean mHideContentPreview = false; private boolean mLayoutRequested = false; private int mFooterHeight = 0; private static final int VIEW_TYPE_DIRECT_SHARE = 0; private static final int VIEW_TYPE_NORMAL = 1; private static final int VIEW_TYPE_PROFILE = 2; private static final int VIEW_TYPE_AZ_LABEL = 3; private static final int VIEW_TYPE_CALLER_AND_RANK = 4; private static final int VIEW_TYPE_FOOTER = 5; private static final int VIEW_TYPE_CONTENT_PREVIEW = 2; private static final int VIEW_TYPE_PROFILE = 3; private static final int VIEW_TYPE_AZ_LABEL = 4; private static final int VIEW_TYPE_CALLER_AND_RANK = 5; private static final int VIEW_TYPE_FOOTER = 6; private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4; private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8; Loading Loading @@ -2765,6 +2787,17 @@ public class ChooserActivity extends ResolverActivity implements return maxTargets; } /** * Hides the list item content preview. * <p>Not to be confused with the sticky content preview which is above the * personal and work tabs. */ public void hideContentPreview() { mHideContentPreview = true; mLayoutRequested = true; notifyDataSetChanged(); } public boolean consumeLayoutRequest() { boolean oldValue = mLayoutRequested; mLayoutRequested = false; Loading @@ -2773,7 +2806,8 @@ public class ChooserActivity extends ResolverActivity implements public int getRowCount() { return (int) ( getProfileRowCount() getContentPreviewRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + getAzLabelRowCount() Loading @@ -2783,7 +2817,33 @@ public class ChooserActivity extends ResolverActivity implements ); } /** * Returns either {@code 0} or {@code 1} depending on whether we want to show the list item * content preview. Not to be confused with the sticky content preview which is above the * personal and work tabs. */ public int getContentPreviewRowCount() { // For the tabbed case we show the sticky content preview above the tabs, // please refer to shouldShowStickyContentPreview if (hasWorkProfile() && ENABLE_TABBED_VIEW) { return 0; } if (!isSendAction(getTargetIntent())) { return 0; } if (mHideContentPreview || mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) { return 0; } return 1; } public int getProfileRowCount() { if (hasWorkProfile() && ENABLE_TABBED_VIEW) { return 0; } return mChooserListAdapter.getOtherProfile() == null ? 0 : 1; } Loading Loading @@ -2815,7 +2875,8 @@ public class ChooserActivity extends ResolverActivity implements @Override public int getItemCount() { return (int) ( getProfileRowCount() getContentPreviewRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + getAzLabelRowCount() Loading @@ -2827,6 +2888,8 @@ public class ChooserActivity extends ResolverActivity implements @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_CONTENT_PREVIEW: return new ItemViewHolder(createContentPreviewView(parent), false); case VIEW_TYPE_PROFILE: return new ItemViewHolder(createProfileView(parent), false); case VIEW_TYPE_AZ_LABEL: Loading Loading @@ -2866,7 +2929,10 @@ public class ChooserActivity extends ResolverActivity implements public int getItemViewType(int position) { int count; int countSum = (count = getProfileRowCount()); int countSum = (count = getContentPreviewRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW; countSum += (count = getProfileRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_PROFILE; countSum += (count = getServiceTargetRowCount()); Loading Loading @@ -3082,7 +3148,7 @@ public class ChooserActivity extends ResolverActivity implements } int getListPosition(int position) { position -= getProfileRowCount(); position -= getContentPreviewRowCount() + getProfileRowCount(); final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount Loading
core/java/com/android/internal/app/IntentForwarderActivity.java +9 −6 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.IPackageManager; Loading Loading @@ -108,7 +109,8 @@ public class IntentForwarderActivity extends Activity { } final int callingUserId = getUserId(); final Intent newIntent = canForward(intentReceived, targetUserId); final Intent newIntent = canForward(intentReceived, getUserId(), targetUserId, mInjector.getIPackageManager(), getContentResolver()); if (newIntent != null) { if (Intent.ACTION_CHOOSER.equals(newIntent.getAction())) { Intent innerIntent = newIntent.getParcelableExtra(Intent.EXTRA_INTENT); Loading Loading @@ -191,7 +193,8 @@ public class IntentForwarderActivity extends Activity { * Check whether the intent can be forwarded to target user. Return the intent used for * forwarding if it can be forwarded, {@code null} otherwise. */ Intent canForward(Intent incomingIntent, int targetUserId) { static Intent canForward(Intent incomingIntent, int sourceUserId, int targetUserId, IPackageManager packageManager, ContentResolver contentResolver) { Intent forwardIntent = new Intent(incomingIntent); forwardIntent.addFlags( Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); Loading Loading @@ -220,11 +223,11 @@ public class IntentForwarderActivity extends Activity { if (forwardIntent.getSelector() != null) { intentToCheck = forwardIntent.getSelector(); } String resolvedType = intentToCheck.resolveTypeIfNeeded(getContentResolver()); String resolvedType = intentToCheck.resolveTypeIfNeeded(contentResolver); sanitizeIntent(intentToCheck); try { if (mInjector.getIPackageManager(). canForwardTo(intentToCheck, resolvedType, getUserId(), targetUserId)) { if (packageManager.canForwardTo( intentToCheck, resolvedType, sourceUserId, targetUserId)) { return forwardIntent; } } catch (RemoteException e) { Loading Loading @@ -267,7 +270,7 @@ public class IntentForwarderActivity extends Activity { /** * Sanitize the intent in place. */ private void sanitizeIntent(Intent intent) { private static void sanitizeIntent(Intent intent) { // Apps should not be allowed to target a specific package/ component in the target user. intent.setPackage(null); intent.setComponent(null); Loading
core/java/com/android/internal/app/ResolverActivity.java +17 −14 Original line number Diff line number Diff line Loading @@ -387,6 +387,11 @@ public class ResolverActivity extends Activity implements | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); rdl.setMaxCollapsedHeight(hasWorkProfile() && ENABLE_TABBED_VIEW ? getResources().getDimensionPixelSize( R.dimen.resolver_empty_state_height_with_tabs) : getResources().getDimensionPixelSize(R.dimen.resolver_empty_state_height)); mResolverDrawerLayout = rdl; } Loading Loading @@ -548,13 +553,6 @@ public class ResolverActivity extends Activity implements applyFooterView(mSystemWindowInsets.bottom); } View emptyView = findViewById(R.id.empty); if (emptyView != null) { emptyView.setPadding(0, 0, 0, mSystemWindowInsets.bottom + getResources().getDimensionPixelSize( R.dimen.chooser_edge_margin_normal) * 2); } return insets.consumeSystemWindowInsets(); } Loading Loading @@ -941,10 +939,13 @@ public class ResolverActivity extends Activity implements } @Override // ResolverListCommunicator public void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing) { public final void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing) { if (isAutolaunching() || maybeAutolaunchActivity()) { return; } if (shouldShowEmptyState(listAdapter)) { mMultiProfilePagerAdapter.showEmptyState(listAdapter); } if (doPostProcessing) { if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() == UserHandle.myUserId()) { Loading Loading @@ -1497,13 +1498,15 @@ public class ResolverActivity extends Activity implements } private void setupViewVisibilities() { int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount(); boolean shouldShowEmptyState = count == 0 && mMultiProfilePagerAdapter.getActiveListAdapter().getPlaceholderCount() == 0; //TODO(arangelov): Handle empty state if (!shouldShowEmptyState) { addUseDifferentAppLabelIfNecessary(mMultiProfilePagerAdapter.getActiveListAdapter()); ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter(); if (!shouldShowEmptyState(activeListAdapter)) { addUseDifferentAppLabelIfNecessary(activeListAdapter); } } private boolean shouldShowEmptyState(ResolverListAdapter listAdapter) { int count = listAdapter.getUnfilteredCount(); return count == 0 && listAdapter.getPlaceholderCount() == 0; } /** Loading
core/java/com/android/internal/app/ResolverListAdapter.java +4 −0 Original line number Diff line number Diff line Loading @@ -607,6 +607,10 @@ public class ResolverListAdapter extends BaseAdapter { mIntents, userHandle); } protected List<Intent> getIntents() { return mIntents; } /** * Necessary methods to communicate between {@link ResolverListAdapter} * and {@link ResolverActivity}. Loading