From ca858797816be82e2b1e2b88dea17b20e52d8429 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Sat, 5 May 2012 18:00:26 -0700 Subject: ActivityChooserModel does not handle package changes on the thread that created it. 1. The model is using a package monitor to observe changes in packages (adding/memoving/etc) to update its internal state for which it then notifies its clients. However, the monitor is called from a binder thread and the work has to be off handed on the thread that created the model. Hence, clients do not need to worry about using the the model from the UI thread since the change callback may touch the UI from another thread. bug:6386152 Change-Id: I882a0f4104907f64de64a95ece585052bba457d6 --- core/java/android/widget/ActivityChooserModel.java | 547 +++++++++------------ 1 file changed, 244 insertions(+), 303 deletions(-) (limited to 'core/java/android/widget/ActivityChooserModel.java') diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index c53b5f6..91d7447 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -21,9 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.database.DataSetObservable; -import android.database.DataSetObserver; import android.os.AsyncTask; -import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.util.Xml; @@ -42,10 +40,8 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** *

@@ -239,7 +235,7 @@ public class ActivityChooserModel extends DataSetObservable { /** * List of activities that can handle the current intent. */ - private final List mActivites = new ArrayList(); + private final List mActivities = new ArrayList(); /** * List with historical choice records. @@ -278,18 +274,18 @@ public class ActivityChooserModel extends DataSetObservable { /** * Flag whether choice history can be read. In general many clients can - * share the same data model and {@link #readHistoricalData()} may be called + * share the same data model and {@link #readHistoricalDataIfNeeded()} may be called * by arbitrary of them any number of times. Therefore, this class guarantees * that the very first read succeeds and subsequent reads can be performed - * only after a call to {@link #persistHistoricalData()} followed by change + * only after a call to {@link #persistHistoricalDataIfNeeded()} followed by change * of the share records. */ private boolean mCanReadHistoricalData = true; /** * Flag whether the choice history was read. This is used to enforce that - * before calling {@link #persistHistoricalData()} a call to - * {@link #persistHistoricalData()} has been made. This aims to avoid a + * before calling {@link #persistHistoricalDataIfNeeded()} a call to + * {@link #persistHistoricalDataIfNeeded()} has been made. This aims to avoid a * scenario in which a choice history file exits, it is not read yet and * it is overwritten. Note that always all historical records are read in * full and the file is rewritten. This is necessary since we need to @@ -299,16 +295,16 @@ public class ActivityChooserModel extends DataSetObservable { /** * Flag whether the choice records have changed. In general many clients can - * share the same data model and {@link #persistHistoricalData()} may be called + * share the same data model and {@link #persistHistoricalDataIfNeeded()} may be called * by arbitrary of them any number of times. Therefore, this class guarantees * that choice history will be persisted only if it has changed. */ private boolean mHistoricalRecordsChanged = true; /** - * Hander for scheduling work on client tread. + * Flag whether to reload the activities for the current intent. */ - private final Handler mHandler = new Handler(); + private boolean mReloadActivities = false; /** * Policy for controlling how the model handles chosen activities. @@ -346,7 +342,6 @@ public class ActivityChooserModel extends DataSetObservable { dataModel = new ActivityChooserModel(context, historyFileName); sDataModelRegistry.put(historyFileName, dataModel); } - dataModel.readHistoricalData(); return dataModel; } } @@ -383,7 +378,8 @@ public class ActivityChooserModel extends DataSetObservable { return; } mIntent = intent; - loadActivitiesLocked(); + mReloadActivities = true; + ensureConsistentState(); } } @@ -407,7 +403,8 @@ public class ActivityChooserModel extends DataSetObservable { */ public int getActivityCount() { synchronized (mInstanceLock) { - return mActivites.size(); + ensureConsistentState(); + return mActivities.size(); } } @@ -421,7 +418,8 @@ public class ActivityChooserModel extends DataSetObservable { */ public ResolveInfo getActivity(int index) { synchronized (mInstanceLock) { - return mActivites.get(index).resolveInfo; + ensureConsistentState(); + return mActivities.get(index).resolveInfo; } } @@ -433,15 +431,18 @@ public class ActivityChooserModel extends DataSetObservable { * @return The index if found, -1 otherwise. */ public int getActivityIndex(ResolveInfo activity) { - List activities = mActivites; - final int activityCount = activities.size(); - for (int i = 0; i < activityCount; i++) { - ActivityResolveInfo currentActivity = activities.get(i); - if (currentActivity.resolveInfo == activity) { - return i; + synchronized (mInstanceLock) { + ensureConsistentState(); + List activities = mActivities; + final int activityCount = activities.size(); + for (int i = 0; i < activityCount; i++) { + ActivityResolveInfo currentActivity = activities.get(i); + if (currentActivity.resolveInfo == activity) { + return i; + } } + return INVALID_INDEX; } - return INVALID_INDEX; } /** @@ -462,30 +463,34 @@ public class ActivityChooserModel extends DataSetObservable { * @see OnChooseActivityListener */ public Intent chooseActivity(int index) { - ActivityResolveInfo chosenActivity = mActivites.get(index); + synchronized (mInstanceLock) { + ensureConsistentState(); - ComponentName chosenName = new ComponentName( - chosenActivity.resolveInfo.activityInfo.packageName, - chosenActivity.resolveInfo.activityInfo.name); + ActivityResolveInfo chosenActivity = mActivities.get(index); - Intent choiceIntent = new Intent(mIntent); - choiceIntent.setComponent(chosenName); + ComponentName chosenName = new ComponentName( + chosenActivity.resolveInfo.activityInfo.packageName, + chosenActivity.resolveInfo.activityInfo.name); - 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; + 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); + HistoricalRecord historicalRecord = new HistoricalRecord(chosenName, + System.currentTimeMillis(), DEFAULT_HISTORICAL_RECORD_WEIGHT); + addHisoricalRecord(historicalRecord); - return choiceIntent; + return choiceIntent; + } } /** @@ -494,7 +499,9 @@ public class ActivityChooserModel extends DataSetObservable { * @param listener The listener. */ public void setOnChooseActivityListener(OnChooseActivityListener listener) { - mActivityChoserModelPolicy = listener; + synchronized (mInstanceLock) { + mActivityChoserModelPolicy = listener; + } } /** @@ -508,8 +515,9 @@ public class ActivityChooserModel extends DataSetObservable { */ public ResolveInfo getDefaultActivity() { synchronized (mInstanceLock) { - if (!mActivites.isEmpty()) { - return mActivites.get(0).resolveInfo; + ensureConsistentState(); + if (!mActivities.isEmpty()) { + return mActivities.get(0).resolveInfo; } } return null; @@ -526,72 +534,50 @@ public class ActivityChooserModel extends DataSetObservable { * @param index The index of the activity to set as default. */ public void setDefaultActivity(int index) { - ActivityResolveInfo newDefaultActivity = mActivites.get(index); - ActivityResolveInfo oldDefaultActivity = mActivites.get(0); - - final float weight; - if (oldDefaultActivity != null) { - // Add a record with weight enough to boost the chosen at the top. - weight = oldDefaultActivity.weight - newDefaultActivity.weight - + DEFAULT_ACTIVITY_INFLATION; - } else { - weight = DEFAULT_HISTORICAL_RECORD_WEIGHT; - } - - ComponentName defaultName = new ComponentName( - newDefaultActivity.resolveInfo.activityInfo.packageName, - newDefaultActivity.resolveInfo.activityInfo.name); - HistoricalRecord historicalRecord = new HistoricalRecord(defaultName, - System.currentTimeMillis(), weight); - addHisoricalRecord(historicalRecord); - } - - /** - * Reads the history data from the backing file if the latter - * was provided. Calling this method more than once before a call - * to {@link #persistHistoricalData()} has been made has no effect. - *

- * Note: Historical data is read asynchronously and - * as soon as the reading is completed any registered - * {@link DataSetObserver}s will be notified. Also no historical - * data is read until this method is invoked. - *

- */ - private void readHistoricalData() { synchronized (mInstanceLock) { - if (!mCanReadHistoricalData || !mHistoricalRecordsChanged) { - return; - } - mCanReadHistoricalData = false; - mReadShareHistoryCalled = true; - if (!TextUtils.isEmpty(mHistoryFileName)) { - AsyncTask.SERIAL_EXECUTOR.execute(new HistoryLoader()); + ensureConsistentState(); + + ActivityResolveInfo newDefaultActivity = mActivities.get(index); + ActivityResolveInfo oldDefaultActivity = mActivities.get(0); + + final float weight; + if (oldDefaultActivity != null) { + // Add a record with weight enough to boost the chosen at the top. + weight = oldDefaultActivity.weight - newDefaultActivity.weight + + DEFAULT_ACTIVITY_INFLATION; + } else { + weight = DEFAULT_HISTORICAL_RECORD_WEIGHT; } + + ComponentName defaultName = new ComponentName( + newDefaultActivity.resolveInfo.activityInfo.packageName, + newDefaultActivity.resolveInfo.activityInfo.name); + HistoricalRecord historicalRecord = new HistoricalRecord(defaultName, + System.currentTimeMillis(), weight); + addHisoricalRecord(historicalRecord); } } /** * Persists the history data to the backing file if the latter - * was provided. Calling this method before a call to {@link #readHistoricalData()} + * was provided. Calling this method before a call to {@link #readHistoricalDataIfNeeded()} * throws an exception. Calling this method more than one without choosing an * activity has not effect. * * @throws IllegalStateException If this method is called before a call to - * {@link #readHistoricalData()}. + * {@link #readHistoricalDataIfNeeded()}. */ - private void persistHistoricalData() { - synchronized (mInstanceLock) { - if (!mReadShareHistoryCalled) { - throw new IllegalStateException("No preceding call to #readHistoricalData"); - } - if (!mHistoricalRecordsChanged) { - return; - } - mHistoricalRecordsChanged = false; - mCanReadHistoricalData = true; - if (!TextUtils.isEmpty(mHistoryFileName)) { - AsyncTask.SERIAL_EXECUTOR.execute(new HistoryPersister()); - } + private void persistHistoricalDataIfNeeded() { + if (!mReadShareHistoryCalled) { + throw new IllegalStateException("No preceding call to #readHistoricalData"); + } + if (!mHistoricalRecordsChanged) { + return; + } + mHistoricalRecordsChanged = false; + if (!TextUtils.isEmpty(mHistoryFileName)) { + new PersistHistoryAsyncTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, + new ArrayList(mHistoricalRecords), mHistoryFileName); } } @@ -608,21 +594,7 @@ public class ActivityChooserModel extends DataSetObservable { return; } mActivitySorter = activitySorter; - sortActivities(); - } - } - - /** - * Sorts the activities based on history and an intent. If - * a sorter is not specified this a default implementation is used. - * - * @see #setActivitySorter(ActivitySorter) - */ - private void sortActivities() { - synchronized (mInstanceLock) { - if (mActivitySorter != null && !mActivites.isEmpty()) { - mActivitySorter.sort(mIntent, mActivites, - Collections.unmodifiableList(mHistoricalRecords)); + if (sortActivitiesIfNeeded()) { notifyChanged(); } } @@ -647,8 +619,10 @@ public class ActivityChooserModel extends DataSetObservable { return; } mHistoryMaxSize = historyMaxSize; - pruneExcessiveHistoricalRecordsLocked(); - sortActivities(); + pruneExcessiveHistoricalRecordsIfNeeded(); + if (sortActivitiesIfNeeded()) { + notifyChanged(); + } } } @@ -670,6 +644,7 @@ public class ActivityChooserModel extends DataSetObservable { */ public int getHistorySize() { synchronized (mInstanceLock) { + ensureConsistentState(); return mHistoricalRecords.size(); } } @@ -681,82 +656,110 @@ public class ActivityChooserModel extends DataSetObservable { } /** - * Adds a historical record. - * - * @param historicalRecord The record to add. - * @return True if the record was added. + * Ensures the model is in a consistent state which is the + * activities for the current intent have been loaded, the + * most recent history has been read, and the activities + * are sorted. */ - private boolean addHisoricalRecord(HistoricalRecord historicalRecord) { - synchronized (mInstanceLock) { - final boolean added = mHistoricalRecords.add(historicalRecord); - if (added) { - mHistoricalRecordsChanged = true; - pruneExcessiveHistoricalRecordsLocked(); - persistHistoricalData(); - sortActivities(); - } - return added; + private void ensureConsistentState() { + boolean stateChanged = loadActivitiesIfNeeded(); + stateChanged |= readHistoricalDataIfNeeded(); + pruneExcessiveHistoricalRecordsIfNeeded(); + if (stateChanged) { + sortActivitiesIfNeeded(); + notifyChanged(); } } /** - * Prunes older excessive records to guarantee {@link #mHistoryMaxSize}. + * Sorts the activities if necessary which is if there is a + * sorter, there are some activities to sort, and there is some + * historical data. + * + * @return Whether sorting was performed. */ - private void pruneExcessiveHistoricalRecordsLocked() { - List choiceRecords = mHistoricalRecords; - final int pruneCount = choiceRecords.size() - mHistoryMaxSize; - if (pruneCount <= 0) { - return; - } - mHistoricalRecordsChanged = true; - for (int i = 0; i < pruneCount; i++) { - HistoricalRecord prunedRecord = choiceRecords.remove(0); - if (DEBUG) { - Log.i(LOG_TAG, "Pruned: " + prunedRecord); - } + private boolean sortActivitiesIfNeeded() { + if (mActivitySorter != null && mIntent != null + && !mActivities.isEmpty() && !mHistoricalRecords.isEmpty()) { + mActivitySorter.sort(mIntent, mActivities, + Collections.unmodifiableList(mHistoricalRecords)); + return true; } + return false; } /** - * Loads the activities. + * Loads the activities for the current intent if needed which is + * if they are not already loaded for the current intent. + * + * @return Whether loading was performed. */ - private void loadActivitiesLocked() { - mActivites.clear(); - if (mIntent != null) { - List resolveInfos = - mContext.getPackageManager().queryIntentActivities(mIntent, 0); + private boolean loadActivitiesIfNeeded() { + if (mReloadActivities && mIntent != null) { + mReloadActivities = false; + mActivities.clear(); + List resolveInfos = mContext.getPackageManager() + .queryIntentActivities(mIntent, 0); final int resolveInfoCount = resolveInfos.size(); for (int i = 0; i < resolveInfoCount; i++) { ResolveInfo resolveInfo = resolveInfos.get(i); - mActivites.add(new ActivityResolveInfo(resolveInfo)); + mActivities.add(new ActivityResolveInfo(resolveInfo)); } - sortActivities(); - } else { - notifyChanged(); + return true; } + return false; } /** - * Prunes historical records for a package that goes away. + * Reads the historical data if necessary which is it has + * changed, there is a history file, and there is not persist + * in progress. * - * @param packageName The name of the package that goes away. + * @return Whether reading was performed. */ - private void pruneHistoricalRecordsForPackageLocked(String packageName) { - boolean recordsRemoved = false; - - List historicalRecords = mHistoricalRecords; - for (int i = 0; i < historicalRecords.size(); i++) { - HistoricalRecord historicalRecord = historicalRecords.get(i); - String recordPackageName = historicalRecord.activity.getPackageName(); - if (recordPackageName.equals(packageName)) { - historicalRecords.remove(historicalRecord); - recordsRemoved = true; - } + private boolean readHistoricalDataIfNeeded() { + if (mCanReadHistoricalData && mHistoricalRecordsChanged && + !TextUtils.isEmpty(mHistoryFileName)) { + mCanReadHistoricalData = false; + mReadShareHistoryCalled = true; + readHistoricalDataImpl(); + return true; } + return false; + } - if (recordsRemoved) { + /** + * Adds a historical record. + * + * @param historicalRecord The record to add. + * @return True if the record was added. + */ + private boolean addHisoricalRecord(HistoricalRecord historicalRecord) { + final boolean added = mHistoricalRecords.add(historicalRecord); + if (added) { mHistoricalRecordsChanged = true; - sortActivities(); + pruneExcessiveHistoricalRecordsIfNeeded(); + persistHistoricalDataIfNeeded(); + sortActivitiesIfNeeded(); + notifyChanged(); + } + return added; + } + + /** + * Prunes older excessive records to guarantee maxHistorySize. + */ + private void pruneExcessiveHistoricalRecordsIfNeeded() { + final int pruneCount = mHistoricalRecords.size() - mHistoryMaxSize; + if (pruneCount <= 0) { + return; + } + mHistoricalRecordsChanged = true; + for (int i = 0; i < pruneCount; i++) { + HistoricalRecord prunedRecord = mHistoricalRecords.remove(0); + if (DEBUG) { + Log.i(LOG_TAG, "Pruned: " + prunedRecord); + } } } @@ -964,112 +967,72 @@ public class ActivityChooserModel extends DataSetObservable { /** * Command for reading the historical records from a file off the UI thread. */ - private final class HistoryLoader implements Runnable { - - public void run() { - FileInputStream fis = null; - try { - fis = mContext.openFileInput(mHistoryFileName); - } catch (FileNotFoundException fnfe) { - if (DEBUG) { - Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName); - } - return; + private void readHistoricalDataImpl() { + FileInputStream fis = null; + try { + fis = mContext.openFileInput(mHistoryFileName); + } catch (FileNotFoundException fnfe) { + if (DEBUG) { + Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName); } - try { - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(fis, null); - - int type = XmlPullParser.START_DOCUMENT; - while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { - type = parser.next(); - } - - if (!TAG_HISTORICAL_RECORDS.equals(parser.getName())) { - throw new XmlPullParserException("Share records file does not start with " - + TAG_HISTORICAL_RECORDS + " tag."); - } - - List readRecords = new ArrayList(); + return; + } + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(fis, null); - while (true) { - type = parser.next(); - if (type == XmlPullParser.END_DOCUMENT) { - break; - } - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - String nodeName = parser.getName(); - if (!TAG_HISTORICAL_RECORD.equals(nodeName)) { - throw new XmlPullParserException("Share records file not well-formed."); - } + int type = XmlPullParser.START_DOCUMENT; + while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { + type = parser.next(); + } - String activity = parser.getAttributeValue(null, ATTRIBUTE_ACTIVITY); - final long time = - Long.parseLong(parser.getAttributeValue(null, ATTRIBUTE_TIME)); - final float weight = - Float.parseFloat(parser.getAttributeValue(null, ATTRIBUTE_WEIGHT)); + if (!TAG_HISTORICAL_RECORDS.equals(parser.getName())) { + throw new XmlPullParserException("Share records file does not start with " + + TAG_HISTORICAL_RECORDS + " tag."); + } - HistoricalRecord readRecord = new HistoricalRecord(activity, time, - weight); - readRecords.add(readRecord); + List historicalRecords = mHistoricalRecords; + historicalRecords.clear(); - if (DEBUG) { - Log.i(LOG_TAG, "Read " + readRecord.toString()); - } + while (true) { + type = parser.next(); + if (type == XmlPullParser.END_DOCUMENT) { + break; } - - if (DEBUG) { - Log.i(LOG_TAG, "Read " + readRecords.size() + " historical records."); + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String nodeName = parser.getName(); + if (!TAG_HISTORICAL_RECORD.equals(nodeName)) { + throw new XmlPullParserException("Share records file not well-formed."); } - synchronized (mInstanceLock) { - Set uniqueShareRecords = - new LinkedHashSet(readRecords); - - // Make sure no duplicates. Example: Read a file with - // one record, add one record, persist the two records, - // add a record, read the persisted records - the - // read two records should not be added again. - List historicalRecords = mHistoricalRecords; - final int historicalRecordsCount = historicalRecords.size(); - for (int i = historicalRecordsCount - 1; i >= 0; i--) { - HistoricalRecord historicalRecord = historicalRecords.get(i); - uniqueShareRecords.add(historicalRecord); - } - - if (historicalRecords.size() == uniqueShareRecords.size()) { - return; - } + String activity = parser.getAttributeValue(null, ATTRIBUTE_ACTIVITY); + final long time = + Long.parseLong(parser.getAttributeValue(null, ATTRIBUTE_TIME)); + final float weight = + Float.parseFloat(parser.getAttributeValue(null, ATTRIBUTE_WEIGHT)); + HistoricalRecord readRecord = new HistoricalRecord(activity, time, weight); + historicalRecords.add(readRecord); - // Make sure the oldest records go to the end. - historicalRecords.clear(); - historicalRecords.addAll(uniqueShareRecords); - - mHistoricalRecordsChanged = true; - - // Do this on the client thread since the client may be on the UI - // thread, wait for data changes which happen during sorting, and - // perform UI modification based on the data change. - mHandler.post(new Runnable() { - public void run() { - pruneExcessiveHistoricalRecordsLocked(); - sortActivities(); - } - }); + if (DEBUG) { + Log.i(LOG_TAG, "Read " + readRecord.toString()); } - } catch (XmlPullParserException xppe) { - Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, xppe); - } catch (IOException ioe) { - Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, ioe); - } finally { - if (fis != null) { - try { - fis.close(); - } catch (IOException ioe) { - /* ignore */ - } + } + + if (DEBUG) { + Log.i(LOG_TAG, "Read " + historicalRecords.size() + " historical records."); + } + } catch (XmlPullParserException xppe) { + Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, xppe); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, ioe); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException ioe) { + /* ignore */ } } } @@ -1078,21 +1041,21 @@ public class ActivityChooserModel extends DataSetObservable { /** * Command for persisting the historical records to a file off the UI thread. */ - private final class HistoryPersister implements Runnable { + private final class PersistHistoryAsyncTask extends AsyncTask { - public void run() { - FileOutputStream fos = null; - List records = null; + @Override + @SuppressWarnings("unchecked") + public Void doInBackground(Object... args) { + List historicalRecords = (List) args[0]; + String hostoryFileName = (String) args[1]; - synchronized (mInstanceLock) { - records = new ArrayList(mHistoricalRecords); - } + FileOutputStream fos = null; try { - fos = mContext.openFileOutput(mHistoryFileName, Context.MODE_PRIVATE); + fos = mContext.openFileOutput(hostoryFileName, Context.MODE_PRIVATE); } catch (FileNotFoundException fnfe) { - Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, fnfe); - return; + Log.e(LOG_TAG, "Error writing historical recrod file: " + hostoryFileName, fnfe); + return null; } XmlSerializer serializer = Xml.newSerializer(); @@ -1102,11 +1065,12 @@ public class ActivityChooserModel extends DataSetObservable { serializer.startDocument("UTF-8", true); serializer.startTag(null, TAG_HISTORICAL_RECORDS); - final int recordCount = records.size(); + final int recordCount = historicalRecords.size(); for (int i = 0; i < recordCount; i++) { - HistoricalRecord record = records.remove(0); + HistoricalRecord record = historicalRecords.remove(0); serializer.startTag(null, TAG_HISTORICAL_RECORD); - serializer.attribute(null, ATTRIBUTE_ACTIVITY, record.activity.flattenToString()); + serializer.attribute(null, ATTRIBUTE_ACTIVITY, + record.activity.flattenToString()); serializer.attribute(null, ATTRIBUTE_TIME, String.valueOf(record.time)); serializer.attribute(null, ATTRIBUTE_WEIGHT, String.valueOf(record.weight)); serializer.endTag(null, TAG_HISTORICAL_RECORD); @@ -1128,6 +1092,7 @@ public class ActivityChooserModel extends DataSetObservable { } catch (IOException ioe) { Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ioe); } finally { + mCanReadHistoricalData = true; if (fos != null) { try { fos.close(); @@ -1136,6 +1101,7 @@ public class ActivityChooserModel extends DataSetObservable { } } } + return null; } } @@ -1145,33 +1111,8 @@ public class ActivityChooserModel extends DataSetObservable { private final class DataModelPackageMonitor extends PackageMonitor { @Override - public void onPackageAdded(String packageName, int uid) { - synchronized (mInstanceLock) { - loadActivitiesLocked(); - } - } - - @Override - public void onPackageAppeared(String packageName, int reason) { - synchronized (mInstanceLock) { - loadActivitiesLocked(); - } - } - - @Override - public void onPackageRemoved(String packageName, int uid) { - synchronized (mInstanceLock) { - pruneHistoricalRecordsForPackageLocked(packageName); - loadActivitiesLocked(); - } - } - - @Override - public void onPackageDisappeared(String packageName, int reason) { - synchronized (mInstanceLock) { - pruneHistoricalRecordsForPackageLocked(packageName); - loadActivitiesLocked(); - } + public void onSomePackagesChanged() { + mReloadActivities = true; } } } -- cgit v1.1