summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/contacts/ProfileAwareUriMatcher.java
blob: ee5ec03c0f05e4c767ece97f325f86fec7c00df1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.providers.contacts;

import android.content.UriMatcher;
import android.net.Uri;
import android.provider.ContactsContract;

import com.google.android.collect.Lists;
import com.google.android.collect.Maps;

import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * A subclass of URI matcher with additional logic and awareness around profile-specific URIs.
 */
public class ProfileAwareUriMatcher extends UriMatcher {

    private static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/");

    private static final String PROFILE_SEGMENT = "profile";
    private static final String LOOKUP_SEGMENT = "lookup";
    private static final String VCARD_SEGMENT = "as_vcard";
    private static final String ID_SEGMENT = "#";
    private static final String WILDCARD_SEGMENT = "*";

    // URIs matching to these constants must always use the profile database.
    private static final List<Integer> PROFILE_URIS = Lists.newArrayList();

    // URIs in this map will direct to the profile database if the ID (which is at the segment
    // path with the location specified by the value in the map) is in the profile ID-space.
    private static final Map<Integer, Integer> PROFILE_URI_ID_MAP = Maps.newHashMap();

    // URIs in this map will direct to the profile database if the lookup key (which is at the
    // segment path with the location specified by the value in the map) is the special profile
    // lookup key (see {@link ProfileAggregator#PROFILE_LOOKUP_KEY}).
    private static final Map<Integer, Integer> PROFILE_URI_LOOKUP_KEY_MAP = Maps.newHashMap();

    /**
     * Creates the root node of the URI tree.
     *
     * @param code the code to match for the root URI
     */
    public ProfileAwareUriMatcher(int code) {
        super(code);
    }

    @Override
    public void addURI(String authority, String path, int code) {
        super.addURI(authority, path, code);

        // Do a second tokenization pass to determine whether the URI may apply to profiles.
        if (path != null) {
            String newPath = path;
            // Strip leading slash if present.
            if (path.length() > 0 && path.charAt(0) == '/') {
                newPath = path.substring(1);
            }
            String[] tokens = PATH_SPLIT_PATTERN.split(newPath);

            if (tokens != null) {

                // Keep track of whether we've passed a "lookup" token in the path; wildcards after
                // that token will be interpreted as lookup keys.  For our purposes, vcard paths
                // also count as lookup tokens, since the vcard is specified by lookup key.
                boolean afterLookup = false;
                for (int i = 0; i < tokens.length; i++) {
                    String token = tokens[i];
                    if (token.equals(PROFILE_SEGMENT)) {
                        PROFILE_URIS.add(code);
                        return;
                    } else if (token.equals(LOOKUP_SEGMENT)
                            || token.equals(VCARD_SEGMENT)) {
                        afterLookup = true;
                        continue;
                    } else if (token.equals(ID_SEGMENT)) {
                        PROFILE_URI_ID_MAP.put(code, i);
                    } else if (token.equals(WILDCARD_SEGMENT)) {
                        if (afterLookup) {
                            PROFILE_URI_LOOKUP_KEY_MAP.put(code, i);
                        }
                    }
                    afterLookup = false;
                }
            }
        }
    }

    /**
     * Determines whether the given URI is intended for the profile DB rather than contacts.
     * This is true under any of three conditions:
     * 1. The URI itself is specifically for the profile (it contains a "profile" segment).
     * 2. The URI contains ID references that are in the profile ID-space.
     * 3. The URI contains lookup key references that match the special profile lookup key.
     * @param uri The URI to examine.
     * @return Whether the operation for this URI is intended for the profile DB.
     */
    public boolean mapsToProfile(Uri uri) {
        int match = match(uri);
        if (PROFILE_URIS.contains(match)) {
            return true;
        } else if (PROFILE_URI_ID_MAP.containsKey(match)) {
            int idSegment = PROFILE_URI_ID_MAP.get(match);
            long id = Long.parseLong(uri.getPathSegments().get(idSegment));
            if (ContactsContract.isProfileId(id)) {
                return true;
            }
        } else if (PROFILE_URI_LOOKUP_KEY_MAP.containsKey(match)) {
            int lookupKeySegment = PROFILE_URI_LOOKUP_KEY_MAP.get(match);
            String lookupKey = uri.getPathSegments().get(lookupKeySegment);
            if (ContactLookupKey.PROFILE_LOOKUP_KEY.equals(lookupKey)) {
                return true;
            }
        }
        return false;
    }
}