Merge "Adding a callback to ShareActionProvider + make ActivityChooserView popup hide on action bar hide."

This commit is contained in:
Svetoslav Ganov
2011-08-22 09:35:00 -07:00
committed by Android (Google) Code Review
5 changed files with 168 additions and 9 deletions

View File

@@ -26694,11 +26694,16 @@ package android.widget {
public class ShareActionProvider extends android.view.ActionProvider {
ctor public ShareActionProvider(android.content.Context);
method public android.view.View onCreateActionView();
method public void setOnShareTargetSelectedListener(android.widget.ShareActionProvider.OnShareTargetSelectedListener);
method public void setShareHistoryFileName(java.lang.String);
method public void setShareIntent(android.content.Intent);
field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
}
public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
method public abstract boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
}
public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[]);
method public int getCount();

View File

@@ -130,6 +130,30 @@ public class ActivityChooserModel extends DataSetObservable {
List<HistoricalRecord> historicalRecords);
}
/**
* Listener for choosing an activity.
*/
public interface OnChooseActivityListener {
/**
* Called when an activity has been chosen. The client can decide whether
* an activity can be chosen and if so the caller of
* {@link ActivityChooserModel#chooseActivity(int)} will receive and {@link Intent}
* for launching it.
* <p>
* <strong>Note:</strong> Modifying the intent is not permitted and
* any changes to the latter will be ignored.
* </p>
*
* @param host The listener's host model.
* @param intent The intent for launching the chosen activity.
* @return Whether the intent is handled and should not be delivered to clients.
*
* @see ActivityChooserModel#chooseActivity(int)
*/
public boolean onChooseActivity(ActivityChooserModel host, Intent intent);
}
/**
* Flag for selecting debug mode.
*/
@@ -286,6 +310,11 @@ public class ActivityChooserModel extends DataSetObservable {
*/
private final Handler mHandler = new Handler();
/**
* Policy for controlling how the model handles chosen activities.
*/
private OnChooseActivityListener mActivityChoserModelPolicy;
/**
* Gets the data model backed by the contents of the provided file with historical data.
* Note that only one data model is backed by a given file, thus multiple calls with
@@ -426,9 +455,11 @@ public class ActivityChooserModel extends DataSetObservable {
* the client solely to let additional customization before the start.
* </p>
*
* @return Whether adding succeeded.
* @return An {@link Intent} for launching the activity or null if the
* policy has consumed the intent.
*
* @see HistoricalRecord
* @see OnChooseActivityListener
*/
public Intent chooseActivity(int index) {
ActivityResolveInfo chosenActivity = mActivites.get(index);
@@ -436,16 +467,36 @@ public class ActivityChooserModel extends DataSetObservable {
ComponentName chosenName = new ComponentName(
chosenActivity.resolveInfo.activityInfo.packageName,
chosenActivity.resolveInfo.activityInfo.name);
HistoricalRecord historicalRecord = new HistoricalRecord(chosenName,
System.currentTimeMillis(), DEFAULT_HISTORICAL_RECORD_WEIGHT);
addHisoricalRecord(historicalRecord);
Intent choiceIntent = new Intent(mIntent);
choiceIntent.setComponent(chosenName);
if (mActivityChoserModelPolicy != null) {
// Do not allow the policy to change the intent.
Intent choiceIntentCopy = new Intent(choiceIntent);
final boolean handled = mActivityChoserModelPolicy.onChooseActivity(this,
choiceIntentCopy);
if (handled) {
return null;
}
}
HistoricalRecord historicalRecord = new HistoricalRecord(chosenName,
System.currentTimeMillis(), DEFAULT_HISTORICAL_RECORD_WEIGHT);
addHisoricalRecord(historicalRecord);
return choiceIntent;
}
/**
* Sets the listener for choosing an activity.
*
* @param listener The listener.
*/
public void setOnChooseActivityListener(OnChooseActivityListener listener) {
mActivityChoserModelPolicy = listener;
}
/**
* Gets the default activity, The default activity is defined as the one
* with highest rank i.e. the first one in the list of activities that can

View File

@@ -29,6 +29,8 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
import com.android.internal.R;
@@ -115,6 +117,19 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
};
private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (isShowingPopup()) {
if (!isShown()) {
getListPopupWindow().dismiss();
} else {
getListPopupWindow().show();
}
}
}
};
/**
* Popup window for showing the activity overflow list.
*/
@@ -261,6 +276,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
throw new IllegalStateException("No data model. Did you call #setDataModel?");
}
getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
mAdapter.setMaxActivityCount(maxActivityCount);
final int activityCount = mAdapter.getActivityCount();
@@ -292,6 +309,10 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
public boolean dismissPopup() {
if (isShowingPopup()) {
getListPopupWindow().dismiss();
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
}
}
return true;
}
@@ -322,6 +343,10 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
if (dataModel != null) {
dataModel.unregisterObserver(mModelDataSetOberver);
}
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
}
mIsAttachedToWindow = false;
}
@@ -433,8 +458,10 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
} else {
// The first item in the model is default action => adjust index
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1);
mContext.startActivity(launchIntent);
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1);
if (launchIntent != null) {
mContext.startActivity(launchIntent);
}
}
} break;
default:
@@ -449,7 +476,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
mContext.startActivity(launchIntent);
if (launchIntent != null) {
mContext.startActivity(launchIntent);
}
} else if (view == mExpandActivityOverflowButton) {
mIsSelectingDefaultActivity = false;
showPopupUnchecked(mInitialActivityCount);

View File

@@ -23,11 +23,11 @@ import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.accessibility.AccessibilityEvent;
@@ -278,6 +278,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
*/
public boolean performItemClick(View view, int position, long id) {
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnItemClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnItemClickListener.onItemClick(this, view, position, id);

View File

@@ -28,6 +28,7 @@ import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
import android.view.View;
import android.widget.ActivityChooserModel.OnChooseActivityListener;
import com.android.internal.R;
@@ -72,6 +73,27 @@ import com.android.internal.R;
*/
public class ShareActionProvider extends ActionProvider {
/**
* Listener for the event of selecting a share target.
*/
public interface OnShareTargetSelectedListener {
/**
* Called when a share target has been selected. The client can
* decide whether to handle the intent or rely on the default
* behavior which is launching it.
* <p>
* <strong>Note:</strong> Modifying the intent is not permitted and
* any changes to the latter will be ignored.
* </p>
*
* @param source The source of the notification.
* @param intent The intent for launching the chosen share target.
* @return Whether the client has handled the intent.
*/
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent);
}
/**
* The default for the maximal number of activities shown in the sub-menu.
*/
@@ -103,6 +125,10 @@ public class ShareActionProvider extends ActionProvider {
*/
private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME;
private OnShareTargetSelectedListener mOnShareTargetSelectedListener;
private OnChooseActivityListener mOnChooseActivityListener;
/**
* Creates a new instance.
*
@@ -113,6 +139,21 @@ public class ShareActionProvider extends ActionProvider {
mContext = context;
}
/**
* Sets a listener to be notified when a share target has been selected.
* The listener can optionally decide to handle the selection and
* not rely on the default behavior which is to launch the activity.
* <p>
* <strong>Note:</strong> If you choose the backing share history file
* you will still be notified in this callback.
* </p>
* @param listener The listener.
*/
public void setOnShareTargetSelectedListener(OnShareTargetSelectedListener listener) {
mOnShareTargetSelectedListener = listener;
setActivityChooserPolicyIfNeeded();
}
/**
* {@inheritDoc}
*/
@@ -192,6 +233,7 @@ public class ShareActionProvider extends ActionProvider {
*/
public void setShareHistoryFileName(String shareHistoryFile) {
mShareHistoryFileName = shareHistoryFile;
setActivityChooserPolicyIfNeeded();
}
/**
@@ -229,8 +271,39 @@ public class ShareActionProvider extends ActionProvider {
mShareHistoryFileName);
final int itemId = item.getItemId();
Intent launchIntent = dataModel.chooseActivity(itemId);
mContext.startActivity(launchIntent);
if (launchIntent != null) {
mContext.startActivity(launchIntent);
}
return true;
}
}
/**
* Set the activity chooser policy of the model backed by the current
* share history file if needed which is if there is a registered callback.
*/
private void setActivityChooserPolicyIfNeeded() {
if (mOnShareTargetSelectedListener == null) {
return;
}
if (mOnChooseActivityListener == null) {
mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
}
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
}
/**
* Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
*/
private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
@Override
public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
if (mOnShareTargetSelectedListener != null) {
return mOnShareTargetSelectedListener.onShareTargetSelected(
ShareActionProvider.this, intent);
}
return false;
}
}
}