ContactDirectoryManager.java revision 994c32a995a85937faf59e37a9fc88b526470d7d
172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov/*
272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project
372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov *
472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * you may not use this file except in compliance with the License.
672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * You may obtain a copy of the License at
772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov *
872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov *
1072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
1172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
1272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * See the License for the specific language governing permissions and
1472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * limitations under the License
1572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov */
1672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
1772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovpackage com.android.providers.contacts;
1872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
1972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
2072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport com.google.android.collect.Lists;
2172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
2272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.ContentValues;
2372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.Context;
2472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.pm.PackageInfo;
2572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.pm.PackageManager;
2672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.pm.PackageManager.NameNotFoundException;
2772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.pm.ProviderInfo;
2872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.database.Cursor;
2972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.database.sqlite.SQLiteDatabase;
3072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.net.Uri;
3172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.Binder;
3272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.Bundle;
3372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.Handler;
3472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.HandlerThread;
3572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.Message;
3672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.Process;
3772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.os.SystemClock;
3872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.provider.ContactsContract.Directory;
3972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.util.Log;
4072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
4172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport java.util.ArrayList;
4272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport java.util.List;
4372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
4472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov/**
4572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov * Manages the contents of the {@link Directory} table.
4672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov */
4772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovpublic class ContactDirectoryManager extends HandlerThread {
4872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
4972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private static final String TAG = "ContactDirectoryManager";
5072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
5172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private static final int MESSAGE_SCAN_ALL_PROVIDERS = 0;
5272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private static final int MESSAGE_SCAN_PACKAGES_BY_UID = 1;
5372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
543d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov    public static final String PROPERTY_DIRECTORY_SCAN_COMPLETE = "directoryScanComplete";
553d67ff829e8acb0f650f155c3c0d377c0f46507aDmitri Plotnikov    public static final String CONTACT_DIRECTORY_META_DATA = "android.content.ContactDirectory";
5672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
5772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public class DirectoryInfo {
5872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        long id;
5972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        String packageName;
6072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        String authority;
6172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        String accountName;
6272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        String accountType;
6372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        String displayName;
6472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        int typeResourceId;
6572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        int exportSupport = Directory.EXPORT_SUPPORT_NONE;
6672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        int shortcutSupport = Directory.SHORTCUT_SUPPORT_NONE;
67994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov        int photoSupport = Directory.PHOTO_SUPPORT_NONE;
6872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
6972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
7072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private final static class DirectoryQuery {
7172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final String[] PROJECTION = {
7272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Directory.ACCOUNT_NAME,
7372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Directory.ACCOUNT_TYPE,
7472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Directory.DISPLAY_NAME,
7572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Directory.TYPE_RESOURCE_ID,
7672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Directory.EXPORT_SUPPORT,
7772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Directory.SHORTCUT_SUPPORT,
78994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov            Directory.PHOTO_SUPPORT,
7972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        };
8072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
8172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final int ACCOUNT_NAME = 0;
8272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final int ACCOUNT_TYPE = 1;
8372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final int DISPLAY_NAME = 2;
8472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final int TYPE_RESOURCE_ID = 3;
8572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final int EXPORT_SUPPORT = 4;
8672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        public static final int SHORTCUT_SUPPORT = 5;
87994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov        public static final int PHOTO_SUPPORT = 6;
8872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
8972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
9072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private final ContactsProvider2 mContactsProvider;
9172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private Context mContext;
9272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private Handler mHandler;
9372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
9472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public ContactDirectoryManager(ContactsProvider2 contactsProvider) {
9572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        super("DirectoryManager", Process.THREAD_PRIORITY_BACKGROUND);
9672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        this.mContactsProvider = contactsProvider;
9772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        this.mContext = contactsProvider.getContext();
9872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
9972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
10072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
10172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Launches an asynchronous scan of all packages.
10272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
10372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    @Override
10472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void start() {
10572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        super.start();
1061b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov        scheduleScanAllPackages(false);
10772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
10872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
10972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
11072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Launches an asynchronous scan of all packages owned by the current calling UID.
11172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
11272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void scheduleDirectoryUpdateForCaller() {
11372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        final int callingUid = Binder.getCallingUid();
11472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        if (isAlive()) {
11572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Handler handler = getHandler();
11672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            handler.sendMessage(handler.obtainMessage(MESSAGE_SCAN_PACKAGES_BY_UID, callingUid, 0));
11772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        } else {
11872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            scanPackagesByUid(callingUid);
11972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
12072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
12172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
12272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    protected Handler getHandler() {
12372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        if (mHandler == null) {
12472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            mHandler = new Handler(getLooper()) {
12572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                @Override
12672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                public void handleMessage(Message msg) {
12772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    ContactDirectoryManager.this.handleMessage(msg);
12872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                }
12972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            };
13072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
13172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        return mHandler;
13272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
13372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
13472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    protected void handleMessage(Message msg) {
13572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        switch(msg.what) {
13672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            case MESSAGE_SCAN_ALL_PROVIDERS:
13772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                scanAllPackagesIfNeeded();
13872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                break;
13972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            case MESSAGE_SCAN_PACKAGES_BY_UID:
14072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                scanPackagesByUid(msg.arg1);
14172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                break;
14272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
14372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
14472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
14572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
14672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Scans all packages owned by the specified calling UID looking for contact
14772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * directory providers.
14872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
14972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void scanPackagesByUid(int callingUid) {
15072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        final PackageManager pm = mContext.getPackageManager();
15172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        final String[] callerPackages = pm.getPackagesForUid(callingUid);
15272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        if (callerPackages != null) {
15372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            for (int i = 0; i < callerPackages.length; i++) {
15472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                onPackageChanged(callerPackages[i]);
15572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
15672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
15772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
15872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
15972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
160afb84050536a4472c13efc0e996d31132d254605Dmitri Plotnikov     * Scans all packages for directory content providers.
16172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
16272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private void scanAllPackagesIfNeeded() {
16372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        ContactsDatabaseHelper dbHelper =
16472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                (ContactsDatabaseHelper) mContactsProvider.getDatabaseHelper();
16572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
16672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        String scanComplete = dbHelper.getProperty(PROPERTY_DIRECTORY_SCAN_COMPLETE, "0");
16772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        if (!"0".equals(scanComplete)) {
16872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            return;
16972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
17072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
17172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        long start = SystemClock.currentThreadTimeMillis();
17272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        int count = scanAllPackages();
17372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        dbHelper.setProperty(PROPERTY_DIRECTORY_SCAN_COMPLETE, "1");
17472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        long end = SystemClock.currentThreadTimeMillis();
17572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        Log.i(TAG, "Discovered " + count + " contact directories in " + (end - start) + "ms");
17672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
17772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        // Announce the change to listeners of the contacts authority
17872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        mContactsProvider.notifyChange(false);
17972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
18072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
1811b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov    public void scheduleScanAllPackages(boolean rescan) {
1821b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov        if (rescan) {
1831b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov            ContactsDatabaseHelper dbHelper =
1841b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov                    (ContactsDatabaseHelper) mContactsProvider.getDatabaseHelper();
1851b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov            dbHelper.setProperty(PROPERTY_DIRECTORY_SCAN_COMPLETE, "0");
1861b2a89588e9593756c2627ce1683539f4ffa1e51Dmitri Plotnikov        }
187cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov        if (isAlive()) {
188cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov            getHandler().sendEmptyMessage(MESSAGE_SCAN_ALL_PROVIDERS);
189cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov        } else {
190cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov            scanAllPackagesIfNeeded();
191cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov        }
1926255d756615cfa89fb3411d1840dbe08e1375ffeDmitri Plotnikov    }
1936255d756615cfa89fb3411d1840dbe08e1375ffeDmitri Plotnikov
19472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /* Visible for testing */
19572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    int scanAllPackages() {
19672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        int count = 0;
19772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        PackageManager pm = mContext.getPackageManager();
19872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        List<PackageInfo> packages = pm.getInstalledPackages(
19972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA);
200cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov        if (packages != null) {
201cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov            for (PackageInfo packageInfo : packages) {
202cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov                // Check all packages except the one containing ContactsProvider itself
203cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov                if (!packageInfo.packageName.equals(mContext.getPackageName())) {
204cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov                    count += updateDirectoriesForPackage(packageInfo, true);
205cf832869bcf91b8037d8b7f510a3a213b30764a3Dmitri Plotnikov                }
20672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
20772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
20872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        return count;
20972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
21072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
21172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
21272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Scans the specified package for content directories.  The package may have
21372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * already been removed, so packageName does not necessarily correspond to
21472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * an installed package.
21572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
21672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void onPackageChanged(String packageName) {
21772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        PackageManager pm = mContext.getPackageManager();
21872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        PackageInfo packageInfo = null;
21972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
22072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        try {
22172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            packageInfo = pm.getPackageInfo(packageName,
22272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA);
22372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        } catch (NameNotFoundException e) {
22472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            // The package got removed
22572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            packageInfo = new PackageInfo();
22672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            packageInfo.packageName = packageName;
22772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
22872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
22972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        updateDirectoriesForPackage(packageInfo, false);
23072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov  }
23172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
23272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
23372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Scans the specified package for content directories and updates the {@link Directory}
23472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * table accordingly.
23572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
23672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private int updateDirectoriesForPackage(PackageInfo packageInfo, boolean initialScan) {
23772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        ArrayList<DirectoryInfo> directories = Lists.newArrayList();
23872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
23972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        ProviderInfo[] providers = packageInfo.providers;
24072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        if (providers != null) {
24172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            for (ProviderInfo provider : providers) {
24272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                Bundle metaData = provider.metaData;
24372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                if (metaData != null) {
24472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    Object trueFalse = metaData.get(CONTACT_DIRECTORY_META_DATA);
24572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    if (trueFalse != null && Boolean.TRUE.equals(trueFalse)) {
24672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        queryDirectoriesForAuthority(directories, provider);
24772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    }
24872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                }
24972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
25072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
25172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
25272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        if (directories.size() == 0 && initialScan) {
25372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            return 0;
25472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
25572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
25672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        SQLiteDatabase db = ((ContactsDatabaseHelper) mContactsProvider.getDatabaseHelper())
25772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                .getWritableDatabase();
25872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        db.beginTransaction();
25972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        try {
26072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            updateDirectories(db, directories);
26172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            // Clear out directories that are no longer present
26272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            StringBuilder sb = new StringBuilder(Directory.PACKAGE_NAME + "=?");
26372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            if (!directories.isEmpty()) {
26472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                sb.append(" AND " + Directory._ID + " NOT IN(");
26572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                for (DirectoryInfo info: directories) {
26672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    sb.append(info.id).append(",");
26772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                }
26872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                sb.setLength(sb.length() - 1);  // Remove the extra comma
26972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                sb.append(")");
27072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
27172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            db.delete(Tables.DIRECTORIES, sb.toString(), new String[] { packageInfo.packageName });
27272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            db.setTransactionSuccessful();
27372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        } finally {
27472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            db.endTransaction();
27572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
27672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
27772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        mContactsProvider.resetDirectoryCache();
27872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        return directories.size();
27972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
28072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
28172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
28272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Sends a {@link Directory#CONTENT_URI} request to a specific contact directory
28372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * provider and appends all discovered directories to the directoryInfo list.
28472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
28572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    protected void queryDirectoriesForAuthority(
28672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            ArrayList<DirectoryInfo> directoryInfo, ProviderInfo provider) {
28772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        Uri uri = new Uri.Builder().scheme("content")
28872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                .authority(provider.authority).appendPath("directories").build();
28972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        Cursor cursor = null;
29072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        try {
29172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            cursor = mContext.getContentResolver().query(
29272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    uri, DirectoryQuery.PROJECTION, null, null, null);
29372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            if (cursor == null) {
29472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                Log.i(TAG, providerDescription(provider) + " returned a NULL cursor.");
29572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            } else {
29672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                while (cursor.moveToNext()) {
29772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    DirectoryInfo info = new DirectoryInfo();
29872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    info.packageName = provider.packageName;
29972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    info.authority = provider.authority;
30072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    info.accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
30172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    info.accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
30272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    info.displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
30372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    if (!cursor.isNull(DirectoryQuery.TYPE_RESOURCE_ID)) {
30472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        info.typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
30572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    }
30672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    if (!cursor.isNull(DirectoryQuery.EXPORT_SUPPORT)) {
30772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
30872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        switch (exportSupport) {
30972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            case Directory.EXPORT_SUPPORT_NONE:
31072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            case Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY:
31172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            case Directory.EXPORT_SUPPORT_ANY_ACCOUNT:
31272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                info.exportSupport = exportSupport;
31372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                break;
31472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            default:
31572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                Log.e(TAG, providerDescription(provider)
31672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                        + " - invalid export support flag: " + exportSupport);
31772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        }
31872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    }
31972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    if (!cursor.isNull(DirectoryQuery.SHORTCUT_SUPPORT)) {
32072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        int shortcutSupport = cursor.getInt(DirectoryQuery.SHORTCUT_SUPPORT);
32172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        switch (shortcutSupport) {
32272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            case Directory.SHORTCUT_SUPPORT_NONE:
32372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            case Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY:
32472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            case Directory.SHORTCUT_SUPPORT_FULL:
32572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                info.shortcutSupport = shortcutSupport;
32672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                break;
32772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            default:
32872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                Log.e(TAG, providerDescription(provider)
32972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                                        + " - invalid shortcut support flag: " + shortcutSupport);
33072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                        }
33172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    }
332994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                    if (!cursor.isNull(DirectoryQuery.PHOTO_SUPPORT)) {
333994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                        int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
334994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                        switch (photoSupport) {
335994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                            case Directory.PHOTO_SUPPORT_NONE:
336994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                            case Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY:
337994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                            case Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY:
338994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                            case Directory.PHOTO_SUPPORT_FULL:
339994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                                info.photoSupport = photoSupport;
340994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                                break;
341994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                            default:
342994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                                Log.e(TAG, providerDescription(provider)
343994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                                        + " - invalid photo support flag: " + photoSupport);
344994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                        }
345994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov                    }
34672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    directoryInfo.add(info);
34772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                }
34872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
34972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        } catch (Throwable t) {
35072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Log.e(TAG, providerDescription(provider) + " exception", t);
35172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        } finally {
35272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            if (cursor != null) {
35372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                cursor.close();
35472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
35572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
35672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
35772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
35872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    /**
35972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * Updates the directories tables in the database to match the info received
36072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     * from directory providers.
36172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov     */
36272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    private void updateDirectories(SQLiteDatabase db, ArrayList<DirectoryInfo> directoryInfo) {
36372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
36472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        // Insert or replace existing directories.
36572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        // This happens so infrequently that we can use a less-then-optimal one-a-time approach
36672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        for (DirectoryInfo info : directoryInfo) {
36772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            ContentValues values = new ContentValues();
36872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.PACKAGE_NAME, info.packageName);
36972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.DIRECTORY_AUTHORITY, info.authority);
37072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.ACCOUNT_NAME, info.accountName);
37172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.ACCOUNT_TYPE, info.accountType);
37272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.TYPE_RESOURCE_ID, info.typeResourceId);
37372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.DISPLAY_NAME, info.displayName);
37472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.EXPORT_SUPPORT, info.exportSupport);
37572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            values.put(Directory.SHORTCUT_SUPPORT, info.shortcutSupport);
376994c32a995a85937faf59e37a9fc88b526470d7dDmitri Plotnikov            values.put(Directory.PHOTO_SUPPORT, info.photoSupport);
37772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
37872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            Cursor cursor = db.query(Tables.DIRECTORIES, new String[] { Directory._ID },
37972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    Directory.PACKAGE_NAME + "=? AND " + Directory.DIRECTORY_AUTHORITY + "=? AND "
38072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            + Directory.ACCOUNT_NAME + "=? AND " + Directory.ACCOUNT_TYPE + "=?",
38172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    new String[] {
38272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            info.packageName, info.authority, info.accountName, info.accountType },
38372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    null, null, null);
38472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            try {
38572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                long id;
38672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                if (cursor.moveToFirst()) {
38772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    id = cursor.getLong(0);
38872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    db.update(Tables.DIRECTORIES, values, Directory._ID + "=?",
38972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                            new String[] { String.valueOf(id) });
39072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                } else {
39172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                    id = db.insert(Tables.DIRECTORIES, null, values);
39272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                }
39372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                info.id = id;
39472e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            } finally {
39572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov                cursor.close();
39672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            }
39772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        }
39872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
39972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov
40072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    protected String providerDescription(ProviderInfo provider) {
40172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        return "Directory provider " + provider.packageName + "(" + provider.authority + ")";
40272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    }
40372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov}
404