| 14792 |
manas |
1 |
/**
|
|
|
2 |
* Copyright 2010-present Facebook.
|
|
|
3 |
*
|
|
|
4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
5 |
* you may not use this file except in compliance with the License.
|
|
|
6 |
* You may obtain a copy of the License at
|
|
|
7 |
*
|
|
|
8 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
9 |
*
|
|
|
10 |
* Unless required by applicable law or agreed to in writing, software
|
|
|
11 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13 |
* See the License for the specific language governing permissions and
|
|
|
14 |
* limitations under the License.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
package com.facebook.internal;
|
|
|
18 |
|
|
|
19 |
import android.content.ContentResolver;
|
|
|
20 |
import android.content.Context;
|
|
|
21 |
import android.content.Intent;
|
|
|
22 |
import android.content.pm.*;
|
|
|
23 |
import android.database.Cursor;
|
|
|
24 |
import android.net.Uri;
|
|
|
25 |
import android.os.Build;
|
|
|
26 |
import android.os.Bundle;
|
|
|
27 |
import android.text.TextUtils;
|
|
|
28 |
import com.facebook.FacebookException;
|
|
|
29 |
import com.facebook.FacebookOperationCanceledException;
|
|
|
30 |
import com.facebook.SessionDefaultAudience;
|
|
|
31 |
import com.facebook.Settings;
|
|
|
32 |
|
|
|
33 |
import java.util.*;
|
|
|
34 |
|
|
|
35 |
/**
|
|
|
36 |
* com.facebook.internal is solely for the use of other packages within the Facebook SDK for Android. Use of
|
|
|
37 |
* any of the classes in this package is unsupported, and they may be modified or removed without warning at
|
|
|
38 |
* any time.
|
|
|
39 |
*/
|
|
|
40 |
public final class NativeProtocol {
|
|
|
41 |
|
|
|
42 |
public static final int NO_PROTOCOL_AVAILABLE = -1;
|
|
|
43 |
|
|
|
44 |
private static final String FACEBOOK_PROXY_AUTH_ACTIVITY = "com.facebook.katana.ProxyAuth";
|
|
|
45 |
private static final String FACEBOOK_TOKEN_REFRESH_ACTIVITY = "com.facebook.katana.platform.TokenRefreshService";
|
|
|
46 |
|
|
|
47 |
public static final String FACEBOOK_PROXY_AUTH_PERMISSIONS_KEY = "scope";
|
|
|
48 |
public static final String FACEBOOK_PROXY_AUTH_APP_ID_KEY = "client_id";
|
|
|
49 |
public static final String FACEBOOK_PROXY_AUTH_E2E_KEY = "e2e";
|
|
|
50 |
|
|
|
51 |
// ---------------------------------------------------------------------------------------------
|
|
|
52 |
// Native Protocol updated 2012-11
|
|
|
53 |
|
|
|
54 |
static final String INTENT_ACTION_PLATFORM_ACTIVITY = "com.facebook.platform.PLATFORM_ACTIVITY";
|
|
|
55 |
static final String INTENT_ACTION_PLATFORM_SERVICE = "com.facebook.platform.PLATFORM_SERVICE";
|
|
|
56 |
|
|
|
57 |
public static final int PROTOCOL_VERSION_20121101 = 20121101;
|
|
|
58 |
public static final int PROTOCOL_VERSION_20130502 = 20130502;
|
|
|
59 |
public static final int PROTOCOL_VERSION_20130618 = 20130618;
|
|
|
60 |
public static final int PROTOCOL_VERSION_20131107 = 20131107;
|
|
|
61 |
public static final int PROTOCOL_VERSION_20140204 = 20140204;
|
|
|
62 |
public static final int PROTOCOL_VERSION_20140324 = 20140324;
|
|
|
63 |
public static final int PROTOCOL_VERSION_20140701 = 20140701;
|
|
|
64 |
public static final int PROTOCOL_VERSION_20141001 = 20141001;
|
|
|
65 |
public static final int PROTOCOL_VERSION_20141028 = 20141028;
|
|
|
66 |
public static final int PROTOCOL_VERSION_20141107 = 20141107; // Bucketed Result Intents
|
|
|
67 |
|
|
|
68 |
public static final String EXTRA_PROTOCOL_VERSION = "com.facebook.platform.protocol.PROTOCOL_VERSION";
|
|
|
69 |
public static final String EXTRA_PROTOCOL_ACTION = "com.facebook.platform.protocol.PROTOCOL_ACTION";
|
|
|
70 |
public static final String EXTRA_PROTOCOL_CALL_ID = "com.facebook.platform.protocol.CALL_ID";
|
|
|
71 |
public static final String EXTRA_GET_INSTALL_DATA_PACKAGE = "com.facebook.platform.extra.INSTALLDATA_PACKAGE";
|
|
|
72 |
|
|
|
73 |
public static final String EXTRA_PROTOCOL_BRIDGE_ARGS =
|
|
|
74 |
"com.facebook.platform.protocol.BRIDGE_ARGS";
|
|
|
75 |
|
|
|
76 |
public static final String EXTRA_PROTOCOL_METHOD_ARGS =
|
|
|
77 |
"com.facebook.platform.protocol.METHOD_ARGS";
|
|
|
78 |
|
|
|
79 |
public static final String EXTRA_PROTOCOL_METHOD_RESULTS =
|
|
|
80 |
"com.facebook.platform.protocol.RESULT_ARGS";
|
|
|
81 |
|
|
|
82 |
public static final String BRIDGE_ARG_APP_NAME_STRING = "app_name";
|
|
|
83 |
public static final String BRIDGE_ARG_ACTION_ID_STRING = "action_id";
|
|
|
84 |
public static final String BRIDGE_ARG_ERROR_BUNDLE = "error";
|
|
|
85 |
|
|
|
86 |
// Messages supported by PlatformService:
|
|
|
87 |
public static final int MESSAGE_GET_ACCESS_TOKEN_REQUEST = 0x10000;
|
|
|
88 |
public static final int MESSAGE_GET_ACCESS_TOKEN_REPLY = 0x10001;
|
|
|
89 |
static final int MESSAGE_GET_PROTOCOL_VERSIONS_REQUEST = 0x10002;
|
|
|
90 |
static final int MESSAGE_GET_PROTOCOL_VERSIONS_REPLY = 0x10003;
|
|
|
91 |
public static final int MESSAGE_GET_INSTALL_DATA_REQUEST = 0x10004;
|
|
|
92 |
public static final int MESSAGE_GET_INSTALL_DATA_REPLY = 0x10005;
|
|
|
93 |
public static final int MESSAGE_GET_LIKE_STATUS_REQUEST = 0x10006;
|
|
|
94 |
public static final int MESSAGE_GET_LIKE_STATUS_REPLY = 0x10007;
|
|
|
95 |
|
|
|
96 |
// MESSAGE_ERROR_REPLY data keys:
|
|
|
97 |
// See STATUS_*
|
|
|
98 |
|
|
|
99 |
// MESSAGE_GET_ACCESS_TOKEN_REQUEST data keys:
|
|
|
100 |
// EXTRA_APPLICATION_ID
|
|
|
101 |
|
|
|
102 |
// MESSAGE_GET_ACCESS_TOKEN_REPLY data keys:
|
|
|
103 |
// EXTRA_ACCESS_TOKEN
|
|
|
104 |
// EXTRA_EXPIRES_SECONDS_SINCE_EPOCH
|
|
|
105 |
// EXTRA_PERMISSIONS
|
|
|
106 |
|
|
|
107 |
// MESSAGE_GET_LIKE_STATUS_REQUEST data keys:
|
|
|
108 |
// EXTRA_APPLICATION_ID
|
|
|
109 |
// EXTRA_OBJECT_ID
|
|
|
110 |
|
|
|
111 |
// MESSAGE_GET_LIKE_STATUS_REPLY data keys:
|
|
|
112 |
// EXTRA_OBJECT_IS_LIKED
|
|
|
113 |
// EXTRA_LIKE_COUNT_STRING_WITH_LIKE
|
|
|
114 |
// EXTRA_LIKE_COUNT_STRING_WITHOUT_LIKE
|
|
|
115 |
// EXTRA_SOCIAL_SENTENCE_WITH_LIKE
|
|
|
116 |
// EXTRA_SOCIAL_SENTENCE_WITHOUT_LIKE
|
|
|
117 |
// EXTRA_UNLIKE_TOKEN
|
|
|
118 |
|
|
|
119 |
// MESSAGE_GET_PROTOCOL_VERSIONS_REPLY data keys:
|
|
|
120 |
static final String EXTRA_PROTOCOL_VERSIONS = "com.facebook.platform.extra.PROTOCOL_VERSIONS";
|
|
|
121 |
|
|
|
122 |
// Values of EXTRA_PROTOCOL_ACTION supported by PlatformActivity:
|
|
|
123 |
public static final String ACTION_FEED_DIALOG = "com.facebook.platform.action.request.FEED_DIALOG";
|
|
|
124 |
public static final String ACTION_MESSAGE_DIALOG = "com.facebook.platform.action.request.MESSAGE_DIALOG";
|
|
|
125 |
public static final String ACTION_OGACTIONPUBLISH_DIALOG =
|
|
|
126 |
"com.facebook.platform.action.request.OGACTIONPUBLISH_DIALOG";
|
|
|
127 |
public static final String ACTION_OGMESSAGEPUBLISH_DIALOG =
|
|
|
128 |
"com.facebook.platform.action.request.OGMESSAGEPUBLISH_DIALOG";
|
|
|
129 |
public static final String ACTION_LIKE_DIALOG =
|
|
|
130 |
"com.facebook.platform.action.request.LIKE_DIALOG";
|
|
|
131 |
|
|
|
132 |
// Values of EXTRA_PROTOCOL_ACTION values returned by PlatformActivity:
|
|
|
133 |
public static final String ACTION_FEED_DIALOG_REPLY =
|
|
|
134 |
"com.facebook.platform.action.reply.FEED_DIALOG";
|
|
|
135 |
public static final String ACTION_MESSAGE_DIALOG_REPLY =
|
|
|
136 |
"com.facebook.platform.action.reply.MESSAGE_DIALOG";
|
|
|
137 |
public static final String ACTION_OGACTIONPUBLISH_DIALOG_REPLY =
|
|
|
138 |
"com.facebook.platform.action.reply.OGACTIONPUBLISH_DIALOG";
|
|
|
139 |
public static final String ACTION_OGMESSAGEPUBLISH_DIALOG_REPLY =
|
|
|
140 |
"com.facebook.platform.action.reply.OGMESSAGEPUBLISH_DIALOG";
|
|
|
141 |
public static final String ACTION_LIKE_DIALOG_REPLY =
|
|
|
142 |
"com.facebook.platform.action.reply.LIKE_DIALOG";
|
|
|
143 |
|
|
|
144 |
// Extras supported for ACTION_LOGIN_DIALOG:
|
|
|
145 |
public static final String EXTRA_PERMISSIONS = "com.facebook.platform.extra.PERMISSIONS";
|
|
|
146 |
public static final String EXTRA_APPLICATION_ID = "com.facebook.platform.extra.APPLICATION_ID";
|
|
|
147 |
public static final String EXTRA_APPLICATION_NAME = "com.facebook.platform.extra.APPLICATION_NAME";
|
|
|
148 |
|
|
|
149 |
// Extras returned by setResult() for ACTION_LOGIN_DIALOG
|
|
|
150 |
public static final String EXTRA_ACCESS_TOKEN = "com.facebook.platform.extra.ACCESS_TOKEN";
|
|
|
151 |
public static final String EXTRA_EXPIRES_SECONDS_SINCE_EPOCH =
|
|
|
152 |
"com.facebook.platform.extra.EXPIRES_SECONDS_SINCE_EPOCH";
|
|
|
153 |
// EXTRA_PERMISSIONS
|
|
|
154 |
|
|
|
155 |
public static final String RESULT_ARGS_ACCESS_TOKEN = "access_token";
|
|
|
156 |
public static final String RESULT_ARGS_EXPIRES_SECONDS_SINCE_EPOCH =
|
|
|
157 |
"expires_seconds_since_epoch";
|
|
|
158 |
public static final String RESULT_ARGS_PERMISSIONS = "permissions";
|
|
|
159 |
|
|
|
160 |
// Extras supported for ACTION_FEED_DIALOG:
|
|
|
161 |
public static final String EXTRA_PLACE_TAG = "com.facebook.platform.extra.PLACE";
|
|
|
162 |
public static final String EXTRA_FRIEND_TAGS = "com.facebook.platform.extra.FRIENDS";
|
|
|
163 |
public static final String EXTRA_LINK = "com.facebook.platform.extra.LINK";
|
|
|
164 |
public static final String EXTRA_IMAGE = "com.facebook.platform.extra.IMAGE";
|
|
|
165 |
public static final String EXTRA_TITLE = "com.facebook.platform.extra.TITLE";
|
|
|
166 |
public static final String EXTRA_SUBTITLE = "com.facebook.platform.extra.SUBTITLE";
|
|
|
167 |
public static final String EXTRA_DESCRIPTION = "com.facebook.platform.extra.DESCRIPTION";
|
|
|
168 |
public static final String EXTRA_REF = "com.facebook.platform.extra.REF";
|
|
|
169 |
public static final String EXTRA_DATA_FAILURES_FATAL = "com.facebook.platform.extra.DATA_FAILURES_FATAL";
|
|
|
170 |
public static final String EXTRA_PHOTOS = "com.facebook.platform.extra.PHOTOS";
|
|
|
171 |
|
|
|
172 |
public static final String METHOD_ARGS_PLACE_TAG = "PLACE";
|
|
|
173 |
public static final String METHOD_ARGS_FRIEND_TAGS = "FRIENDS";
|
|
|
174 |
public static final String METHOD_ARGS_LINK = "LINK";
|
|
|
175 |
public static final String METHOD_ARGS_IMAGE = "IMAGE";
|
|
|
176 |
public static final String METHOD_ARGS_TITLE = "TITLE";
|
|
|
177 |
public static final String METHOD_ARGS_SUBTITLE = "SUBTITLE";
|
|
|
178 |
public static final String METHOD_ARGS_DESCRIPTION = "DESCRIPTION";
|
|
|
179 |
public static final String METHOD_ARGS_REF = "REF";
|
|
|
180 |
public static final String METHOD_ARGS_DATA_FAILURES_FATAL = "DATA_FAILURES_FATAL";
|
|
|
181 |
public static final String METHOD_ARGS_PHOTOS = "PHOTOS";
|
|
|
182 |
public static final String METHOD_ARGS_VIDEO = "VIDEO";
|
|
|
183 |
|
|
|
184 |
// Extras supported for ACTION_OGACTIONPUBLISH_DIALOG:
|
|
|
185 |
public static final String EXTRA_ACTION = "com.facebook.platform.extra.ACTION";
|
|
|
186 |
public static final String EXTRA_ACTION_TYPE = "com.facebook.platform.extra.ACTION_TYPE";
|
|
|
187 |
public static final String EXTRA_PREVIEW_PROPERTY_NAME =
|
|
|
188 |
"com.facebook.platform.extra.PREVIEW_PROPERTY_NAME";
|
|
|
189 |
|
|
|
190 |
public static final String METHOD_ARGS_ACTION = "ACTION";
|
|
|
191 |
public static final String METHOD_ARGS_ACTION_TYPE = "ACTION_TYPE";
|
|
|
192 |
public static final String METHOD_ARGS_PREVIEW_PROPERTY_NAME = "PREVIEW_PROPERTY_NAME";
|
|
|
193 |
|
|
|
194 |
// Extras supported for MESSAGE_GET_LIKE_STATUS_REQUEST:
|
|
|
195 |
public static final String EXTRA_OBJECT_ID = "com.facebook.platform.extra.OBJECT_ID";
|
|
|
196 |
|
|
|
197 |
// Extras supported in MESSAGE_GET_LIKE_STATUS_REPLY:
|
|
|
198 |
public static final String EXTRA_OBJECT_IS_LIKED = "com.facebook.platform.extra.OBJECT_IS_LIKED";
|
|
|
199 |
public static final String EXTRA_LIKE_COUNT_STRING_WITH_LIKE = "com.facebook.platform.extra.LIKE_COUNT_STRING_WITH_LIKE";
|
|
|
200 |
public static final String EXTRA_LIKE_COUNT_STRING_WITHOUT_LIKE = "com.facebook.platform.extra.LIKE_COUNT_STRING_WITHOUT_LIKE";
|
|
|
201 |
public static final String EXTRA_SOCIAL_SENTENCE_WITH_LIKE = "com.facebook.platform.extra.SOCIAL_SENTENCE_WITH_LIKE";
|
|
|
202 |
public static final String EXTRA_SOCIAL_SENTENCE_WITHOUT_LIKE = "com.facebook.platform.extra.SOCIAL_SENTENCE_WITHOUT_LIKE";
|
|
|
203 |
public static final String EXTRA_UNLIKE_TOKEN = "com.facebook.platform.extra.UNLIKE_TOKEN";
|
|
|
204 |
|
|
|
205 |
// OG objects will have this key to set to true if they should be created as part of OG Action publish
|
|
|
206 |
public static final String OPEN_GRAPH_CREATE_OBJECT_KEY = "fbsdk:create_object";
|
|
|
207 |
// Determines whether an image is user generated
|
|
|
208 |
public static final String IMAGE_USER_GENERATED_KEY = "user_generated";
|
|
|
209 |
// url key for images
|
|
|
210 |
public static final String IMAGE_URL_KEY = "url";
|
|
|
211 |
|
|
|
212 |
// Method args supported for ACTION_LIKE_DIALOG
|
|
|
213 |
public static final String METHOD_ARGS_OBJECT_ID = "object_id";
|
|
|
214 |
|
|
|
215 |
// Keys for status data in MESSAGE_ERROR_REPLY from PlatformService and for error
|
|
|
216 |
// extras returned by PlatformActivity's setResult() in case of errors:
|
|
|
217 |
public static final String STATUS_ERROR_TYPE = "com.facebook.platform.status.ERROR_TYPE";
|
|
|
218 |
public static final String STATUS_ERROR_DESCRIPTION =
|
|
|
219 |
"com.facebook.platform.status.ERROR_DESCRIPTION";
|
|
|
220 |
public static final String STATUS_ERROR_CODE = "com.facebook.platform.status.ERROR_CODE";
|
|
|
221 |
public static final String STATUS_ERROR_SUBCODE = "com.facebook.platform.status.ERROR_SUBCODE";
|
|
|
222 |
public static final String STATUS_ERROR_JSON = "com.facebook.platform.status.ERROR_JSON";
|
|
|
223 |
|
|
|
224 |
public static final String BRIDGE_ARG_ERROR_TYPE = "error_type";
|
|
|
225 |
public static final String BRIDGE_ARG_ERROR_DESCRIPTION = "error_description";
|
|
|
226 |
public static final String BRIDGE_ARG_ERROR_CODE = "error_code";
|
|
|
227 |
public static final String BRIDGE_ARG_ERROR_SUBCODE = "error_subcode";
|
|
|
228 |
public static final String BRIDGE_ARG_ERROR_JSON = "error_json";
|
|
|
229 |
|
|
|
230 |
// Expected values for ERROR_KEY_TYPE. Clients should tolerate other values:
|
|
|
231 |
public static final String ERROR_UNKNOWN_ERROR = "UnknownError";
|
|
|
232 |
public static final String ERROR_PROTOCOL_ERROR = "ProtocolError";
|
|
|
233 |
public static final String ERROR_USER_CANCELED = "UserCanceled";
|
|
|
234 |
public static final String ERROR_APPLICATION_ERROR = "ApplicationError";
|
|
|
235 |
public static final String ERROR_NETWORK_ERROR = "NetworkError";
|
|
|
236 |
public static final String ERROR_PERMISSION_DENIED = "PermissionDenied";
|
|
|
237 |
public static final String ERROR_SERVICE_DISABLED = "ServiceDisabled";
|
|
|
238 |
|
|
|
239 |
public static final String AUDIENCE_ME = "only_me";
|
|
|
240 |
public static final String AUDIENCE_FRIENDS = "friends";
|
|
|
241 |
public static final String AUDIENCE_EVERYONE = "everyone";
|
|
|
242 |
|
|
|
243 |
// Request codes for different categories of native protocol calls.
|
|
|
244 |
public static final int DIALOG_REQUEST_CODE = 0xfacf;
|
|
|
245 |
|
|
|
246 |
private static final String CONTENT_SCHEME = "content://";
|
|
|
247 |
private static final String PLATFORM_PROVIDER_VERSIONS = ".provider.PlatformProvider/versions";
|
|
|
248 |
|
|
|
249 |
// Columns returned by PlatformProvider
|
|
|
250 |
private static final String PLATFORM_PROVIDER_VERSION_COLUMN = "version";
|
|
|
251 |
|
|
|
252 |
private static abstract class NativeAppInfo {
|
|
|
253 |
abstract protected String getPackage();
|
|
|
254 |
|
|
|
255 |
private static final String FBI_HASH = "a4b7452e2ed8f5f191058ca7bbfd26b0d3214bfc";
|
|
|
256 |
private static final String FBL_HASH = "5e8f16062ea3cd2c4a0d547876baa6f38cabf625";
|
|
|
257 |
private static final String FBR_HASH = "8a3c4b262d721acd49a4bf97d5213199c86fa2b9";
|
|
|
258 |
|
|
|
259 |
private static final HashSet<String> validAppSignatureHashes = buildAppSignatureHashes();
|
|
|
260 |
|
|
|
261 |
private static HashSet<String> buildAppSignatureHashes() {
|
|
|
262 |
HashSet<String> set = new HashSet<String>();
|
|
|
263 |
set.add(FBR_HASH);
|
|
|
264 |
set.add(FBI_HASH);
|
|
|
265 |
set.add(FBL_HASH);
|
|
|
266 |
return set;
|
|
|
267 |
}
|
|
|
268 |
|
|
|
269 |
public boolean validateSignature(Context context, String packageName) {
|
|
|
270 |
String brand = Build.BRAND;
|
|
|
271 |
int applicationFlags = context.getApplicationInfo().flags;
|
|
|
272 |
if (brand.startsWith("generic") && (applicationFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
|
|
|
273 |
// We are debugging on an emulator, don't validate package signature.
|
|
|
274 |
return true;
|
|
|
275 |
}
|
|
|
276 |
|
|
|
277 |
PackageInfo packageInfo = null;
|
|
|
278 |
try {
|
|
|
279 |
packageInfo = context.getPackageManager().getPackageInfo(packageName,
|
|
|
280 |
PackageManager.GET_SIGNATURES);
|
|
|
281 |
} catch (PackageManager.NameNotFoundException e) {
|
|
|
282 |
return false;
|
|
|
283 |
}
|
|
|
284 |
|
|
|
285 |
for (Signature signature : packageInfo.signatures) {
|
|
|
286 |
String hashedSignature = Utility.sha1hash(signature.toByteArray());
|
|
|
287 |
if (validAppSignatureHashes.contains(hashedSignature)) {
|
|
|
288 |
return true;
|
|
|
289 |
}
|
|
|
290 |
}
|
|
|
291 |
|
|
|
292 |
return false;
|
|
|
293 |
}
|
|
|
294 |
}
|
|
|
295 |
|
|
|
296 |
private static class KatanaAppInfo extends NativeAppInfo {
|
|
|
297 |
static final String KATANA_PACKAGE = "com.facebook.katana";
|
|
|
298 |
|
|
|
299 |
@Override
|
|
|
300 |
protected String getPackage() {
|
|
|
301 |
return KATANA_PACKAGE;
|
|
|
302 |
}
|
|
|
303 |
}
|
|
|
304 |
|
|
|
305 |
private static class MessengerAppInfo extends NativeAppInfo {
|
|
|
306 |
static final String MESSENGER_PACKAGE = "com.facebook.orca";
|
|
|
307 |
|
|
|
308 |
@Override
|
|
|
309 |
protected String getPackage() {
|
|
|
310 |
return MESSENGER_PACKAGE;
|
|
|
311 |
}
|
|
|
312 |
}
|
|
|
313 |
|
|
|
314 |
private static class WakizashiAppInfo extends NativeAppInfo {
|
|
|
315 |
static final String WAKIZASHI_PACKAGE = "com.facebook.wakizashi";
|
|
|
316 |
|
|
|
317 |
@Override
|
|
|
318 |
protected String getPackage() {
|
|
|
319 |
return WAKIZASHI_PACKAGE;
|
|
|
320 |
}
|
|
|
321 |
}
|
|
|
322 |
|
|
|
323 |
private static final NativeAppInfo FACEBOOK_APP_INFO = new KatanaAppInfo();
|
|
|
324 |
private static List<NativeAppInfo> facebookAppInfoList = buildFacebookAppList();
|
|
|
325 |
private static Map<String, List<NativeAppInfo>> actionToAppInfoMap = buildActionToAppInfoMap();
|
|
|
326 |
|
|
|
327 |
private static List<NativeAppInfo> buildFacebookAppList() {
|
|
|
328 |
List<NativeAppInfo> list = new ArrayList<NativeAppInfo>();
|
|
|
329 |
|
|
|
330 |
// Katana needs to be the first thing in the list since it will get selected as the default FACEBOOK_APP_INFO
|
|
|
331 |
list.add(FACEBOOK_APP_INFO);
|
|
|
332 |
list.add(new WakizashiAppInfo());
|
|
|
333 |
|
|
|
334 |
return list;
|
|
|
335 |
}
|
|
|
336 |
|
|
|
337 |
private static Map<String, List<NativeAppInfo>> buildActionToAppInfoMap() {
|
|
|
338 |
Map<String, List<NativeAppInfo>> map = new HashMap<String, List<NativeAppInfo>>();
|
|
|
339 |
|
|
|
340 |
ArrayList<NativeAppInfo> messengerAppInfoList = new ArrayList<NativeAppInfo>();
|
|
|
341 |
messengerAppInfoList.add(new MessengerAppInfo());
|
|
|
342 |
|
|
|
343 |
// Add individual actions and the list they should try
|
|
|
344 |
map.put(ACTION_OGACTIONPUBLISH_DIALOG, facebookAppInfoList);
|
|
|
345 |
map.put(ACTION_FEED_DIALOG, facebookAppInfoList);
|
|
|
346 |
map.put(ACTION_LIKE_DIALOG, facebookAppInfoList);
|
|
|
347 |
map.put(ACTION_MESSAGE_DIALOG, messengerAppInfoList);
|
|
|
348 |
map.put(ACTION_OGMESSAGEPUBLISH_DIALOG, messengerAppInfoList);
|
|
|
349 |
|
|
|
350 |
return map;
|
|
|
351 |
}
|
|
|
352 |
|
|
|
353 |
static Intent validateActivityIntent(Context context, Intent intent, NativeAppInfo appInfo) {
|
|
|
354 |
if (intent == null) {
|
|
|
355 |
return null;
|
|
|
356 |
}
|
|
|
357 |
|
|
|
358 |
ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
|
|
|
359 |
if (resolveInfo == null) {
|
|
|
360 |
return null;
|
|
|
361 |
}
|
|
|
362 |
|
|
|
363 |
if (!appInfo.validateSignature(context, resolveInfo.activityInfo.packageName)) {
|
|
|
364 |
return null;
|
|
|
365 |
}
|
|
|
366 |
|
|
|
367 |
return intent;
|
|
|
368 |
}
|
|
|
369 |
|
|
|
370 |
static Intent validateServiceIntent(Context context, Intent intent, NativeAppInfo appInfo) {
|
|
|
371 |
if (intent == null) {
|
|
|
372 |
return null;
|
|
|
373 |
}
|
|
|
374 |
|
|
|
375 |
ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, 0);
|
|
|
376 |
if (resolveInfo == null) {
|
|
|
377 |
return null;
|
|
|
378 |
}
|
|
|
379 |
|
|
|
380 |
if (!appInfo.validateSignature(context, resolveInfo.serviceInfo.packageName)) {
|
|
|
381 |
return null;
|
|
|
382 |
}
|
|
|
383 |
|
|
|
384 |
return intent;
|
|
|
385 |
}
|
|
|
386 |
|
|
|
387 |
public static Intent createProxyAuthIntent(Context context, String applicationId, List<String> permissions,
|
|
|
388 |
String e2e, boolean isRerequest, SessionDefaultAudience defaultAudience) {
|
|
|
389 |
for (NativeAppInfo appInfo : facebookAppInfoList) {
|
|
|
390 |
Intent intent = new Intent()
|
|
|
391 |
.setClassName(appInfo.getPackage(), FACEBOOK_PROXY_AUTH_ACTIVITY)
|
|
|
392 |
.putExtra(FACEBOOK_PROXY_AUTH_APP_ID_KEY, applicationId);
|
|
|
393 |
|
|
|
394 |
if (!Utility.isNullOrEmpty(permissions)) {
|
|
|
395 |
intent.putExtra(FACEBOOK_PROXY_AUTH_PERMISSIONS_KEY, TextUtils.join(",", permissions));
|
|
|
396 |
}
|
|
|
397 |
if (!Utility.isNullOrEmpty(e2e)) {
|
|
|
398 |
intent.putExtra(FACEBOOK_PROXY_AUTH_E2E_KEY, e2e);
|
|
|
399 |
}
|
|
|
400 |
|
|
|
401 |
intent.putExtra(ServerProtocol.DIALOG_PARAM_RESPONSE_TYPE, ServerProtocol.DIALOG_RESPONSE_TYPE_TOKEN);
|
|
|
402 |
intent.putExtra(ServerProtocol.DIALOG_PARAM_RETURN_SCOPES, ServerProtocol.DIALOG_RETURN_SCOPES_TRUE);
|
|
|
403 |
intent.putExtra(ServerProtocol.DIALOG_PARAM_DEFAULT_AUDIENCE, defaultAudience.getNativeProtocolAudience());
|
|
|
404 |
|
|
|
405 |
if (!Settings.getPlatformCompatibilityEnabled()) {
|
|
|
406 |
// Override the API Version for Auth
|
|
|
407 |
intent.putExtra(ServerProtocol.DIALOG_PARAM_LEGACY_OVERRIDE, ServerProtocol.GRAPH_API_VERSION);
|
|
|
408 |
|
|
|
409 |
// Only set the rerequest auth type for non legacy requests
|
|
|
410 |
if (isRerequest) {
|
|
|
411 |
intent.putExtra(ServerProtocol.DIALOG_PARAM_AUTH_TYPE, ServerProtocol.DIALOG_REREQUEST_AUTH_TYPE);
|
|
|
412 |
}
|
|
|
413 |
}
|
|
|
414 |
|
|
|
415 |
intent = validateActivityIntent(context, intent, appInfo);
|
|
|
416 |
|
|
|
417 |
if (intent != null) {
|
|
|
418 |
return intent;
|
|
|
419 |
}
|
|
|
420 |
}
|
|
|
421 |
return null;
|
|
|
422 |
}
|
|
|
423 |
|
|
|
424 |
public static Intent createTokenRefreshIntent(Context context) {
|
|
|
425 |
for (NativeAppInfo appInfo : facebookAppInfoList) {
|
|
|
426 |
Intent intent = new Intent()
|
|
|
427 |
.setClassName(appInfo.getPackage(), FACEBOOK_TOKEN_REFRESH_ACTIVITY);
|
|
|
428 |
|
|
|
429 |
intent = validateServiceIntent(context, intent, appInfo);
|
|
|
430 |
|
|
|
431 |
if (intent != null) {
|
|
|
432 |
return intent;
|
|
|
433 |
}
|
|
|
434 |
}
|
|
|
435 |
return null;
|
|
|
436 |
}
|
|
|
437 |
|
|
|
438 |
public static final int getLatestKnownVersion() {
|
|
|
439 |
return KNOWN_PROTOCOL_VERSIONS.get(0);
|
|
|
440 |
}
|
|
|
441 |
|
|
|
442 |
// Note: be sure this stays sorted in descending order; add new versions at the beginning
|
|
|
443 |
private static final List<Integer> KNOWN_PROTOCOL_VERSIONS =
|
|
|
444 |
Arrays.asList(
|
|
|
445 |
PROTOCOL_VERSION_20141107,
|
|
|
446 |
PROTOCOL_VERSION_20141028,
|
|
|
447 |
PROTOCOL_VERSION_20141001,
|
|
|
448 |
PROTOCOL_VERSION_20140701,
|
|
|
449 |
PROTOCOL_VERSION_20140324,
|
|
|
450 |
PROTOCOL_VERSION_20140204,
|
|
|
451 |
PROTOCOL_VERSION_20131107,
|
|
|
452 |
PROTOCOL_VERSION_20130618,
|
|
|
453 |
PROTOCOL_VERSION_20130502,
|
|
|
454 |
PROTOCOL_VERSION_20121101
|
|
|
455 |
);
|
|
|
456 |
|
|
|
457 |
private static Intent findActivityIntent(Context context, String activityAction, String internalAction) {
|
|
|
458 |
List<NativeAppInfo> list = actionToAppInfoMap.get(internalAction);
|
|
|
459 |
if (list == null) {
|
|
|
460 |
return null;
|
|
|
461 |
}
|
|
|
462 |
|
|
|
463 |
Intent intent = null;
|
|
|
464 |
for (NativeAppInfo appInfo : list) {
|
|
|
465 |
intent = new Intent()
|
|
|
466 |
.setAction(activityAction)
|
|
|
467 |
.setPackage(appInfo.getPackage())
|
|
|
468 |
.addCategory(Intent.CATEGORY_DEFAULT);
|
|
|
469 |
intent = validateActivityIntent(context, intent, appInfo);
|
|
|
470 |
if (intent != null) {
|
|
|
471 |
return intent;
|
|
|
472 |
}
|
|
|
473 |
}
|
|
|
474 |
|
|
|
475 |
return intent;
|
|
|
476 |
}
|
|
|
477 |
|
|
|
478 |
public static boolean isVersionCompatibleWithBucketedIntent(int version) {
|
|
|
479 |
return KNOWN_PROTOCOL_VERSIONS.contains(version) && version >= PROTOCOL_VERSION_20140701;
|
|
|
480 |
}
|
|
|
481 |
|
|
|
482 |
public static Intent createPlatformActivityIntent(
|
|
|
483 |
Context context,
|
|
|
484 |
String callId,
|
|
|
485 |
String action,
|
|
|
486 |
int version,
|
|
|
487 |
String applicationName,
|
|
|
488 |
Bundle extras) {
|
|
|
489 |
Intent intent = findActivityIntent(context, INTENT_ACTION_PLATFORM_ACTIVITY, action);
|
|
|
490 |
if (intent == null) {
|
|
|
491 |
return null;
|
|
|
492 |
}
|
|
|
493 |
|
|
|
494 |
String applicationId = Utility.getMetadataApplicationId(context);
|
|
|
495 |
|
|
|
496 |
intent.putExtra(EXTRA_PROTOCOL_VERSION, version)
|
|
|
497 |
.putExtra(EXTRA_PROTOCOL_ACTION, action)
|
|
|
498 |
.putExtra(EXTRA_APPLICATION_ID, applicationId);
|
|
|
499 |
|
|
|
500 |
if (isVersionCompatibleWithBucketedIntent(version)) {
|
|
|
501 |
// This is a bucketed intent
|
|
|
502 |
Bundle bridgeArguments = new Bundle();
|
|
|
503 |
bridgeArguments.putString(BRIDGE_ARG_ACTION_ID_STRING, callId);
|
|
|
504 |
bridgeArguments.putString(BRIDGE_ARG_APP_NAME_STRING, applicationName);
|
|
|
505 |
intent.putExtra(EXTRA_PROTOCOL_BRIDGE_ARGS, bridgeArguments);
|
|
|
506 |
|
|
|
507 |
Bundle methodArguments = (extras == null) ? new Bundle() : extras;
|
|
|
508 |
intent.putExtra(EXTRA_PROTOCOL_METHOD_ARGS, methodArguments);
|
|
|
509 |
} else {
|
|
|
510 |
// This is the older flat intent
|
|
|
511 |
intent.putExtra(EXTRA_PROTOCOL_CALL_ID, callId);
|
|
|
512 |
intent.putExtra(EXTRA_APPLICATION_NAME, applicationName);
|
|
|
513 |
intent.putExtras(extras);
|
|
|
514 |
}
|
|
|
515 |
|
|
|
516 |
return intent;
|
|
|
517 |
}
|
|
|
518 |
|
|
|
519 |
public static Intent createPlatformServiceIntent(Context context) {
|
|
|
520 |
for (NativeAppInfo appInfo : facebookAppInfoList) {
|
|
|
521 |
Intent intent = new Intent(INTENT_ACTION_PLATFORM_SERVICE)
|
|
|
522 |
.setPackage(appInfo.getPackage())
|
|
|
523 |
.addCategory(Intent.CATEGORY_DEFAULT);
|
|
|
524 |
intent = validateServiceIntent(context, intent, appInfo);
|
|
|
525 |
if (intent != null) {
|
|
|
526 |
return intent;
|
|
|
527 |
}
|
|
|
528 |
}
|
|
|
529 |
return null;
|
|
|
530 |
}
|
|
|
531 |
|
|
|
532 |
public static int getProtocolVersionFromIntent(Intent intent) {
|
|
|
533 |
return intent.getIntExtra(EXTRA_PROTOCOL_VERSION, 0);
|
|
|
534 |
}
|
|
|
535 |
|
|
|
536 |
public static UUID getCallIdFromIntent(Intent intent) {
|
|
|
537 |
if (intent == null) {
|
|
|
538 |
return null;
|
|
|
539 |
}
|
|
|
540 |
int version = getProtocolVersionFromIntent(intent);
|
|
|
541 |
String callIdString = null;
|
|
|
542 |
if (isVersionCompatibleWithBucketedIntent(version)) {
|
|
|
543 |
Bundle bridgeArgs = intent.getBundleExtra(EXTRA_PROTOCOL_BRIDGE_ARGS);
|
|
|
544 |
if (bridgeArgs != null) {
|
|
|
545 |
callIdString = bridgeArgs.getString(BRIDGE_ARG_ACTION_ID_STRING);
|
|
|
546 |
}
|
|
|
547 |
} else {
|
|
|
548 |
callIdString = intent.getStringExtra(EXTRA_PROTOCOL_CALL_ID);
|
|
|
549 |
}
|
|
|
550 |
|
|
|
551 |
UUID callId = null;
|
|
|
552 |
if (callIdString != null) {
|
|
|
553 |
try {
|
|
|
554 |
callId = UUID.fromString(callIdString);
|
|
|
555 |
} catch (IllegalArgumentException exception) {
|
|
|
556 |
}
|
|
|
557 |
}
|
|
|
558 |
return callId;
|
|
|
559 |
}
|
|
|
560 |
|
|
|
561 |
public static Bundle getBridgeArgumentsFromIntent(Intent intent) {
|
|
|
562 |
int version = getProtocolVersionFromIntent(intent);
|
|
|
563 |
if (!isVersionCompatibleWithBucketedIntent(version)) {
|
|
|
564 |
return null;
|
|
|
565 |
}
|
|
|
566 |
|
|
|
567 |
return intent.getBundleExtra(EXTRA_PROTOCOL_BRIDGE_ARGS);
|
|
|
568 |
}
|
|
|
569 |
|
|
|
570 |
public static Bundle getSuccessResultsFromIntent(Intent resultIntent) {
|
|
|
571 |
int version = getProtocolVersionFromIntent(resultIntent);
|
|
|
572 |
Bundle extras = resultIntent.getExtras();
|
|
|
573 |
if (!isVersionCompatibleWithBucketedIntent(version) || extras == null) {
|
|
|
574 |
return extras;
|
|
|
575 |
}
|
|
|
576 |
|
|
|
577 |
return extras.getBundle(EXTRA_PROTOCOL_METHOD_RESULTS);
|
|
|
578 |
}
|
|
|
579 |
|
|
|
580 |
public static boolean isErrorResult(Intent resultIntent) {
|
|
|
581 |
Bundle bridgeArgs = getBridgeArgumentsFromIntent(resultIntent);
|
|
|
582 |
if (bridgeArgs != null) {
|
|
|
583 |
return bridgeArgs.containsKey(BRIDGE_ARG_ERROR_BUNDLE);
|
|
|
584 |
} else {
|
|
|
585 |
return resultIntent.hasExtra(STATUS_ERROR_TYPE);
|
|
|
586 |
}
|
|
|
587 |
}
|
|
|
588 |
|
|
|
589 |
public static Bundle getErrorDataFromResultIntent(Intent resultIntent) {
|
|
|
590 |
if (!isErrorResult(resultIntent)) {
|
|
|
591 |
return null;
|
|
|
592 |
}
|
|
|
593 |
|
|
|
594 |
Bundle bridgeArgs = getBridgeArgumentsFromIntent(resultIntent);
|
|
|
595 |
if (bridgeArgs != null) {
|
|
|
596 |
return bridgeArgs.getBundle(BRIDGE_ARG_ERROR_BUNDLE);
|
|
|
597 |
}
|
|
|
598 |
|
|
|
599 |
return resultIntent.getExtras();
|
|
|
600 |
}
|
|
|
601 |
|
|
|
602 |
public static Exception getExceptionFromErrorData(Bundle errorData) {
|
|
|
603 |
if (errorData == null) {
|
|
|
604 |
return null;
|
|
|
605 |
}
|
|
|
606 |
|
|
|
607 |
String type = errorData.getString(BRIDGE_ARG_ERROR_TYPE);
|
|
|
608 |
if (type == null) {
|
|
|
609 |
type = errorData.getString(STATUS_ERROR_TYPE);
|
|
|
610 |
}
|
|
|
611 |
|
|
|
612 |
String description = errorData.getString(BRIDGE_ARG_ERROR_DESCRIPTION);
|
|
|
613 |
if (description == null) {
|
|
|
614 |
description = errorData.getString(STATUS_ERROR_DESCRIPTION);
|
|
|
615 |
}
|
|
|
616 |
|
|
|
617 |
if (type != null && type.equalsIgnoreCase(ERROR_USER_CANCELED)) {
|
|
|
618 |
return new FacebookOperationCanceledException(description);
|
|
|
619 |
}
|
|
|
620 |
|
|
|
621 |
/* TODO parse error values and create appropriate exception class */
|
|
|
622 |
return new FacebookException(description);
|
|
|
623 |
}
|
|
|
624 |
|
|
|
625 |
public static int getLatestAvailableProtocolVersionForService(Context context, final int minimumVersion) {
|
|
|
626 |
// Services are currently always against the Facebook App
|
|
|
627 |
return getLatestAvailableProtocolVersionForAppInfoList(context, facebookAppInfoList, new int[] {minimumVersion});
|
|
|
628 |
}
|
|
|
629 |
|
|
|
630 |
public static int getLatestAvailableProtocolVersionForAction(Context context, String action, int[] versionSpec) {
|
|
|
631 |
List<NativeAppInfo> appInfoList = actionToAppInfoMap.get(action);
|
|
|
632 |
return getLatestAvailableProtocolVersionForAppInfoList(context, appInfoList, versionSpec);
|
|
|
633 |
}
|
|
|
634 |
|
|
|
635 |
private static int getLatestAvailableProtocolVersionForAppInfoList(Context context, List<NativeAppInfo> appInfoList,
|
|
|
636 |
int[] versionSpec) {
|
|
|
637 |
if (appInfoList == null) {
|
|
|
638 |
return NO_PROTOCOL_AVAILABLE;
|
|
|
639 |
}
|
|
|
640 |
|
|
|
641 |
// Could potentially cache the NativeAppInfo to latestProtocolVersion
|
|
|
642 |
for (NativeAppInfo appInfo : appInfoList) {
|
|
|
643 |
int protocolVersion = getLatestAvailableProtocolVersionForAppInfo(context, appInfo, versionSpec);
|
|
|
644 |
if (protocolVersion != NO_PROTOCOL_AVAILABLE) {
|
|
|
645 |
return protocolVersion;
|
|
|
646 |
}
|
|
|
647 |
}
|
|
|
648 |
|
|
|
649 |
return NO_PROTOCOL_AVAILABLE;
|
|
|
650 |
}
|
|
|
651 |
|
|
|
652 |
private static int getLatestAvailableProtocolVersionForAppInfo(
|
|
|
653 |
Context context,
|
|
|
654 |
NativeAppInfo appInfo,
|
|
|
655 |
int[] versionSpec) {
|
|
|
656 |
TreeSet<Integer> fbAppVersions = getAllAvailableProtocolVersionsForAppInfo(context, appInfo);
|
|
|
657 |
return computeLatestAvailableVersionFromVersionSpec(fbAppVersions, getLatestKnownVersion(), versionSpec);
|
|
|
658 |
}
|
|
|
659 |
|
|
|
660 |
private static TreeSet<Integer> getAllAvailableProtocolVersionsForAppInfo(
|
|
|
661 |
Context context,
|
|
|
662 |
NativeAppInfo appInfo) {
|
|
|
663 |
TreeSet<Integer> allAvailableVersions = new TreeSet<Integer>();
|
|
|
664 |
|
|
|
665 |
ContentResolver contentResolver = context.getContentResolver();
|
|
|
666 |
|
|
|
667 |
String [] projection = new String[]{ PLATFORM_PROVIDER_VERSION_COLUMN };
|
|
|
668 |
Uri uri = buildPlatformProviderVersionURI(appInfo);
|
|
|
669 |
Cursor c = null;
|
|
|
670 |
try {
|
|
|
671 |
c = contentResolver.query(uri, projection, null, null, null);
|
|
|
672 |
if (c != null) {
|
|
|
673 |
while (c.moveToNext()) {
|
|
|
674 |
int version = c.getInt(c.getColumnIndex(PLATFORM_PROVIDER_VERSION_COLUMN));
|
|
|
675 |
allAvailableVersions.add(version);
|
|
|
676 |
}
|
|
|
677 |
}
|
|
|
678 |
} finally {
|
|
|
679 |
if (c != null) {
|
|
|
680 |
c.close();
|
|
|
681 |
}
|
|
|
682 |
}
|
|
|
683 |
|
|
|
684 |
return allAvailableVersions;
|
|
|
685 |
}
|
|
|
686 |
|
|
|
687 |
/**
|
|
|
688 |
* This is public to allow for testing. Developers are discouraged from using this method, since it may change without
|
|
|
689 |
* notice.
|
|
|
690 |
*/
|
|
|
691 |
public static int computeLatestAvailableVersionFromVersionSpec(
|
|
|
692 |
TreeSet<Integer> allAvailableFacebookAppVersions,
|
|
|
693 |
int latestSdkVersion,
|
|
|
694 |
int[] versionSpec) {
|
|
|
695 |
// Remember that these ranges are sorted in ascending order and can be unbounded. So we are starting
|
|
|
696 |
// from the end of the version-spec array and working backwards, to try get the newest possible version
|
|
|
697 |
int versionSpecIndex = versionSpec.length - 1;
|
|
|
698 |
Iterator<Integer> fbAppVersionsIterator = allAvailableFacebookAppVersions.descendingIterator();
|
|
|
699 |
int latestFacebookAppVersion = -1;
|
|
|
700 |
|
|
|
701 |
while (fbAppVersionsIterator.hasNext()) {
|
|
|
702 |
int fbAppVersion = fbAppVersionsIterator.next();
|
|
|
703 |
|
|
|
704 |
// We're holding on to the greatest fb-app version available.
|
|
|
705 |
latestFacebookAppVersion = Math.max(latestFacebookAppVersion, fbAppVersion);
|
|
|
706 |
|
|
|
707 |
// If there is a newer version in the versionSpec, throw it away, we don't have it
|
|
|
708 |
while (versionSpecIndex >= 0 && versionSpec[versionSpecIndex] > fbAppVersion) {
|
|
|
709 |
versionSpecIndex--;
|
|
|
710 |
}
|
|
|
711 |
|
|
|
712 |
if (versionSpecIndex < 0) {
|
|
|
713 |
// There was no fb app version that fell into any range in the versionSpec - or - the
|
|
|
714 |
// versionSpec was empty, which means that this action is not supported.
|
|
|
715 |
return NO_PROTOCOL_AVAILABLE;
|
|
|
716 |
}
|
|
|
717 |
|
|
|
718 |
// If we are here, we know we are within a range specified in the versionSpec. We should see if it is
|
|
|
719 |
// a disabled or enabled range.
|
|
|
720 |
|
|
|
721 |
if (versionSpec[versionSpecIndex] == fbAppVersion) {
|
|
|
722 |
// if the versionSpecIndex is even, it is enabled; if odd, disabled
|
|
|
723 |
return (
|
|
|
724 |
versionSpecIndex % 2 == 0 ?
|
|
|
725 |
Math.min(latestFacebookAppVersion, latestSdkVersion) :
|
|
|
726 |
NO_PROTOCOL_AVAILABLE
|
|
|
727 |
);
|
|
|
728 |
}
|
|
|
729 |
}
|
|
|
730 |
|
|
|
731 |
return NO_PROTOCOL_AVAILABLE;
|
|
|
732 |
}
|
|
|
733 |
|
|
|
734 |
private static Uri buildPlatformProviderVersionURI(NativeAppInfo appInfo) {
|
|
|
735 |
return Uri.parse(CONTENT_SCHEME + appInfo.getPackage() + PLATFORM_PROVIDER_VERSIONS);
|
|
|
736 |
}
|
|
|
737 |
}
|