19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.content;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
197a1355950172b7a549820e9a2cd4a9b2099ec32fDianne Hackbornimport android.accounts.Account;
2016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tateimport android.app.ActivityManager;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.IContentObserver;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.sqlite.SQLiteException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
241b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport android.os.Binder;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
27231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackbornimport android.os.Parcel;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
30f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
321b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport android.util.SparseIntArray;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.Manifest;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
3716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tateimport java.security.InvalidParameterException;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
391b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport java.util.Collections;
401b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport java.util.Comparator;
41c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintanaimport java.util.List;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
46231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackbornpublic final class ContentService extends IContentService.Stub {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "ContentService";
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mFactoryTest;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final ObserverNode mRootNode = new ObserverNode("");
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SyncManager mSyncManager = null;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Object mSyncManagerLock = new Object();
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SyncManager getSyncManager() {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(mSyncManagerLock) {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (SQLiteException e) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Can't create SyncManager", e);
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSyncManager;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "caller doesn't have the DUMP permission");
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSyncManager == null) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("No SyncManager created!  (Disk full?)");
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncManager.dump(fd, pw);
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
801b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            pw.println();
811b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            pw.println("Observer tree:");
821b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            synchronized (mRootNode) {
831b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                int[] counts = new int[2];
841b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                final SparseIntArray pidCounts = new SparseIntArray();
851b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
861b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.println();
871b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                ArrayList<Integer> sorted = new ArrayList<Integer>();
881b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<pidCounts.size(); i++) {
891b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    sorted.add(pidCounts.keyAt(i));
901b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
911b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                Collections.sort(sorted, new Comparator<Integer>() {
921b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    @Override
931b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    public int compare(Integer lhs, Integer rhs) {
941b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        int lc = pidCounts.get(lhs);
951b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        int rc = pidCounts.get(rhs);
961b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        if (lc < rc) {
971b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            return 1;
981b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        } else if (lc > rc) {
991b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            return -1;
1001b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        }
1011b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        return 0;
1021b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    }
1031b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn
1041b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                });
1051b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<sorted.size(); i++) {
1061b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    int pid = sorted.get(i);
1071b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    pw.print("  pid "); pw.print(pid); pw.print(": ");
1081b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            pw.print(pidCounts.get(pid)); pw.println(" observers");
1091b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
1101b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.println();
1111b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.print(" Total number of nodes: "); pw.println(counts[0]);
1121b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.print(" Total number of observers: "); pw.println(counts[1]);
1131b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
119231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    @Override
120231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
121231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            throws RemoteException {
122231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
123231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            return super.onTransact(code, data, reply, flags);
124231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } catch (RuntimeException e) {
125231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // The content service only throws security exceptions, so let's
126231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // log all others.
127231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (!(e instanceof SecurityException)) {
128231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                Log.e(TAG, "Content Service Crash", e);
129231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
130231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            throw e;
131231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
132231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
133231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*package*/ ContentService(Context context, boolean factoryTest) {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFactoryTest = factoryTest;
13726ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    }
13826ff6626fc4ee0ae46f01ad309b366921da589feKenny Root
13926ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    public void systemReady() {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        getSyncManager();
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    /**
14416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * Register a content observer tied to a specific user's view of the provider.
14516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * @param userHandle the user whose view of the provider is to be observed.  May be
14616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     the calling user without requiring any permission, otherwise the caller needs to
14716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
14816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     USER_CURRENT are properly handled; all other pseudousers are forbidden.
14916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     */
15016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    @Override
15116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    public void registerContentObserver(Uri uri, boolean notifyForDescendants,
15216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            IContentObserver observer, int userHandle) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (observer == null || uri == null) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("You must pass a valid uri and observer");
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
15716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        final int callingUser = UserHandle.getCallingUserId();
15816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (callingUser != userHandle) {
15916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
16016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    "no permission to observe other users' provider view");
16116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
16216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
16316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (userHandle < 0) {
16416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            if (userHandle == UserHandle.USER_CURRENT) {
16516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                userHandle = ActivityManager.getCurrentUser();
16616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            } else if (userHandle != UserHandle.USER_ALL) {
16716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                throw new InvalidParameterException("Bad user handle for registerContentObserver: "
16816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        + userHandle);
16916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            }
17016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
17116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mRootNode) {
17316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
17416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
17543a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato            if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
17616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    " with notifyForDescendants " + notifyForDescendants);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    public void registerContentObserver(Uri uri, boolean notifyForDescendants,
18116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            IContentObserver observer) {
18216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        registerContentObserver(uri, notifyForDescendants, observer,
18316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                UserHandle.getCallingUserId());
18416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    }
18516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unregisterContentObserver(IContentObserver observer) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (observer == null) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("You must pass a valid observer");
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mRootNode) {
191002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana            mRootNode.removeObserverLocked(observer);
19243a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato            if (false) Log.v(TAG, "Unregistered observer " + observer);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    /**
19716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * Notify observers of a particular user's view of the provider.
19816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * @param userHandle the user whose view of the provider is to be notified.  May be
19916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     the calling user without requiring any permission, otherwise the caller needs to
20016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
20116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     USER_CURRENT are properly interpreted; no other pseudousers are allowed.
20216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     */
20316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    @Override
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notifyChange(Uri uri, IContentObserver observer,
20516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            boolean observerWantsSelfNotifications, boolean syncToNetwork,
20616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            int userHandle) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Log.isLoggable(TAG, Log.VERBOSE)) {
20816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle
20916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
21016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
21116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
21216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        // Notify for any user other than the caller's own requires permission.
21316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        final int callingUserHandle = UserHandle.getCallingUserId();
21416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (userHandle != callingUserHandle) {
21516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
21616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    "no permission to notify other users");
21716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
21816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
21916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        // We passed the permission check; resolve pseudouser targets as appropriate
22016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (userHandle < 0) {
22116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            if (userHandle == UserHandle.USER_CURRENT) {
22216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                userHandle = ActivityManager.getCurrentUser();
22316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            } else if (userHandle != UserHandle.USER_ALL) {
22416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                throw new InvalidParameterException("Bad user handle for notifyChange: "
22516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        + userHandle);
22616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mRootNode) {
235002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
23616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        userHandle, calls);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numCalls = calls.size();
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<numCalls; i++) {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverCall oc = calls.get(i);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
242655e66bceba7595a2b80e7a328433e6ed5dc28a9Jeff Brown                    oc.mObserver.onChange(oc.mSelfChange, uri);
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException ex) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    synchronized (mRootNode) {
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(TAG, "Found dead observer, removing");
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        IBinder binder = oc.mObserver.asBinder();
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final ArrayList<ObserverNode.ObserverEntry> list
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                = oc.mNode.mObservers;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int numList = list.size();
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        for (int j=0; j<numList; j++) {
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ObserverNode.ObserverEntry oe = list.get(j);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (oe.observer.asBinder() == binder) {
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                list.remove(j);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                j--;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                numList--;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncToNetwork) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SyncManager syncManager = getSyncManager();
266ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                if (syncManager != null) {
26716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle,
26804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            uri.getAuthority());
269ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    public void notifyChange(Uri uri, IContentObserver observer,
27716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            boolean observerWantsSelfNotifications, boolean syncToNetwork) {
27816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
27916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                UserHandle.getCallingUserId());
28016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    }
28116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Hide this class since it is not part of api,
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but current unittest framework requires it to be public
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final class ObserverCall {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ObserverNode mNode;
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IContentObserver mObserver;
29186de0590b94bcce27e3038c27464bed510bb564aJeff Brown        final boolean mSelfChange;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29386de0590b94bcce27e3038c27464bed510bb564aJeff Brown        ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) {
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNode = node;
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mObserver = observer;
29686de0590b94bcce27e3038c27464bed510bb564aJeff Brown            mSelfChange = selfChange;
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
300ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void requestSync(Account account, String authority, Bundle extras) {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentResolver.validateSyncExtrasBundle(extras);
302f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
30304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SyncManager syncManager = getSyncManager();
309ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            if (syncManager != null) {
31004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.scheduleSync(account, userId, authority, extras, 0 /* no delay */,
3114a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana                        false /* onlyThoseWithUnkownSyncableState */);
312ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            }
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clear all scheduled sync operations that match the uri and cancel the active sync
320ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * if they match the authority and account, if they are present.
321ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param account filter the pending and active syncs to cancel using this account
322ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param authority filter the pending and active syncs to cancel using this authority
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
324ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void cancelSync(Account account, String authority) {
325f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
32604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SyncManager syncManager = getSyncManager();
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncManager != null) {
33304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.clearScheduledSyncOperations(account, userId, authority);
33404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.cancelActiveSync(account, userId, authority);
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
341ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    /**
342ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * Get information about the SyncAdapters that are known to the system.
343ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @return an array of SyncAdapters that have registered with the system
344ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     */
345ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public SyncAdapterType[] getSyncAdapterTypes() {
346ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        // This makes it so that future permission checks will be in the context of this
347ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        // process rather than the caller's process. We will restore this before returning.
3486ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final int userId = UserHandle.getCallingUserId();
3496ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final long identityToken = clearCallingIdentity();
350ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        try {
351ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            SyncManager syncManager = getSyncManager();
3526ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            return syncManager.getSyncAdapterTypes(userId);
353ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        } finally {
354ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            restoreCallingIdentity(identityToken);
355ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        }
356ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    }
357b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
358ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public boolean getSyncAutomatically(Account account, String providerName) {
359231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
360231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync settings");
361f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
36204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
363231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
364231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
365231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
366231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
367ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return syncManager.getSyncStorageEngine().getSyncAutomatically(
36804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName);
369231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
370231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
371231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
372231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
373231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
374231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
375231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
376ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void setSyncAutomatically(Account account, String providerName, boolean sync) {
377231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
378231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to write the sync settings");
379f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
38004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
381231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
382231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
383231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
384231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
385ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                syncManager.getSyncStorageEngine().setSyncAutomatically(
38604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName, sync);
387231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
388231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
389231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
390231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
391231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
392231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
393c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    public void addPeriodicSync(Account account, String authority, Bundle extras,
394c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            long pollFrequency) {
395c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
396c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                "no permission to write the sync settings");
397f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
39804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
399c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        long identityToken = clearCallingIdentity();
400c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        try {
401c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            getSyncManager().getSyncStorageEngine().addPeriodicSync(
40204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    account, userId, authority, extras, pollFrequency);
403c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        } finally {
404c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            restoreCallingIdentity(identityToken);
405c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
406c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    }
407c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
408c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    public void removePeriodicSync(Account account, String authority, Bundle extras) {
409c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
410c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                "no permission to write the sync settings");
411f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
41204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
413c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        long identityToken = clearCallingIdentity();
414c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        try {
41504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            getSyncManager().getSyncStorageEngine().removePeriodicSync(account, userId, authority,
41604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    extras);
417c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        } finally {
418c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            restoreCallingIdentity(identityToken);
419c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
420c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    }
421c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
422c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
423c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
424c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                "no permission to read the sync settings");
425f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
42604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
427c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        long identityToken = clearCallingIdentity();
428c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        try {
429c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
43004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    account, userId, providerName);
431c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        } finally {
432c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            restoreCallingIdentity(identityToken);
433c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
434c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    }
435c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
4365e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    public int getIsSyncable(Account account, String providerName) {
4375e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
4385e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                "no permission to read the sync settings");
439f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
44004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
4415e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        long identityToken = clearCallingIdentity();
4425e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        try {
4435e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            SyncManager syncManager = getSyncManager();
4445e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            if (syncManager != null) {
4455e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                return syncManager.getSyncStorageEngine().getIsSyncable(
44604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName);
4475e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            }
4485e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        } finally {
4495e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            restoreCallingIdentity(identityToken);
4505e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        }
4515e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        return -1;
4525e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    }
4535e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana
4545e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    public void setIsSyncable(Account account, String providerName, int syncable) {
4555e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
4565e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                "no permission to write the sync settings");
457f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
45804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
4595e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        long identityToken = clearCallingIdentity();
4605e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        try {
4615e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            SyncManager syncManager = getSyncManager();
4625e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            if (syncManager != null) {
4635e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                syncManager.getSyncStorageEngine().setIsSyncable(
46404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName, syncable);
4655e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            }
4665e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        } finally {
4675e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            restoreCallingIdentity(identityToken);
4685e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        }
4695e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    }
4705e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana
471ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public boolean getMasterSyncAutomatically() {
472231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
473231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync settings");
474f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
47504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
476231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
477231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
478231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
479231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
48004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
481231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
482231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
483231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
484231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
485231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
486231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
487b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
488ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void setMasterSyncAutomatically(boolean flag) {
489231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
490231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to write the sync settings");
491f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
49204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
493231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
494231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
495231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
496231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
49704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
498231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
499231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
500231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
501231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
502231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
503231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
5047a1355950172b7a549820e9a2cd4a9b2099ec32fDianne Hackborn    public boolean isSyncActive(Account account, String authority) {
505231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
506231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
507f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
50804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
509231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
510231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
511231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
512231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
513231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                return syncManager.getSyncStorageEngine().isSyncActive(
51404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, authority);
515231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
516231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
517231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
518231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
519231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
520231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
521b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
522c6a69559cb62bd20166c0c9684e64c60d779da38Fred Quintana    public List<SyncInfo> getCurrentSyncs() {
523231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
524231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
525f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
52604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
527231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
528231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
52904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
530231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
531231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
532231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
533231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
534b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
535ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public SyncStatusInfo getSyncStatus(Account account, String authority) {
536231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
537231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
538f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
53904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
540231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
541231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
542231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
543231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
544b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache                return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
54504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, authority);
546231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
547231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
548231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
549231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
550231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return null;
551231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
552b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
553ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public boolean isSyncPending(Account account, String authority) {
554231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
555231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
556f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
55704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
558231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
559231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
560231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
561231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
56204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority);
563231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
564231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
565231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
566231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
567231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
568231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
569b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
570231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
571231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
572231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
573231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
5741b487ec44b6b5594914d52fa427bec4f29a60541Fred Quintana            if (syncManager != null && callback != null) {
575ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
576231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
577231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
578231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
579231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
580231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
581b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
582231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public void removeStatusChangeListener(ISyncStatusObserver callback) {
583231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
584231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
585231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
5861b487ec44b6b5594914d52fa427bec4f29a60541Fred Quintana            if (syncManager != null && callback != null) {
587ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
588231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
589231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
590231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
591231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
592231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
593b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
59426ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    public static ContentService main(Context context, boolean factoryTest) {
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentService service = new ContentService(context, factoryTest);
596231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return service;
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Hide this class since it is not part of api,
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but current unittest framework requires it to be public
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final class ObserverNode {
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class ObserverEntry implements IBinder.DeathRecipient {
607002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana            public final IContentObserver observer;
6081b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public final int uid;
6091b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public final int pid;
61016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            public final boolean notifyForDescendants;
61116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            private final int userHandle;
612002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana            private final Object observersLock;
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6141b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
61516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    int _uid, int _pid, int _userHandle) {
616002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                this.observersLock = observersLock;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                observer = o;
6181b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                uid = _uid;
6191b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pid = _pid;
62016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                userHandle = _userHandle;
62116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                notifyForDescendants = n;
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    observer.asBinder().linkToDeath(this, 0);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    binderDied();
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
630002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                synchronized (observersLock) {
631002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                    removeObserverLocked(observer);
632002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6341b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn
6351b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
6361b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    String name, String prefix, SparseIntArray pidCounts) {
6371b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pidCounts.put(pid, pidCounts.get(pid)+1);
6381b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.print(prefix); pw.print(name); pw.print(": pid=");
6391b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        pw.print(pid); pw.print(" uid=");
64016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        pw.print(uid); pw.print(" user=");
64116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        pw.print(userHandle); pw.print(" target=");
6421b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        pw.println(Integer.toHexString(System.identityHashCode(
6431b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                                observer != null ? observer.asBinder() : null)));
6441b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int INSERT_TYPE = 0;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int UPDATE_TYPE = 1;
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DELETE_TYPE = 2;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mName;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ObserverNode(String name) {
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mName = name;
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6591b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn        public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
6601b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                String name, String prefix, int[] counts, SparseIntArray pidCounts) {
6611b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            String innerName = null;
6621b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            if (mObservers.size() > 0) {
6631b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                if ("".equals(name)) {
6641b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    innerName = mName;
6651b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                } else {
6661b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    innerName = name + "/" + mName;
6671b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
6681b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<mObservers.size(); i++) {
6691b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    counts[1]++;
6701b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
6711b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            pidCounts);
6721b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
6731b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
6741b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            if (mChildren.size() > 0) {
6751b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                if (innerName == null) {
6761b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    if ("".equals(name)) {
6771b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        innerName = mName;
6781b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    } else {
6791b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        innerName = name + "/" + mName;
6801b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    }
6811b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
6821b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<mChildren.size(); i++) {
6831b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    counts[0]++;
6841b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
6851b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            counts, pidCounts);
6861b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
6871b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
6881b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn        }
6891b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String getUriSegment(Uri uri, int index) {
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uri != null) {
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index == 0) {
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return uri.getAuthority();
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return uri.getPathSegments().get(index - 1);
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int countUriSegments(Uri uri) {
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uri == null) {
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uri.getPathSegments().size() + 1;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
70916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        // Invariant:  userHandle is either a hard user number or is USER_ALL
710002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        public void addObserverLocked(Uri uri, IContentObserver observer,
71116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean notifyForDescendants, Object observersLock,
71216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                int uid, int pid, int userHandle) {
71316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
71416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    uid, pid, userHandle);
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
717002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        private void addObserverLocked(Uri uri, int index, IContentObserver observer,
71816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean notifyForDescendants, Object observersLock,
71916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                int uid, int pid, int userHandle) {
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If this is the leaf node add the observer
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index == countUriSegments(uri)) {
72216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
72316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        uid, pid, userHandle));
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Look to see if the proper child already exists
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String segment = getUriSegment(uri, index);
729f51266471cb6c3e824435ae6e416012a62266d52Anthony Newnam            if (segment == null) {
730f51266471cb6c3e824435ae6e416012a62266d52Anthony Newnam                throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
731f51266471cb6c3e824435ae6e416012a62266d52Anthony Newnam            }
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mChildren.size();
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverNode node = mChildren.get(i);
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (node.mName.equals(segment)) {
73616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
73716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                            observersLock, uid, pid, userHandle);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // No child found, create one
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ObserverNode node = new ObserverNode(segment);
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChildren.add(node);
74516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
74616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    observersLock, uid, pid, userHandle);
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        public boolean removeObserverLocked(IContentObserver observer) {
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mChildren.size();
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
752002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                boolean empty = mChildren.get(i).removeObserverLocked(observer);
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (empty) {
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mChildren.remove(i);
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    i--;
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    size--;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IBinder observerBinder = observer.asBinder();
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size = mObservers.size();
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverEntry entry = mObservers.get(i);
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (entry.observer.asBinder() == observerBinder) {
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mObservers.remove(i);
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We no longer need to listen for death notifications. Remove it.
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    observerBinder.unlinkToDeath(entry, 0);
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mChildren.size() == 0 && mObservers.size() == 0) {
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
778002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
77916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean observerWantsSelfNotifications, int targetUserHandle,
78016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                ArrayList<ObserverCall> calls) {
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mObservers.size();
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IBinder observerBinder = observer == null ? null : observer.asBinder();
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverEntry entry = mObservers.get(i);
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
78616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                // Don't notify the observer if it sent the notification and isn't interested
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // in self notifications
78886de0590b94bcce27e3038c27464bed510bb564aJeff Brown                boolean selfChange = (entry.observer.asBinder() == observerBinder);
78986de0590b94bcce27e3038c27464bed510bb564aJeff Brown                if (selfChange && !observerWantsSelfNotifications) {
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                // Does this observer match the target user?
79416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                if (targetUserHandle == UserHandle.USER_ALL
79516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        || entry.userHandle == UserHandle.USER_ALL
79616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        || targetUserHandle == entry.userHandle) {
79716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    // Make sure the observer is interested in the notification
79816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    if (leaf || (!leaf && entry.notifyForDescendants)) {
79916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        calls.add(new ObserverCall(this, entry.observer, selfChange));
80016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    }
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
80516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        /**
80616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate         * targetUserHandle is either a hard user handle or is USER_ALL
80716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate         */
808002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
80916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean observerWantsSelfNotifications, int targetUserHandle,
81016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                ArrayList<ObserverCall> calls) {
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String segment = null;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int segmentCount = countUriSegments(uri);
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index >= segmentCount) {
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This is the leaf node, notify all observers
81516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
81616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        targetUserHandle, calls);
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (index < segmentCount){
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                segment = getUriSegment(uri, index);
81916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                // Notify any observers at this level who are interested in descendants
82016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
82116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        targetUserHandle, calls);
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mChildren.size();
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverNode node = mChildren.get(i);
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (segment == null || node.mName.equals(segment)) {
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We found the child,
82986de0590b94bcce27e3038c27464bed510bb564aJeff Brown                    node.collectObserversLocked(uri, index + 1,
83016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                            observer, observerWantsSelfNotifications, targetUserHandle, calls);
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (segment != null) {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
839