summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt5
-rw-r--r--core/java/android/widget/ActivityChooserModel.java59
-rw-r--r--core/java/android/widget/ActivityChooserView.java35
-rw-r--r--core/java/android/widget/AdapterView.java3
-rw-r--r--core/java/android/widget/ShareActionProvider.java75
5 files changed, 168 insertions, 9 deletions
diff --git a/api/current.txt b/api/current.txt
index 1180440..861677c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26480,11 +26480,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();
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 4b0a6da..9fea506 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -131,6 +131,30 @@ public class ActivityChooserModel extends DataSetObservable {
}
/**
+ * 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.
*/
private static final boolean DEBUG = false;
@@ -287,6 +311,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
* the same file name will return the same model instance. If no such instance is present
@@ -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,17 +467,37 @@ 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
* handle the intent.
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 45d73af..556414c 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -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);
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 9f5737e..f267458c 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -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);
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 665109a..6e29024 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -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;
@@ -73,6 +74,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.
*/
private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4;
@@ -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.
*
@@ -114,6 +140,21 @@ public class ShareActionProvider extends ActionProvider {
}
/**
+ * 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}
*/
@Override
@@ -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;
+ }
+ }
}