Source code
package android.support.v7.internal.widget;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.database.DataSetObservable;
import android.os.AsyncTask;
import android.support.v4.os.AsyncTaskCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
public class ActivityChooserModel extends DataSetObservable {
private static final String ATTRIBUTE_ACTIVITY = "activity";
private static final String ATTRIBUTE_TIME = "time";
private static final String ATTRIBUTE_WEIGHT = "weight";
private static final boolean DEBUG = false;
private static final int DEFAULT_ACTIVITY_INFLATION = 5;
private static final float DEFAULT_HISTORICAL_RECORD_WEIGHT = 1.0f;
public static final String DEFAULT_HISTORY_FILE_NAME = "activity_choser_model_history.xml";
public static final int DEFAULT_HISTORY_MAX_LENGTH = 50;
private static final String HISTORY_FILE_EXTENSION = ".xml";
private static final int INVALID_INDEX = -1;
private static final String LOG_TAG = ActivityChooserModel.class.getSimpleName();
private static final String TAG_HISTORICAL_RECORD = "historical-record";
private static final String TAG_HISTORICAL_RECORDS = "historical-records";
private static final Map<String, ActivityChooserModel> sDataModelRegistry = new HashMap();
private static final Object sRegistryLock = new Object();
private final List<ActivityResolveInfo> mActivities = new ArrayList();
private OnChooseActivityListener mActivityChoserModelPolicy;
private ActivitySorter mActivitySorter = new DefaultSorter();
private boolean mCanReadHistoricalData = true;
private final Context mContext;
private final List<HistoricalRecord> mHistoricalRecords = new ArrayList();
private boolean mHistoricalRecordsChanged = true;
private final String mHistoryFileName;
private int mHistoryMaxSize = 50;
private final Object mInstanceLock = new Object();
private Intent mIntent;
private boolean mReadShareHistoryCalled = false;
private boolean mReloadActivities = false;
public interface ActivityChooserModelClient {
void setActivityChooserModel(ActivityChooserModel activityChooserModel);
}
public final class ActivityResolveInfo implements Comparable<ActivityResolveInfo> {
public final ResolveInfo resolveInfo;
public float weight;
public ActivityResolveInfo(ResolveInfo resolveInfo) {
this.resolveInfo = resolveInfo;
}
public int hashCode() {
return Float.floatToIntBits(this.weight) + 31;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
if (Float.floatToIntBits(this.weight) != Float.floatToIntBits(((ActivityResolveInfo) obj).weight)) {
return false;
}
return true;
}
public int compareTo(ActivityResolveInfo another) {
return Float.floatToIntBits(another.weight) - Float.floatToIntBits(this.weight);
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[");
builder.append("resolveInfo:").append(this.resolveInfo.toString());
builder.append("; weight:").append(new BigDecimal((double) this.weight));
builder.append("]");
return builder.toString();
}
}
public interface ActivitySorter {
void sort(Intent intent, List<ActivityResolveInfo> list, List<HistoricalRecord> list2);
}
public static final class HistoricalRecord {
public final ComponentName activity;
public final long time;
public final float weight;
public HistoricalRecord(String activityName, long time, float weight) {
this(ComponentName.unflattenFromString(activityName), time, weight);
}
public HistoricalRecord(ComponentName activityName, long time, float weight) {
this.activity = activityName;
this.time = time;
this.weight = weight;
}
public int hashCode() {
return (((((this.activity == null ? 0 : this.activity.hashCode()) + 31) * 31) + ((int) (this.time ^ (this.time >>> 32)))) * 31) + Float.floatToIntBits(this.weight);
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
HistoricalRecord other = (HistoricalRecord) obj;
if (this.activity == null) {
if (other.activity != null) {
return false;
}
} else if (!this.activity.equals(other.activity)) {
return false;
}
if (this.time != other.time) {
return false;
}
if (Float.floatToIntBits(this.weight) != Float.floatToIntBits(other.weight)) {
return false;
}
return true;
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[");
builder.append("; activity:").append(this.activity);
builder.append("; time:").append(this.time);
builder.append("; weight:").append(new BigDecimal((double) this.weight));
builder.append("]");
return builder.toString();
}
}
public interface OnChooseActivityListener {
boolean onChooseActivity(ActivityChooserModel activityChooserModel, Intent intent);
}
private final class PersistHistoryAsyncTask extends AsyncTask<Object, Void, Void> {
private PersistHistoryAsyncTask() {
}
public Void doInBackground(Object... args) {
List<HistoricalRecord> historicalRecords = args[0];
String hostoryFileName = args[1];
try {
FileOutputStream fos = ActivityChooserModel.this.mContext.openFileOutput(hostoryFileName, 0);
XmlSerializer serializer = Xml.newSerializer();
try {
serializer.setOutput(fos, null);
serializer.startDocument("UTF-8", Boolean.valueOf(true));
serializer.startTag(null, ActivityChooserModel.TAG_HISTORICAL_RECORDS);
int recordCount = historicalRecords.size();
for (int i = 0; i < recordCount; i++) {
HistoricalRecord record = (HistoricalRecord) historicalRecords.remove(0);
serializer.startTag(null, ActivityChooserModel.TAG_HISTORICAL_RECORD);
serializer.attribute(null, ActivityChooserModel.ATTRIBUTE_ACTIVITY, record.activity.flattenToString());
serializer.attribute(null, ActivityChooserModel.ATTRIBUTE_TIME, String.valueOf(record.time));
serializer.attribute(null, ActivityChooserModel.ATTRIBUTE_WEIGHT, String.valueOf(record.weight));
serializer.endTag(null, ActivityChooserModel.TAG_HISTORICAL_RECORD);
}
serializer.endTag(null, ActivityChooserModel.TAG_HISTORICAL_RECORDS);
serializer.endDocument();
ActivityChooserModel.this.mCanReadHistoricalData = true;
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
}
}
} catch (IllegalArgumentException iae) {
Log.e(ActivityChooserModel.LOG_TAG, "Error writing historical recrod file: " + ActivityChooserModel.this.mHistoryFileName, iae);
ActivityChooserModel.this.mCanReadHistoricalData = true;
if (fos != null) {
try {
fos.close();
} catch (IOException e2) {
}
}
} catch (IllegalStateException ise) {
Log.e(ActivityChooserModel.LOG_TAG, "Error writing historical recrod file: " + ActivityChooserModel.this.mHistoryFileName, ise);
ActivityChooserModel.this.mCanReadHistoricalData = true;
if (fos != null) {
try {
fos.close();
} catch (IOException e3) {
}
}
} catch (IOException ioe) {
Log.e(ActivityChooserModel.LOG_TAG, "Error writing historical recrod file: " + ActivityChooserModel.this.mHistoryFileName, ioe);
ActivityChooserModel.this.mCanReadHistoricalData = true;
if (fos != null) {
try {
fos.close();
} catch (IOException e4) {
}
}
} catch (Throwable th) {
ActivityChooserModel.this.mCanReadHistoricalData = true;
if (fos != null) {
try {
fos.close();
} catch (IOException e5) {
}
}
}
return null;
} catch (FileNotFoundException fnfe) {
Log.e(ActivityChooserModel.LOG_TAG, "Error writing historical recrod file: " + hostoryFileName, fnfe);
return null;
}
}
}
private final class DefaultSorter implements ActivitySorter {
private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f;
private final Map<ComponentName, ActivityResolveInfo> mPackageNameToActivityMap;
private DefaultSorter() {
this.mPackageNameToActivityMap = new HashMap();
}
public void sort(Intent intent, List<ActivityResolveInfo> activities, List<HistoricalRecord> historicalRecords) {
int i;
Map<ComponentName, ActivityResolveInfo> componentNameToActivityMap = this.mPackageNameToActivityMap;
componentNameToActivityMap.clear();
int activityCount = activities.size();
for (i = 0; i < activityCount; i++) {
ActivityResolveInfo activity = (ActivityResolveInfo) activities.get(i);
activity.weight = 0.0f;
componentNameToActivityMap.put(new ComponentName(activity.resolveInfo.activityInfo.packageName, activity.resolveInfo.activityInfo.name), activity);
}
int lastShareIndex = historicalRecords.size() - 1;
float nextRecordWeight = ActivityChooserModel.DEFAULT_HISTORICAL_RECORD_WEIGHT;
for (i = lastShareIndex; i >= 0; i--) {
HistoricalRecord historicalRecord = (HistoricalRecord) historicalRecords.get(i);
activity = (ActivityResolveInfo) componentNameToActivityMap.get(historicalRecord.activity);
if (activity != null) {
activity.weight += historicalRecord.weight * nextRecordWeight;
nextRecordWeight *= WEIGHT_DECAY_COEFFICIENT;
}
}
Collections.sort(activities);
}
}
public static ActivityChooserModel get(Context context, String historyFileName) {
ActivityChooserModel dataModel;
synchronized (sRegistryLock) {
dataModel = (ActivityChooserModel) sDataModelRegistry.get(historyFileName);
if (dataModel == null) {
dataModel = new ActivityChooserModel(context, historyFileName);
sDataModelRegistry.put(historyFileName, dataModel);
}
}
return dataModel;
}
private ActivityChooserModel(Context context, String historyFileName) {
this.mContext = context.getApplicationContext();
if (TextUtils.isEmpty(historyFileName) || historyFileName.endsWith(HISTORY_FILE_EXTENSION)) {
this.mHistoryFileName = historyFileName;
} else {
this.mHistoryFileName = historyFileName + HISTORY_FILE_EXTENSION;
}
}
public void setIntent(Intent intent) {
synchronized (this.mInstanceLock) {
if (this.mIntent == intent) {
return;
}
this.mIntent = intent;
this.mReloadActivities = true;
ensureConsistentState();
}
}
public Intent getIntent() {
Intent intent;
synchronized (this.mInstanceLock) {
intent = this.mIntent;
}
return intent;
}
public int getActivityCount() {
int size;
synchronized (this.mInstanceLock) {
ensureConsistentState();
size = this.mActivities.size();
}
return size;
}
public ResolveInfo getActivity(int index) {
ResolveInfo resolveInfo;
synchronized (this.mInstanceLock) {
ensureConsistentState();
resolveInfo = ((ActivityResolveInfo) this.mActivities.get(index)).resolveInfo;
}
return resolveInfo;
}
public int getActivityIndex(ResolveInfo activity) {
int i;
synchronized (this.mInstanceLock) {
ensureConsistentState();
List<ActivityResolveInfo> activities = this.mActivities;
int activityCount = activities.size();
i = 0;
while (i < activityCount) {
if (((ActivityResolveInfo) activities.get(i)).resolveInfo == activity) {
break;
}
i++;
}
i = -1;
}
return i;
}
public Intent chooseActivity(int index) {
synchronized (this.mInstanceLock) {
if (this.mIntent == null) {
return null;
}
ensureConsistentState();
ActivityResolveInfo chosenActivity = (ActivityResolveInfo) this.mActivities.get(index);
ComponentName chosenName = new ComponentName(chosenActivity.resolveInfo.activityInfo.packageName, chosenActivity.resolveInfo.activityInfo.name);
Intent choiceIntent = new Intent(this.mIntent);
choiceIntent.setComponent(chosenName);
if (this.mActivityChoserModelPolicy != null) {
if (this.mActivityChoserModelPolicy.onChooseActivity(this, new Intent(choiceIntent))) {
return null;
}
}
addHisoricalRecord(new HistoricalRecord(chosenName, System.currentTimeMillis(), (float) DEFAULT_HISTORICAL_RECORD_WEIGHT));
return choiceIntent;
}
}
public void setOnChooseActivityListener(OnChooseActivityListener listener) {
synchronized (this.mInstanceLock) {
this.mActivityChoserModelPolicy = listener;
}
}
public ResolveInfo getDefaultActivity() {
synchronized (this.mInstanceLock) {
ensureConsistentState();
if (this.mActivities.isEmpty()) {
return null;
}
ResolveInfo resolveInfo = ((ActivityResolveInfo) this.mActivities.get(0)).resolveInfo;
return resolveInfo;
}
}
public void setDefaultActivity(int index) {
synchronized (this.mInstanceLock) {
float weight;
ensureConsistentState();
ActivityResolveInfo newDefaultActivity = (ActivityResolveInfo) this.mActivities.get(index);
ActivityResolveInfo oldDefaultActivity = (ActivityResolveInfo) this.mActivities.get(0);
if (oldDefaultActivity != null) {
weight = (oldDefaultActivity.weight - newDefaultActivity.weight) + 5.0f;
} else {
weight = DEFAULT_HISTORICAL_RECORD_WEIGHT;
}
addHisoricalRecord(new HistoricalRecord(new ComponentName(newDefaultActivity.resolveInfo.activityInfo.packageName, newDefaultActivity.resolveInfo.activityInfo.name), System.currentTimeMillis(), weight));
}
}
private void persistHistoricalDataIfNeeded() {
if (!this.mReadShareHistoryCalled) {
throw new IllegalStateException("No preceding call to #readHistoricalData");
} else if (this.mHistoricalRecordsChanged) {
this.mHistoricalRecordsChanged = false;
if (!TextUtils.isEmpty(this.mHistoryFileName)) {
AsyncTaskCompat.executeParallel(new PersistHistoryAsyncTask(), new ArrayList(this.mHistoricalRecords), this.mHistoryFileName);
}
}
}
/* JADX WARNING: inconsistent code. */
/* Code decompiled incorrectly, please refer to instructions dump. */
public void setActivitySorter(android.support.v7.internal.widget.ActivityChooserModel.ActivitySorter r3) {
/*
r2 = this;
r1 = r2.mInstanceLock;
monitor-enter(r1);
r0 = r2.mActivitySorter; Catch:{ all -> 0x0016 }
if (r0 != r3) goto L_0x0009;
L_0x0007:
monitor-exit(r1); Catch:{ all -> 0x0016 }
L_0x0008:
return;
L_0x0009:
r2.mActivitySorter = r3; Catch:{ all -> 0x0016 }
r0 = r2.sortActivitiesIfNeeded(); Catch:{ all -> 0x0016 }
if (r0 == 0) goto L_0x0014;
L_0x0011:
r2.notifyChanged(); Catch:{ all -> 0x0016 }
L_0x0014:
monitor-exit(r1); Catch:{ all -> 0x0016 }
goto L_0x0008;
L_0x0016:
r0 = move-exception;
monitor-exit(r1); Catch:{ all -> 0x0016 }
throw r0;
*/
throw new UnsupportedOperationException("Method not decompiled: android.support.v7.internal.widget.ActivityChooserModel.setActivitySorter(android.support.v7.internal.widget.ActivityChooserModel$ActivitySorter):void");
}
/* JADX WARNING: inconsistent code. */
/* Code decompiled incorrectly, please refer to instructions dump. */
public void setHistoryMaxSize(int r3) {
/*
r2 = this;
r1 = r2.mInstanceLock;
monitor-enter(r1);
r0 = r2.mHistoryMaxSize; Catch:{ all -> 0x0019 }
if (r0 != r3) goto L_0x0009;
L_0x0007:
monitor-exit(r1); Catch:{ all -> 0x0019 }
L_0x0008:
return;
L_0x0009:
r2.mHistoryMaxSize = r3; Catch:{ all -> 0x0019 }
r2.pruneExcessiveHistoricalRecordsIfNeeded(); Catch:{ all -> 0x0019 }
r0 = r2.sortActivitiesIfNeeded(); Catch:{ all -> 0x0019 }
if (r0 == 0) goto L_0x0017;
L_0x0014:
r2.notifyChanged(); Catch:{ all -> 0x0019 }
L_0x0017:
monitor-exit(r1); Catch:{ all -> 0x0019 }
goto L_0x0008;
L_0x0019:
r0 = move-exception;
monitor-exit(r1); Catch:{ all -> 0x0019 }
throw r0;
*/
throw new UnsupportedOperationException("Method not decompiled: android.support.v7.internal.widget.ActivityChooserModel.setHistoryMaxSize(int):void");
}
public int getHistoryMaxSize() {
int i;
synchronized (this.mInstanceLock) {
i = this.mHistoryMaxSize;
}
return i;
}
public int getHistorySize() {
int size;
synchronized (this.mInstanceLock) {
ensureConsistentState();
size = this.mHistoricalRecords.size();
}
return size;
}
private void ensureConsistentState() {
boolean stateChanged = loadActivitiesIfNeeded() | readHistoricalDataIfNeeded();
pruneExcessiveHistoricalRecordsIfNeeded();
if (stateChanged) {
sortActivitiesIfNeeded();
notifyChanged();
}
}
private boolean sortActivitiesIfNeeded() {
if (this.mActivitySorter == null || this.mIntent == null || this.mActivities.isEmpty() || this.mHistoricalRecords.isEmpty()) {
return false;
}
this.mActivitySorter.sort(this.mIntent, this.mActivities, Collections.unmodifiableList(this.mHistoricalRecords));
return true;
}
private boolean loadActivitiesIfNeeded() {
if (!this.mReloadActivities || this.mIntent == null) {
return false;
}
this.mReloadActivities = false;
this.mActivities.clear();
List<ResolveInfo> resolveInfos = this.mContext.getPackageManager().queryIntentActivities(this.mIntent, 0);
int resolveInfoCount = resolveInfos.size();
for (int i = 0; i < resolveInfoCount; i++) {
this.mActivities.add(new ActivityResolveInfo((ResolveInfo) resolveInfos.get(i)));
}
return true;
}
private boolean readHistoricalDataIfNeeded() {
if (!this.mCanReadHistoricalData || !this.mHistoricalRecordsChanged || TextUtils.isEmpty(this.mHistoryFileName)) {
return false;
}
this.mCanReadHistoricalData = false;
this.mReadShareHistoryCalled = true;
readHistoricalDataImpl();
return true;
}
private boolean addHisoricalRecord(HistoricalRecord historicalRecord) {
boolean added = this.mHistoricalRecords.add(historicalRecord);
if (added) {
this.mHistoricalRecordsChanged = true;
pruneExcessiveHistoricalRecordsIfNeeded();
persistHistoricalDataIfNeeded();
sortActivitiesIfNeeded();
notifyChanged();
}
return added;
}
private void pruneExcessiveHistoricalRecordsIfNeeded() {
int pruneCount = this.mHistoricalRecords.size() - this.mHistoryMaxSize;
if (pruneCount > 0) {
this.mHistoricalRecordsChanged = true;
for (int i = 0; i < pruneCount; i++) {
HistoricalRecord historicalRecord = (HistoricalRecord) this.mHistoricalRecords.remove(0);
}
}
}
private void readHistoricalDataImpl() {
FileInputStream fis = null;
try {
fis = this.mContext.openFileInput(this.mHistoryFileName);
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, "UTF-8");
int type = 0;
while (type != 1 && type != 2) {
type = parser.next();
}
if (TAG_HISTORICAL_RECORDS.equals(parser.getName())) {
List<HistoricalRecord> historicalRecords = this.mHistoricalRecords;
historicalRecords.clear();
while (true) {
type = parser.next();
if (type == 1) {
break;
} else if (!(type == 3 || type == 4)) {
if (TAG_HISTORICAL_RECORD.equals(parser.getName())) {
historicalRecords.add(new HistoricalRecord(parser.getAttributeValue(null, ATTRIBUTE_ACTIVITY), Long.parseLong(parser.getAttributeValue(null, ATTRIBUTE_TIME)), Float.parseFloat(parser.getAttributeValue(null, ATTRIBUTE_WEIGHT))));
} else {
throw new XmlPullParserException("Share records file not well-formed.");
}
}
}
if (fis != null) {
try {
fis.close();
return;
} catch (IOException e) {
return;
}
}
return;
}
throw new XmlPullParserException("Share records file does not start with historical-records tag.");
} catch (XmlPullParserException xppe) {
Log.e(LOG_TAG, "Error reading historical recrod file: " + this.mHistoryFileName, xppe);
if (fis != null) {
try {
fis.close();
} catch (IOException e2) {
}
}
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error reading historical recrod file: " + this.mHistoryFileName, ioe);
if (fis != null) {
try {
fis.close();
} catch (IOException e3) {
}
}
} catch (Throwable th) {
if (fis != null) {
try {
fis.close();
} catch (IOException e4) {
}
}
}
} catch (FileNotFoundException e5) {
}
}
}