1c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki/* 2c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Copyright (C) 2012 The Android Open Source Project 3c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 4c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 5c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * you may not use this file except in compliance with the License. 6c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * You may obtain a copy of the License at 7c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 8c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 9c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 10c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Unless required by applicable law or agreed to in writing, software 11c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 12c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * See the License for the specific language governing permissions and 14c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * limitations under the License. 15c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 16c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukipackage com.android.contacts.list; 17c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 18c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.content.ContentValues; 19c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.content.Context; 20c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.database.ContentObserver; 21c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.database.Cursor; 22c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.net.Uri; 23c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.os.AsyncTask; 24c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.os.Handler; 25c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.provider.ContactsContract.ProviderStatus; 26c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport android.util.Log; 27c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 28aac0e66fb100b329d6010637998849048efadca9Wenyi Wangimport com.android.contacts.compat.ProviderStatusCompat; 292795a88a8e89a44f7dc4334cc2ae00bbd19dc2c1Wenyi Wang 30e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists; 31e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 32c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukiimport java.util.ArrayList; 33c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 34c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki/** 35c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * A singleton that keeps track of the last known provider status. 36c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 37c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * All methods must be called on the UI thread unless noted otherwise. 38c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 39c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * All members must be set on the UI thread unless noted otherwise. 40c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 41c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onukipublic class ProviderStatusWatcher extends ContentObserver { 42c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private static final String TAG = "ProviderStatusWatcher"; 43c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private static final boolean DEBUG = false; 44c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 45c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 46c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Callback interface invoked when the provider status changes. 47c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 48c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public interface ProviderStatusListener { 49c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void onProviderStatusChange(); 50c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 51c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 52c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private static final String[] PROJECTION = new String[] { 53c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell ProviderStatus.STATUS 54c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki }; 55c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 56c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 57c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * We'll wait for this amount of time on the UI thread if the load hasn't finished. 58c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 59c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private static final int LOAD_WAIT_TIMEOUT_MS = 1000; 60c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 61c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private static ProviderStatusWatcher sInstance; 62c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 63c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private final Context mContext; 64c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private final Handler mHandler = new Handler(); 65c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 66c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private final Object mSignal = new Object(); 67c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 68c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private int mStartRequestedCount; 69c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 70c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private LoaderTask mLoaderTask; 71c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 72c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell /** Last known provider status. This can be changed on a worker thread. 73c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell * See {@link ProviderStatus#STATUS} */ 74c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell private Integer mProviderStatus; 75c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 76c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private final ArrayList<ProviderStatusListener> mListeners = Lists.newArrayList(); 77c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 78c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private final Runnable mStartLoadingRunnable = new Runnable() { 79c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki @Override 80c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void run() { 81c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki startLoading(); 82c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 83c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki }; 84c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 85c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 86c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Returns the singleton instance. 87c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 88c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public synchronized static ProviderStatusWatcher getInstance(Context context) { 89c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (sInstance == null) { 90c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki sInstance = new ProviderStatusWatcher(context); 91c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 92c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return sInstance; 93c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 94c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 95c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private ProviderStatusWatcher(Context context) { 96c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki super(null); 97c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mContext = context; 98c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 99c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 100c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** Add a listener. */ 101c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void addListener(ProviderStatusListener listener) { 102c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mListeners.add(listener); 103c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 104c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 105c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** Remove a listener */ 106c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void removeListener(ProviderStatusListener listener) { 107c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mListeners.remove(listener); 108c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 109c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 110c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private void notifyListeners() { 111c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (DEBUG) { 112c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Log.d(TAG, "notifyListeners: " + mListeners.size()); 113c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 114c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (isStarted()) { 115c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki for (ProviderStatusListener listener : mListeners) { 116c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki listener.onProviderStatusChange(); 117c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 118c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 119c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 120c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 121c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private boolean isStarted() { 122c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return mStartRequestedCount > 0; 123c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 124c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 125c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 126c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Starts watching the provider status. {@link #start()} and {@link #stop()} calls can be 127c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * nested. 128c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 129c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void start() { 130c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (++mStartRequestedCount == 1) { 131c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mContext.getContentResolver() 132c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki .registerContentObserver(ProviderStatus.CONTENT_URI, false, this); 133c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki startLoading(); 134c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 135c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (DEBUG) { 136c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Log.d(TAG, "Start observing"); 137c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 138c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 139c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 140c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 141c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 142c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Stops watching the provider status. 143c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 144c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void stop() { 145c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (!isStarted()) { 146c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Log.e(TAG, "Already stopped"); 147c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return; 148c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 149c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (--mStartRequestedCount == 0) { 150c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 151c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mHandler.removeCallbacks(mStartLoadingRunnable); 152c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 153c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mContext.getContentResolver().unregisterContentObserver(this); 154c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (DEBUG) { 155c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Log.d(TAG, "Stop observing"); 156c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 157c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 158c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 159c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 160c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 161c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * @return last known provider status. 162c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 163c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * If this method is called when we haven't started the status query or the query is still in 164c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * progress, it will start a query in a worker thread if necessary, and *wait for the result*. 165c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 166c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * This means this method is essentially a blocking {@link ProviderStatus#CONTENT_URI} query. 167c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * This URI is not backed by the file system, so is usually fast enough to perform on the main 168c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * thread, but in extreme cases (when the system takes a while to bring up the contacts 169c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * provider?) this may still cause ANRs. 170c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 171c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * In order to avoid that, if we can't load the status within {@link #LOAD_WAIT_TIMEOUT_MS}, 1722795a88a8e89a44f7dc4334cc2ae00bbd19dc2c1Wenyi Wang * we'll give up and just returns {@link ProviderStatusCompat#STATUS_BUSY} in order to unblock 173c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * the UI thread. The actual result will be delivered later via {@link ProviderStatusListener}. 1742795a88a8e89a44f7dc4334cc2ae00bbd19dc2c1Wenyi Wang * (If {@link ProviderStatusCompat#STATUS_BUSY} is returned, the app (should) shows an according 175c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * message, like "contacts are being updated".) 176c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 177c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell public int getProviderStatus() { 178c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki waitForLoaded(); 179c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 180d8fa716e5428791f79f54437087df3005cc907bfMakoto Onuki if (mProviderStatus == null) { 1812795a88a8e89a44f7dc4334cc2ae00bbd19dc2c1Wenyi Wang return ProviderStatusCompat.STATUS_BUSY; 182c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 183c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 184c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return mProviderStatus; 185c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 186c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 187c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private void waitForLoaded() { 188d8fa716e5428791f79f54437087df3005cc907bfMakoto Onuki if (mProviderStatus == null) { 189c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (mLoaderTask == null) { 190c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki // For some reason the loader couldn't load the status. Let's start it again. 191c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki startLoading(); 192c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 193c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki synchronized (mSignal) { 194c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki try { 195c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mSignal.wait(LOAD_WAIT_TIMEOUT_MS); 196c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } catch (InterruptedException ignore) { 197c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 198c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 199c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 200c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 201c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 202c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private void startLoading() { 203c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (mLoaderTask != null) { 204c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return; // Task already running. 205c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 206c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 207c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (DEBUG) { 208c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Log.d(TAG, "Start loading"); 209c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 210c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 211c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mLoaderTask = new LoaderTask(); 212c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mLoaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 213c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 214c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 215c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private class LoaderTask extends AsyncTask<Void, Void, Boolean> { 216c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki @Override 217c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki protected Boolean doInBackground(Void... params) { 218c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki try { 219c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Cursor cursor = mContext.getContentResolver().query(ProviderStatus.CONTENT_URI, 220c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki PROJECTION, null, null, null); 221c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (cursor != null) { 222c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki try { 223c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (cursor.moveToFirst()) { 224d8fa716e5428791f79f54437087df3005cc907bfMakoto Onuki // Note here we can't just say "Status", as AsyncTask has the "Status" 225d8fa716e5428791f79f54437087df3005cc907bfMakoto Onuki // enum too. 226c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell mProviderStatus = cursor.getInt(0); 227c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return true; 228c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 229c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } finally { 230c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki cursor.close(); 231c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 232c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 233c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki return false; 234c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } finally { 235c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki synchronized (mSignal) { 236c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mSignal.notifyAll(); 237c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 238c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 239c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 240c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 241c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki @Override 242c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki protected void onCancelled(Boolean result) { 243c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki cleanUp(); 244c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 245c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 246c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki @Override 247c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki protected void onPostExecute(Boolean loaded) { 248c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki cleanUp(); 249c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (loaded != null && loaded) { 250c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki notifyListeners(); 251c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 252c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 253c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 254c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki private void cleanUp() { 255c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mLoaderTask = null; 256c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 257c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 258c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 259c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki /** 260c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * Called when provider status may has changed. 261c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * 262c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki * This method will be called on a worker thread by the framework. 263c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki */ 264c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki @Override 265c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki public void onChange(boolean selfChange, Uri uri) { 266c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki if (!ProviderStatus.CONTENT_URI.equals(uri)) return; 267c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 268c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki // Provider status change is rare, so okay to log. 269c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki Log.i(TAG, "Provider status changed."); 270c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki 271c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mHandler.removeCallbacks(mStartLoadingRunnable); // Remove one in the queue, if any. 272c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki mHandler.post(mStartLoadingRunnable); 273c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki } 274c2bd6138e19fdcf734843eb55c83d6ffe00e91daMakoto Onuki} 275