/* * Copyright (C) 2015 Twitter, Inc. * * 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.digits.sdk.android; import android.app.Activity; import android.content.Context; import android.content.Intent; import com.twitter.sdk.android.core.Callback; import com.twitter.sdk.android.core.Result; import com.twitter.sdk.android.core.TwitterException; import retrofit.client.Response; public class ContactsClient { private final ContactsPreferenceManager prefManager; private ActivityClassManagerFactory activityClassManagerFactory; private final DigitsApiClientManager apiClientManager; private final Digits digits; private SandboxConfig sandboxConfig; private final DigitsEventCollector digitsEventCollector; ContactsClient(DigitsApiClientManager apiManager) { this(Digits.getInstance(), apiManager, new ContactsPreferenceManager(), new ActivityClassManagerFactory(), Digits.getInstance().getSandboxConfig(), Digits.getInstance().getDigitsEventCollector()); } ContactsClient(Digits digits, DigitsApiClientManager apiManager, ContactsPreferenceManager prefManager, ActivityClassManagerFactory activityClassManagerFactory, SandboxConfig sandboxConfig, DigitsEventCollector digitsEventCollector) { this.digits = digits; this.apiClientManager = apiManager; this.prefManager = prefManager; this.activityClassManagerFactory = activityClassManagerFactory; this.sandboxConfig = sandboxConfig; this.digitsEventCollector = digitsEventCollector; } /** * First checks if user previously gave permission to upload contacts. If not, shows * dialog requesting permission to upload users contacts. If permission granted start * background service to upload contacts. Otherwise, do nothing. */ public void startContactsUpload() { startContactsUpload(R.style.Digits_default); } /** * Like {@link #startContactsUpload}, but enables theming. * * @param themeResId Resource id of theme */ public void startContactsUpload(int themeResId) { startContactsUpload(themeResId, null); } /** * Like {@link #startContactsUpload(int themeResId)}, but defines request code passed to * {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}. * * @param themeResId Resource id of theme * @param requestCode Request code */ public void startContactsUpload(int themeResId, Integer requestCode) { digitsEventCollector.startContactsUpload(new ContactsUploadStartDetails()); if (sandboxConfig.isMode(SandboxConfig.Mode.DEFAULT)) { sandboxedContactUpload(themeResId); } else if (hasUserGrantedPermission()) { startContactsService(digits.getContext()); } else { startContactsActivity(digits.getContext(), themeResId, requestCode); } } /** * Returns true if user has previously granted contacts upload permission. Otherwise, returns * false. */ public boolean hasUserGrantedPermission() { return prefManager.hasContactImportPermissionGranted(); } protected void sandboxedContactUpload(int themeResId){ final Intent intent = new Intent(ContactsUploadService.UPLOAD_COMPLETE); intent.putExtra(ContactsUploadService.UPLOAD_COMPLETE_EXTRA, new ContactsUploadResult(2, 2)); intent.putExtra(ThemeUtils.THEME_RESOURCE_ID, themeResId); digits.getContext().sendBroadcast(intent); } protected void startContactsActivity(Context context, int themeResId, Integer requestCode) { final ActivityClassManager activityClassManager = activityClassManagerFactory.createActivityClassManager(context, themeResId); final Activity activity = digits.getFabric().getCurrentActivity(); final boolean isActivityDefined = activity != null && !activity.isFinishing(); final Intent intent = new Intent(context, activityClassManager.getContactsActivity()); intent.putExtra(ThemeUtils.THEME_RESOURCE_ID, themeResId); if (isActivityDefined) { if (requestCode == null) { activity.startActivity(intent); } else { activity.startActivityForResult(intent, requestCode); } } else { context.startActivity(intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)); } } protected void startContactsService(Context context) { context.startService(new Intent(context, ContactsUploadService.class)); } protected ApiInterface getDigitsApiService() { return apiClientManager.getService(); } /** * Deletes all uploaded contacts. * * @param callback to be executed on UI thread with HTTP response. */ public void deleteAllUploadedContacts(final ContactsCallback<Response> callback) { digitsEventCollector.startDeleteContacts(new ContactsDeletionStartDetails()); //We pass an empty String into the body to work around the an error in Okhttp 2.3+ //See: https://github.com/square/retrofit/issues/854 getDigitsApiService().deleteAll("", new DeleteContactsCallbackWrapper(callback, digitsEventCollector)); } /** * Retrieve all matched contacts. Handles paging, and makes callback * when all matches are retrieved * * @param callback to be executed on UI thread with matched users. */ public void lookupContactMatchesStart(final Callback<Contacts> callback) { lookupContactMatches(null, 100, callback); } /** * Lookup matched contacts. * * @param nextCursor reference to next set of results. If null returns the first 100 users. * @param count number of results to return. Min value is 1. Max value is 100. Default * value is 50. Values out of range will return default. * @param callback to be executed on UI thread with matched users. */ public void lookupContactMatches(final String nextCursor, final Integer count, final Callback<Contacts> callback) { digitsEventCollector.startFindMatches(new ContactsLookupStartDetails(nextCursor)); final FoundContactsCallbackWrapper wrappedCallback = new FoundContactsCallbackWrapper(callback, digitsEventCollector); if (sandboxConfig.isMode(SandboxConfig.Mode.DEFAULT)) { MockApiInterface.createAllContacts(wrappedCallback); } else if (count == null || count < 1 || count > 100) { getDigitsApiService().usersAndUploadedBy(nextCursor, null, wrappedCallback); } else { getDigitsApiService().usersAndUploadedBy(nextCursor, count, wrappedCallback); } } UploadResponse uploadContacts(Vcards vcards) { return getDigitsApiService().upload(vcards); } class FoundContactsCallbackWrapper extends Callback<Contacts> { final Callback<Contacts> callback; final DigitsEventCollector digitsEventCollector; public FoundContactsCallbackWrapper(Callback<Contacts> callback, DigitsEventCollector digitsEventCollector) { this.callback = callback; this.digitsEventCollector = digitsEventCollector; } @Override public void success(Result<Contacts> result) { if (result.data != null && result.data.users != null) { digitsEventCollector.succeedFindMatches( new ContactsLookupSuccessDetails(result.data.users.size())); } if (callback != null) { callback.success(result); } } @Override public void failure(TwitterException exception) { digitsEventCollector.failedFindMatches(new ContactsLookupFailureDetails()); if (callback != null) { callback.failure(exception); } } } class DeleteContactsCallbackWrapper extends ContactsCallback<Response> { final ContactsCallback<Response> callback; final DigitsEventCollector digitsEventCollector; public DeleteContactsCallbackWrapper(ContactsCallback<Response> callback, DigitsEventCollector digitsEventCollector) { this.callback = callback; this.digitsEventCollector = digitsEventCollector; } @Override public void success(Result<Response> result) { digitsEventCollector.succeedDeleteContacts(new ContactsDeletionSuccessDetails()); if (callback != null) { callback.success(result); } } @Override public void failure(TwitterException exception) { digitsEventCollector.failedDeleteContacts(new ContactsDeletionFailureDetails()); if (callback != null) { callback.failure(exception); } } } }