13069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk/*
23069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * Copyright (C) 2015 The Android Open Source Project
33069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk *
43069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
53069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * you may not use this file except in compliance with the License.
63069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * You may obtain a copy of the License at
73069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk *
83069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
93069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk *
103069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * Unless required by applicable law or agreed to in writing, software
113069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
123069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * See the License for the specific language governing permissions and
143069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk * limitations under the License.
153069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk */
163069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkpackage com.android.settings.dashboard;
173069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
183069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport android.app.Activity;
198ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.content.BroadcastReceiver;
20c06457326509ec625d90b26828d6cc1417f4d9a3Jason Monkimport android.content.ComponentName;
218ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.content.IntentFilter;
228ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.os.Bundle;
238ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.os.Handler;
248ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.os.HandlerThread;
258ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.os.Looper;
268ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monkimport android.os.Message;
275673ced93cda4a48872c1452122ee278da3aa17aJason Monkimport android.os.Process;
283069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport android.util.ArrayMap;
29a8a029f8eb8ca51a19ce20206ce307761cfd86baJason Monkimport android.util.ArraySet;
303069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport android.util.Log;
31011362d9f15a3acb96b59e833059825a232db133Fan Zhang
323069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport com.android.settings.SettingsActivity;
333069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport com.android.settingslib.drawer.DashboardCategory;
34011362d9f15a3acb96b59e833059825a232db133Fan Zhangimport com.android.settingslib.drawer.SettingsDrawerActivity;
35d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monkimport com.android.settingslib.drawer.Tile;
363069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
373069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport java.lang.reflect.Field;
383069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport java.util.ArrayList;
393069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkimport java.util.List;
403069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
413069581512bcb9687cb8d79675f6c4950c9ac087Jason Monkpublic class SummaryLoader {
423069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    private static final boolean DEBUG = DashboardSummary.DEBUG;
433069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    private static final String TAG = "SummaryLoader";
443069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
458c4ca41d2595925d108dad82959faddb676a392dJason Monk    public static final String SUMMARY_PROVIDER_FACTORY = "SUMMARY_PROVIDER_FACTORY";
468c4ca41d2595925d108dad82959faddb676a392dJason Monk
473069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    private final Activity mActivity;
48c06457326509ec625d90b26828d6cc1417f4d9a3Jason Monk    private final ArrayMap<SummaryProvider, ComponentName> mSummaryMap = new ArrayMap<>();
49d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monk    private final List<Tile> mTiles = new ArrayList<>();
503069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
51fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    private final Worker mWorker;
52fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    private final Handler mHandler;
53fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    private final HandlerThread mWorkerThread;
54fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk
558c4ca41d2595925d108dad82959faddb676a392dJason Monk    private DashboardAdapter mAdapter;
569425839379d862604d4b5a7b9161540f598f64f6Jason Monk    private boolean mListening;
578d8de1490536468bbc1061abca0f78ab0b682b3bJason Monk    private boolean mWorkerListening;
58a8a029f8eb8ca51a19ce20206ce307761cfd86baJason Monk    private ArraySet<BroadcastReceiver> mReceivers = new ArraySet<>();
593069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
60fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    public SummaryLoader(Activity activity, List<DashboardCategory> categories) {
61fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        mHandler = new Handler();
625673ced93cda4a48872c1452122ee278da3aa17aJason Monk        mWorkerThread = new HandlerThread("SummaryLoader", Process.THREAD_PRIORITY_BACKGROUND);
63fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        mWorkerThread.start();
64fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        mWorker = new Worker(mWorkerThread.getLooper());
653069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        mActivity = activity;
663069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        for (int i = 0; i < categories.size(); i++) {
67d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monk            List<Tile> tiles = categories.get(i).tiles;
683069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            for (int j = 0; j < tiles.size(); j++) {
69d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monk                Tile tile = tiles.get(j);
70fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget();
713069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            }
723069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        }
733069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
743069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
75fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    public void release() {
76816959889ef41012c86fd76bfc173b75d7150158Jason Monk        mWorkerThread.quitSafely();
779425839379d862604d4b5a7b9161540f598f64f6Jason Monk        // Make sure we aren't listening.
789425839379d862604d4b5a7b9161540f598f64f6Jason Monk        setListeningW(false);
79fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    }
80fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk
818c4ca41d2595925d108dad82959faddb676a392dJason Monk    public void setAdapter(DashboardAdapter adapter) {
828c4ca41d2595925d108dad82959faddb676a392dJason Monk        mAdapter = adapter;
838c4ca41d2595925d108dad82959faddb676a392dJason Monk    }
848c4ca41d2595925d108dad82959faddb676a392dJason Monk
85fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    public void setSummary(SummaryProvider provider, final CharSequence summary) {
86c06457326509ec625d90b26828d6cc1417f4d9a3Jason Monk        final ComponentName component= mSummaryMap.get(provider);
87fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        mHandler.post(new Runnable() {
88fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk            @Override
89fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk            public void run() {
90c06457326509ec625d90b26828d6cc1417f4d9a3Jason Monk                // Since tiles are not always cached (like on locale change for instance),
91c06457326509ec625d90b26828d6cc1417f4d9a3Jason Monk                // we need to always get the latest one.
92011362d9f15a3acb96b59e833059825a232db133Fan Zhang                if (!(mActivity instanceof SettingsDrawerActivity)) {
93011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    if (DEBUG) {
94011362d9f15a3acb96b59e833059825a232db133Fan Zhang                        Log.d(TAG, "Can't get category list.");
95011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    }
96011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    return;
97011362d9f15a3acb96b59e833059825a232db133Fan Zhang                }
98011362d9f15a3acb96b59e833059825a232db133Fan Zhang                final List<DashboardCategory> categories =
99011362d9f15a3acb96b59e833059825a232db133Fan Zhang                        ((SettingsDrawerActivity) mActivity).getDashboardCategories();
100011362d9f15a3acb96b59e833059825a232db133Fan Zhang                final Tile tile = getTileFromCategory(categories, component);
101011362d9f15a3acb96b59e833059825a232db133Fan Zhang                if (tile == null) {
102011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    if (DEBUG) {
103011362d9f15a3acb96b59e833059825a232db133Fan Zhang                        Log.d(TAG, "Can't find tile for " + component);
104011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    }
105011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    return;
106011362d9f15a3acb96b59e833059825a232db133Fan Zhang                }
107011362d9f15a3acb96b59e833059825a232db133Fan Zhang                if (DEBUG) {
108011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    Log.d(TAG, "setSummary " + tile.title + " - " + summary);
109011362d9f15a3acb96b59e833059825a232db133Fan Zhang                }
110fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                tile.summary = summary;
111fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                mAdapter.notifyChanged(tile);
112fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk            }
113fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        });
1143069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
1153069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
1168b986f5f7345d2f012792634950669759b9be0ddJason Monk    /**
1178b986f5f7345d2f012792634950669759b9be0ddJason Monk     * Only call from the main thread.
1188b986f5f7345d2f012792634950669759b9be0ddJason Monk     */
1193069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    public void setListening(boolean listening) {
1208b986f5f7345d2f012792634950669759b9be0ddJason Monk        if (mListening == listening) return;
1218b986f5f7345d2f012792634950669759b9be0ddJason Monk        mListening = listening;
1228b986f5f7345d2f012792634950669759b9be0ddJason Monk        // Unregister listeners immediately.
1238b986f5f7345d2f012792634950669759b9be0ddJason Monk        for (int i = 0; i < mReceivers.size(); i++) {
124a8a029f8eb8ca51a19ce20206ce307761cfd86baJason Monk            mActivity.unregisterReceiver(mReceivers.valueAt(i));
1258ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk        }
1268b986f5f7345d2f012792634950669759b9be0ddJason Monk        mReceivers.clear();
1278d8de1490536468bbc1061abca0f78ab0b682b3bJason Monk        mWorker.removeMessages(Worker.MSG_SET_LISTENING);
128fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        mWorker.obtainMessage(Worker.MSG_SET_LISTENING, listening ? 1 : 0, 0).sendToTarget();
1293069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
1303069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
131d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monk    private SummaryProvider getSummaryProvider(Tile tile) {
1323069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        if (!mActivity.getPackageName().equals(tile.intent.getComponent().getPackageName())) {
1333069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            // Not within Settings, can't load Summary directly.
1343069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            // TODO: Load summary indirectly.
1353069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            return null;
1363069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        }
1373069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        Bundle metaData = getMetaData(tile);
1383069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        if (metaData == null) {
1393069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            if (DEBUG) Log.d(TAG, "No metadata specified for " + tile.intent.getComponent());
1403069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            return null;
1413069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        }
1423069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        String clsName = metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
1433069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        if (clsName == null) {
1443069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            if (DEBUG) Log.d(TAG, "No fragment specified for " + tile.intent.getComponent());
1453069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            return null;
1463069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        }
1473069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        try {
1483069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            Class<?> cls = Class.forName(clsName);
1493069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            Field field = cls.getField(SUMMARY_PROVIDER_FACTORY);
1503069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            SummaryProviderFactory factory = (SummaryProviderFactory) field.get(null);
1513069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            return factory.createSummaryProvider(mActivity, this);
1523069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        } catch (ClassNotFoundException e) {
1533069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            if (DEBUG) Log.d(TAG, "Couldn't find " + clsName, e);
1543069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        } catch (NoSuchFieldException e) {
1553069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            if (DEBUG) Log.d(TAG, "Couldn't find " + SUMMARY_PROVIDER_FACTORY, e);
1563069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        } catch (ClassCastException e) {
1573069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            if (DEBUG) Log.d(TAG, "Couldn't cast " + SUMMARY_PROVIDER_FACTORY, e);
1583069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        } catch (IllegalAccessException e) {
1593069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk            if (DEBUG) Log.d(TAG, "Couldn't get " + SUMMARY_PROVIDER_FACTORY, e);
1603069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        }
1613069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        return null;
1623069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
1633069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
164d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monk    private Bundle getMetaData(Tile tile) {
165fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        return tile.metaData;
1663069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
1673069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
1688ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk    /**
1698ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk     * Registers a receiver and automatically unregisters it when the activity is stopping.
1708ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk     * This ensures that the receivers are unregistered immediately, since most summary loader
1718ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk     * operations are asynchronous.
1728ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk     */
1738b986f5f7345d2f012792634950669759b9be0ddJason Monk    public void registerReceiver(final BroadcastReceiver receiver, final IntentFilter filter) {
1748b986f5f7345d2f012792634950669759b9be0ddJason Monk        mActivity.runOnUiThread(new Runnable() {
1758b986f5f7345d2f012792634950669759b9be0ddJason Monk            @Override
1768b986f5f7345d2f012792634950669759b9be0ddJason Monk            public void run() {
1778b986f5f7345d2f012792634950669759b9be0ddJason Monk                if (!mListening) {
1788b986f5f7345d2f012792634950669759b9be0ddJason Monk                    return;
1798b986f5f7345d2f012792634950669759b9be0ddJason Monk                }
1808b986f5f7345d2f012792634950669759b9be0ddJason Monk                mReceivers.add(receiver);
1818b986f5f7345d2f012792634950669759b9be0ddJason Monk                mActivity.registerReceiver(receiver, filter);
1828ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk            }
1838b986f5f7345d2f012792634950669759b9be0ddJason Monk        });
1848ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk    }
1858ab081e304b978602823b5f7fa81a673e98b4bb2Jason Monk
1869425839379d862604d4b5a7b9161540f598f64f6Jason Monk    private synchronized void setListeningW(boolean listening) {
1878d8de1490536468bbc1061abca0f78ab0b682b3bJason Monk        if (mWorkerListening == listening) return;
1888d8de1490536468bbc1061abca0f78ab0b682b3bJason Monk        mWorkerListening = listening;
1899425839379d862604d4b5a7b9161540f598f64f6Jason Monk        if (DEBUG) Log.d(TAG, "Listening " + listening);
1909425839379d862604d4b5a7b9161540f598f64f6Jason Monk        for (SummaryProvider p : mSummaryMap.keySet()) {
1910842797a25af0383b25b039f8d5436d861134157Jason Monk            try {
1920842797a25af0383b25b039f8d5436d861134157Jason Monk                p.setListening(listening);
1930842797a25af0383b25b039f8d5436d861134157Jason Monk            } catch (Exception e) {
1940842797a25af0383b25b039f8d5436d861134157Jason Monk                Log.d(TAG, "Problem in setListening", e);
1950842797a25af0383b25b039f8d5436d861134157Jason Monk            }
1969425839379d862604d4b5a7b9161540f598f64f6Jason Monk        }
1979425839379d862604d4b5a7b9161540f598f64f6Jason Monk    }
1989425839379d862604d4b5a7b9161540f598f64f6Jason Monk
1999425839379d862604d4b5a7b9161540f598f64f6Jason Monk    private synchronized void makeProviderW(Tile tile) {
2009425839379d862604d4b5a7b9161540f598f64f6Jason Monk        SummaryProvider provider = getSummaryProvider(tile);
2019425839379d862604d4b5a7b9161540f598f64f6Jason Monk        if (provider != null) {
2029425839379d862604d4b5a7b9161540f598f64f6Jason Monk            if (DEBUG) Log.d(TAG, "Creating " + tile);
203c06457326509ec625d90b26828d6cc1417f4d9a3Jason Monk            mSummaryMap.put(provider, tile.intent.getComponent());
2049425839379d862604d4b5a7b9161540f598f64f6Jason Monk        }
2059425839379d862604d4b5a7b9161540f598f64f6Jason Monk    }
2069425839379d862604d4b5a7b9161540f598f64f6Jason Monk
207011362d9f15a3acb96b59e833059825a232db133Fan Zhang    private Tile getTileFromCategory(List<DashboardCategory> categories, ComponentName component) {
208011362d9f15a3acb96b59e833059825a232db133Fan Zhang        if (categories == null) {
209011362d9f15a3acb96b59e833059825a232db133Fan Zhang            if (DEBUG) {
210011362d9f15a3acb96b59e833059825a232db133Fan Zhang                Log.d(TAG, "Category is null, can't find tile");
211011362d9f15a3acb96b59e833059825a232db133Fan Zhang            }
212011362d9f15a3acb96b59e833059825a232db133Fan Zhang            return null;
213011362d9f15a3acb96b59e833059825a232db133Fan Zhang        }
214011362d9f15a3acb96b59e833059825a232db133Fan Zhang        final int categorySize = categories.size();
215011362d9f15a3acb96b59e833059825a232db133Fan Zhang        for (int i = 0; i < categorySize; i++) {
216011362d9f15a3acb96b59e833059825a232db133Fan Zhang            final DashboardCategory category = categories.get(i);
217011362d9f15a3acb96b59e833059825a232db133Fan Zhang            final int tileCount = category.tiles.size();
218011362d9f15a3acb96b59e833059825a232db133Fan Zhang            for (int j = 0; j < tileCount; j++) {
219011362d9f15a3acb96b59e833059825a232db133Fan Zhang                final Tile tile = category.tiles.get(j);
220011362d9f15a3acb96b59e833059825a232db133Fan Zhang                if (component.equals(tile.intent.getComponent())) {
221011362d9f15a3acb96b59e833059825a232db133Fan Zhang                    return tile;
222011362d9f15a3acb96b59e833059825a232db133Fan Zhang                }
223011362d9f15a3acb96b59e833059825a232db133Fan Zhang            }
224011362d9f15a3acb96b59e833059825a232db133Fan Zhang        }
225011362d9f15a3acb96b59e833059825a232db133Fan Zhang        return null;
226011362d9f15a3acb96b59e833059825a232db133Fan Zhang    }
227011362d9f15a3acb96b59e833059825a232db133Fan Zhang
2283069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    public interface SummaryProvider {
2293069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        void setListening(boolean listening);
2303069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
2313069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk
2323069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    public interface SummaryProviderFactory {
2333069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk        SummaryProvider createSummaryProvider(Activity activity, SummaryLoader summaryLoader);
2343069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk    }
235fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk
236fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    private class Worker extends Handler {
237fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        private static final int MSG_GET_PROVIDER = 1;
238fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        private static final int MSG_SET_LISTENING = 2;
239fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk
240fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        public Worker(Looper looper) {
241fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk            super(looper);
242fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        }
243fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk
244fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        @Override
245fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        public void handleMessage(Message msg) {
246fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk            switch (msg.what) {
247fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                case MSG_GET_PROVIDER:
248d4f03ec86f9e8b7b108fc63684e23f5c0fb2a864Jason Monk                    Tile tile = (Tile) msg.obj;
2499425839379d862604d4b5a7b9161540f598f64f6Jason Monk                    makeProviderW(tile);
250fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                    break;
251fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                case MSG_SET_LISTENING:
252fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                    boolean listening = msg.arg1 != 0;
2539425839379d862604d4b5a7b9161540f598f64f6Jason Monk                    setListeningW(listening);
254fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk                    break;
255fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk            }
256fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk        }
257fd2c7224185bef301cfaa7de6fe1af22cab8df2fJason Monk    }
2583069581512bcb9687cb8d79675f6c4950c9ac087Jason Monk}
259