| /* |
| * Copyright (C) 2014 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.example.android.wearable.agendadata; |
| |
| import static com.example.android.wearable.agendadata.Constants.TAG; |
| |
| import android.Manifest; |
| import android.content.Intent; |
| import android.content.IntentSender; |
| import android.content.pm.PackageManager; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.support.annotation.NonNull; |
| import android.support.design.widget.Snackbar; |
| import android.support.v4.app.ActivityCompat; |
| import android.support.v7.app.AppCompatActivity; |
| import android.util.Log; |
| import android.view.View; |
| import android.widget.ScrollView; |
| import android.widget.TextView; |
| |
| import com.google.android.gms.common.ConnectionResult; |
| import com.google.android.gms.common.api.GoogleApiClient; |
| import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; |
| import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; |
| import com.google.android.gms.common.api.ResultCallback; |
| import com.google.android.gms.wearable.DataApi; |
| import com.google.android.gms.wearable.DataItem; |
| import com.google.android.gms.wearable.DataItemBuffer; |
| import com.google.android.gms.wearable.Wearable; |
| |
| /** |
| * Syncs or deletes calendar events (event time, description, and background image) to your |
| * Wearable via the Wearable DataApi at the click of a button. Includes code to handle dynamic M+ |
| * permissions as well. |
| */ |
| public class MainActivity extends AppCompatActivity implements |
| ConnectionCallbacks, |
| OnConnectionFailedListener, |
| ActivityCompat.OnRequestPermissionsResultCallback { |
| |
| /* Request code for launching the Intent to resolve Google Play services errors. */ |
| private static final int REQUEST_RESOLVE_ERROR = 1000; |
| |
| /* Id to identify calendar and contact permissions request. */ |
| private static final int REQUEST_CALENDAR_AND_CONTACTS = 0; |
| |
| |
| private GoogleApiClient mGoogleApiClient; |
| private boolean mResolvingError = false; |
| |
| private View mLayout; |
| |
| private TextView mLogTextView; |
| private ScrollView mScroller; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| setContentView(R.layout.main); |
| mLayout = findViewById(R.id.main_layout); |
| |
| mLogTextView = (TextView) findViewById(R.id.log); |
| mScroller = (ScrollView) findViewById(R.id.scroller); |
| |
| mGoogleApiClient = new GoogleApiClient.Builder(this) |
| .addApi(Wearable.API) |
| .addConnectionCallbacks(this) |
| .addOnConnectionFailedListener(this) |
| .build(); |
| } |
| |
| @Override |
| protected void onStart() { |
| super.onStart(); |
| if (!mResolvingError) { |
| mGoogleApiClient.connect(); |
| } |
| } |
| |
| @Override |
| protected void onStop() { |
| if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { |
| mGoogleApiClient.disconnect(); |
| } |
| |
| super.onStop(); |
| } |
| |
| public void onGetEventsClicked(View view) { |
| |
| Log.i(TAG, "onGetEventsClicked(): Checking permission."); |
| |
| // BEGIN_INCLUDE(calendar_and_contact_permissions) |
| // Check if the Calendar permission is already available. |
| boolean calendarApproved = |
| ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) |
| == PackageManager.PERMISSION_GRANTED; |
| |
| boolean contactsApproved = |
| ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) |
| == PackageManager.PERMISSION_GRANTED; |
| |
| if (!calendarApproved || !contactsApproved) { |
| // Calendar and/or Contact permissions have not been granted. |
| requestCalendarAndContactPermissions(); |
| |
| } else { |
| // Calendar permissions is already available, start service |
| Log.i(TAG, "Permissions already granted. Starting service."); |
| pushCalendarToWear(); |
| } |
| // END_INCLUDE(calendar_and_contact_permissions) |
| |
| } |
| |
| /* |
| * Requests Calendar and Contact permissions. |
| * If the permission has been denied previously, a SnackBar will prompt the user to grant the |
| * permission, otherwise it is requested directly. |
| */ |
| private void requestCalendarAndContactPermissions() { |
| Log.i(TAG, "CALENDAR permission has NOT been granted. Requesting permission."); |
| |
| // BEGIN_INCLUDE(calendar_and_contact_permissions_request) |
| |
| boolean showCalendarPermissionRationale = |
| ActivityCompat.shouldShowRequestPermissionRationale(this, |
| Manifest.permission.READ_CALENDAR); |
| boolean showContactsPermissionRationale = |
| ActivityCompat.shouldShowRequestPermissionRationale(this, |
| Manifest.permission.READ_CONTACTS); |
| |
| if (showCalendarPermissionRationale || showContactsPermissionRationale) { |
| /* |
| * Provide an additional rationale to the user if the permission was not granted and |
| * the user would benefit from additional context for the use of the permission. For |
| * example, if the user has previously denied the permission. |
| */ |
| Log.i(TAG, "Display calendar & contact permissions rationale for additional context."); |
| |
| Snackbar.make(mLayout, R.string.permissions_rationale, |
| Snackbar.LENGTH_INDEFINITE) |
| .setAction(R.string.ok, new View.OnClickListener() { |
| @Override |
| public void onClick(View view) { |
| ActivityCompat.requestPermissions(MainActivity.this, |
| new String[] { |
| Manifest.permission.READ_CALENDAR, |
| Manifest.permission.READ_CONTACTS}, |
| REQUEST_CALENDAR_AND_CONTACTS); |
| } |
| }) |
| .show(); |
| |
| |
| } else { |
| |
| // Calendar/Contact permissions have not been granted yet. Request it directly. |
| ActivityCompat.requestPermissions( |
| this, |
| new String[]{ |
| Manifest.permission.READ_CALENDAR, |
| Manifest.permission.READ_CONTACTS |
| }, |
| REQUEST_CALENDAR_AND_CONTACTS); |
| } |
| // END_INCLUDE(calendar_and_contact_permissions_request) |
| } |
| |
| private void pushCalendarToWear() { |
| startService(new Intent(this, CalendarQueryService.class)); |
| } |
| |
| public void onDeleteEventsClicked(View view) { |
| if (mGoogleApiClient.isConnected()) { |
| Wearable.DataApi.getDataItems(mGoogleApiClient) |
| .setResultCallback(new ResultCallback<DataItemBuffer>() { |
| @Override |
| public void onResult(DataItemBuffer result) { |
| try { |
| if (result.getStatus().isSuccess()) { |
| deleteDataItems(result); |
| } else { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "onDeleteEventsClicked(): failed to get Data " |
| + "Items"); |
| } |
| } |
| } finally { |
| result.release(); |
| } |
| } |
| }); |
| } else { |
| Log.e(TAG, "Failed to delete data items" |
| + " - Client disconnected from Google Play Services"); |
| } |
| } |
| |
| private void deleteDataItems(final DataItemBuffer dataItemList) { |
| if (mGoogleApiClient.isConnected()) { |
| for (final DataItem dataItem : dataItemList) { |
| final Uri dataItemUri = dataItem.getUri(); |
| /* |
| * In a real calendar application, this might delete the corresponding calendar |
| * events from the calendar data provider. However, we simply delete the DataItem, |
| * but leave the phone's calendar data intact for this simple sample. |
| */ |
| Wearable.DataApi.deleteDataItems(mGoogleApiClient, dataItemUri) |
| .setResultCallback(new ResultCallback<DataApi.DeleteDataItemsResult>() { |
| @Override |
| public void onResult(DataApi.DeleteDataItemsResult deleteResult) { |
| if (deleteResult.getStatus().isSuccess()) { |
| appendLog("Successfully deleted data item: " + dataItemUri); |
| } else { |
| appendLog("Failed to delete data item:" + dataItemUri); |
| } |
| } |
| }); |
| } |
| } else { |
| Log.e(TAG, "Failed to delete data items" |
| + " - Client disconnected from Google Play Services"); |
| } |
| } |
| |
| @Override |
| public void onConnected(Bundle connectionHint) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Connected to Google Api Service."); |
| } |
| mResolvingError = false; |
| } |
| |
| @Override |
| public void onConnectionSuspended(int cause) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "onConnectionSuspended(): Cause id: " + cause); |
| } |
| } |
| |
| @Override |
| public void onConnectionFailed(ConnectionResult result) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Disconnected from Google Api Service"); |
| } |
| |
| if (mResolvingError) { |
| // Already attempting to resolve an error. |
| return; |
| } else if (result.hasResolution()) { |
| try { |
| mResolvingError = true; |
| result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR); |
| } catch (IntentSender.SendIntentException e) { |
| // There was an error with the resolution intent. Try again. |
| mResolvingError = false; |
| mGoogleApiClient.connect(); |
| } |
| } else { |
| mResolvingError = false; |
| } |
| } |
| |
| @Override |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| super.onActivityResult(requestCode, resultCode, data); |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "onActivityResult request/result codes: " + requestCode + "/" + resultCode); |
| } |
| |
| if (requestCode == REQUEST_RESOLVE_ERROR) { |
| mResolvingError = false; |
| if (resultCode == RESULT_OK) { |
| // Make sure the app is not already connected or attempting to connect |
| if (!mGoogleApiClient.isConnecting() && !mGoogleApiClient.isConnected()) { |
| mGoogleApiClient.connect(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Callback received when a permissions request has been completed. |
| */ |
| @Override |
| public void onRequestPermissionsResult( |
| int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { |
| |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "onRequestPermissionsResult(): " + permissions); |
| } |
| |
| if (requestCode == REQUEST_CALENDAR_AND_CONTACTS) { |
| // BEGIN_INCLUDE(permissions_result) |
| // Received permission result for calendar permission. |
| Log.i(TAG, "Received response for Calendar permission request."); |
| |
| // Check if all required permissions have been granted. |
| if ((grantResults.length == 2) |
| && (grantResults[0] == PackageManager.PERMISSION_GRANTED) |
| && (grantResults[1] == PackageManager.PERMISSION_GRANTED)) { |
| // Calendar/Contact permissions have been granted, pull all calendar events |
| Log.i(TAG, "All permission has now been granted. Showing preview."); |
| Snackbar.make(mLayout, R.string.permisions_granted, Snackbar.LENGTH_SHORT).show(); |
| |
| pushCalendarToWear(); |
| |
| } else { |
| Log.i(TAG, "CALENDAR and/or CONTACT permissions were NOT granted."); |
| Snackbar.make(mLayout, R.string.permissions_denied, Snackbar.LENGTH_SHORT).show(); |
| } |
| // END_INCLUDE(permissions_result) |
| |
| } else { |
| super.onRequestPermissionsResult(requestCode, permissions, grantResults); |
| } |
| } |
| |
| private void appendLog(final String s) { |
| mLogTextView.post(new Runnable() { |
| @Override |
| public void run() { |
| mLogTextView.append(s); |
| mLogTextView.append("\n"); |
| mScroller.fullScroll(View.FOCUS_DOWN); |
| } |
| }); |
| } |
| } |