Skip to content

Commit 68ed48f

Browse files
committed
Merge remote-tracking branch 'samples/master'
2 parents b981622 + 2577053 commit 68ed48f

File tree

97 files changed

+4075
-479
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+4075
-479
lines changed

.DS_Store

0 Bytes
Binary file not shown.

conflict/.gitignore

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
# Android Studio excludes
2+
.idea/
13
*.iml
2-
.gradle
3-
/local.properties
4-
/.idea
5-
.DS_Store
6-
/build
4+
5+
# Gradle build excludes
6+
.gradle/
7+
build/
8+
local.properties
9+
10+
# Misc
11+
.DS_Store

conflict/README.md

+32-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,33 @@
1-
android-conflict
2-
================
1+
# Google Drive Android API Conflict Sample
32

4-
Demonstration of how to handle conflicts from the Android Drive API.
3+
This application demonstrates how to resolve remote [conflicts](https://developers.google.com/drive/android/completion#conflict) using
4+
the [Google Android Drive API](https://developers.google.com/drive/android/intro). Keep in mind the default behavior is to
5+
overwrite the server content with the local content when a conflict arises. Please read the
6+
[conflict strategy documentation](https://developers.google.com/android/reference/com/google/android/gms/drive/ExecutionOptions.Builder#setConflictStrategy(int)) when
7+
choosing to override this capability. This application uses the [CONFLICT_STRATEGY_KEEP_REMOTE](https://developers.google.com/android/reference/com/google/android/gms/drive/ExecutionOptions#CONFLICT_STRATEGY_KEEP_REMOTE)
8+
option to allow the remote app (not the server) to manage the conflict.
9+
10+
## Set Up
11+
1. Install the [Android SDK](https://developer.android.com/sdk/index.html).
12+
1. Download and configure the
13+
[Google Play services SDK](https://developer.android.com/google/play-services/setup.html),
14+
which includes the Google Drive Android API.
15+
1. Create [Google API Console](https://console.developers.google.com/projectselector/apis/dashboard)
16+
project and/or enable the Drive API for an existing project.
17+
1. Register an OAuth 2.0 client for the package 'com.google.android.gms.drive.sample.conflict'
18+
with your own [debug keys](https://developers.google.com/drive/android/auth).
19+
See full instructions in the [Getting Started guide](https://developers.google.com/drive/android/get-started).
20+
1. Build and install the app on 2 devices or emulators. If using Android Studio, install the app
21+
individually on each emulator then use the AVD Manager to run both emulators simultaneously. Be
22+
sure to select Android images that have the Play Store enabled.
23+
24+
## Run the Demo
25+
Launch the application on both devices. Both apps should like this with no items listed.
26+
![Home Screen](images/conflict_home.png)
27+
28+
Add an item to the first device's list and hit 'Update List'.
29+
![Item Screen](images/conflict_first_item.png)
30+
31+
The second device should then show the item. Now add items on the second device's list.
32+
After updating the list, both devices should show the merge lists.
33+
![Resolved Screen](images/conflict_resolved.png)

conflict/app/build.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ android {
1717
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
1818
}
1919
}
20+
compileOptions {
21+
sourceCompatibility JavaVersion.VERSION_1_8
22+
targetCompatibility JavaVersion.VERSION_1_8
23+
}
2024
}
2125

2226
dependencies {

conflict/app/src/main/AndroidManifest.xml

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717

1818
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1919
package="com.google.android.gms.drive.sample.conflict" >
20-
2120
<!-- [START add_service] -->
2221
<application
2322
android:allowBackup="true"

conflict/app/src/main/java/com/google/android/gms/drive/sample/conflict/BaseDemoActivity.java

+12-14
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
/*
22
* Copyright 2014 Google Inc. All Rights Reserved.
33
*
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
55
* in compliance with the License. You may obtain a copy of the License at
66
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
88
*
9-
* Unless required by applicable law or agreed to in writing, software distributed under the
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
1010
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
1111
* express or implied. See the License for the specific language governing permissions and
1212
* limitations under the License.
1313
*/
14-
1514
package com.google.android.gms.drive.sample.conflict;
1615

1716
import android.app.Activity;
@@ -26,7 +25,6 @@
2625
import com.google.android.gms.drive.Drive;
2726
import com.google.android.gms.drive.DriveClient;
2827
import com.google.android.gms.drive.DriveResourceClient;
29-
import com.google.android.gms.tasks.Task;
3028

3129
/**
3230
* An abstract activity that handles authorization and connection to the Drive
@@ -38,15 +36,15 @@ public abstract class BaseDemoActivity extends Activity {
3836
/**
3937
* Request code for auto Google Play Services error resolution.
4038
*/
41-
protected static final int REQUEST_CODE_SIGN_IN = 0;
39+
private static final int REQUEST_CODE_SIGN_IN = 0;
4240

4341
/**
44-
* Handles high-level drive functions like sync
42+
* Handles high-level drive functions like sync.
4543
*/
4644
private DriveClient mDriveClient;
4745

4846
/**
49-
* Handle access to Drive resources/files.
47+
* Handles access to Drive resources/files.
5048
*/
5149
private DriveResourceClient mDriveResourceClient;
5250

@@ -65,21 +63,21 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
6563
if (requestCode == REQUEST_CODE_SIGN_IN) {
6664
if (resultCode != RESULT_OK) {
6765
// Sign-in may fail or be cancelled by the user. For this sample, sign-in is
68-
// required and is fatal. For apps where sign-in is optional, handle appropriately
66+
// required and is fatal. For apps where sign-in is optional, handle appropriately.
6967
Log.e(TAG, "Sign-in failed.");
7068
finish();
7169
return;
7270
}
7371

74-
// We can use last signed in account here because we know the account has Drive scopes
72+
// We can use last signed in account here because we know the account has Drive scopes.
7573
initializeDriveClient(GoogleSignIn.getLastSignedInAccount(this));
7674
}
7775
}
7876

7977
/**
8078
* Starts the sign-in process and initializes the Drive client.
8179
*/
82-
protected void signIn() {
80+
private void signIn() {
8381
GoogleSignInOptions signInOptions =
8482
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
8583
.requestScopes(Drive.SCOPE_FILE)
@@ -102,7 +100,7 @@ private void initializeDriveClient(GoogleSignInAccount signInAccount) {
102100
/**
103101
* Shows a toast message.
104102
*/
105-
protected void showMessage(String message) {
103+
void showMessage(String message) {
106104
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
107105
}
108106

@@ -111,11 +109,11 @@ protected void showMessage(String message) {
111109
*/
112110
protected abstract void onDriveClientReady();
113111

114-
protected DriveClient getDriveClient() {
112+
DriveClient getDriveClient() {
115113
return mDriveClient;
116114
}
117115

118-
protected DriveResourceClient getDriveResourceClient() {
116+
DriveResourceClient getDriveResourceClient() {
119117
return mDriveResourceClient;
120118
}
121119
}

conflict/app/src/main/java/com/google/android/gms/drive/sample/conflict/ConflictResolver.java

+61-87
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*
22
* Copyright 2014 Google Inc. All Rights Reserved.
33
*
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
55
* in compliance with the License. You may obtain a copy of the License at
66
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
88
*
9-
* Unless required by applicable law or agreed to in writing, software distributed under the
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
1010
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
1111
* express or implied. See the License for the specific language governing permissions and
1212
* limitations under the License.
@@ -15,7 +15,6 @@
1515

1616
import android.content.Context;
1717
import android.content.Intent;
18-
import android.support.annotation.NonNull;
1918
import android.support.v4.content.LocalBroadcastManager;
2019
import android.util.Log;
2120

@@ -32,9 +31,6 @@
3231
import com.google.android.gms.drive.MetadataChangeSet;
3332
import com.google.android.gms.drive.events.CompletionEvent;
3433
import com.google.android.gms.tasks.Continuation;
35-
import com.google.android.gms.tasks.OnFailureListener;
36-
import com.google.android.gms.tasks.OnSuccessListener;
37-
import com.google.android.gms.tasks.Task;
3834

3935
import java.io.InputStream;
4036
import java.io.OutputStream;
@@ -88,103 +84,81 @@ void resolve() {
8884
GoogleSignIn.getClient(mContext, signInOptionsBuilder.build());
8985
signInClient.silentSignIn()
9086
.continueWith(mExecutorService,
91-
new Continuation<GoogleSignInAccount, Void>() {
92-
@Override
93-
public Void then(@NonNull Task<GoogleSignInAccount> signInTask)
94-
throws Exception {
95-
mDriveResourceClient = Drive.getDriveResourceClient(
96-
mContext, signInTask.getResult());
97-
mBaseContent = ConflictUtil.getStringFromInputStream(
98-
mConflictedCompletionEvent.getBaseContentsInputStream());
99-
mModifiedContent = ConflictUtil.getStringFromInputStream(
100-
mConflictedCompletionEvent
101-
.getModifiedContentsInputStream());
102-
return null;
103-
}
87+
(Continuation<GoogleSignInAccount, Void>) signInTask -> {
88+
mDriveResourceClient = Drive.getDriveResourceClient(
89+
mContext, signInTask.getResult());
90+
mBaseContent = ConflictUtil.getStringFromInputStream(
91+
mConflictedCompletionEvent.getBaseContentsInputStream());
92+
mModifiedContent = ConflictUtil.getStringFromInputStream(
93+
mConflictedCompletionEvent
94+
.getModifiedContentsInputStream());
95+
return null;
10496
})
10597
.continueWithTask(mExecutorService,
106-
new Continuation<Void, Task<DriveContents>>() {
107-
@Override
108-
public Task<DriveContents> then(@NonNull Task<Void> task)
109-
throws Exception {
110-
DriveId driveId = mConflictedCompletionEvent.getDriveId();
111-
return mDriveResourceClient.openFile(
112-
driveId.asDriveFile(), DriveFile.MODE_READ_ONLY);
113-
}
98+
task -> {
99+
DriveId driveId = mConflictedCompletionEvent.getDriveId();
100+
return mDriveResourceClient.openFile(
101+
driveId.asDriveFile(), DriveFile.MODE_READ_ONLY);
114102
})
115103
.continueWithTask(mExecutorService,
116-
new Continuation<DriveContents, Task<DriveContents>>() {
117-
@Override
118-
public Task<DriveContents> then(@NonNull Task<DriveContents> task)
119-
throws Exception {
120-
mDriveContents = task.getResult();
121-
InputStream serverInputStream = task.getResult().getInputStream();
122-
mServerContent =
123-
ConflictUtil.getStringFromInputStream(serverInputStream);
124-
return mDriveResourceClient.reopenContentsForWrite(mDriveContents);
125-
}
104+
task -> {
105+
mDriveContents = task.getResult();
106+
InputStream serverInputStream = task.getResult().getInputStream();
107+
mServerContent =
108+
ConflictUtil.getStringFromInputStream(serverInputStream);
109+
return mDriveResourceClient.reopenContentsForWrite(mDriveContents);
126110
})
127111
.continueWithTask(mExecutorService,
128-
new Continuation<DriveContents, Task<Void>>() {
129-
@Override
130-
public Task<Void> then(@NonNull Task<DriveContents> task)
131-
throws Exception {
132-
DriveContents contentsForWrite = task.getResult();
133-
mResolvedContent = ConflictUtil.resolveConflict(
134-
mBaseContent, mServerContent, mModifiedContent);
112+
task -> {
113+
DriveContents contentsForWrite = task.getResult();
114+
mResolvedContent = ConflictUtil.resolveConflict(
115+
mBaseContent, mServerContent, mModifiedContent);
135116

136-
OutputStream outputStream = contentsForWrite.getOutputStream();
137-
try (Writer writer = new OutputStreamWriter(outputStream)) {
138-
writer.write(mResolvedContent);
139-
}
117+
OutputStream outputStream = contentsForWrite.getOutputStream();
118+
try (Writer writer = new OutputStreamWriter(outputStream)) {
119+
writer.write(mResolvedContent);
120+
}
140121

141-
// It is not likely that resolving a conflict will result in another
142-
// conflict, but it can happen if the file changed again while this
143-
// conflict was resolved. Since we already implemented conflict
144-
// resolution and we never want to miss user data, we commit here
145-
// with execution options in conflict-aware mode (otherwise we would
146-
// overwrite server content).
147-
ExecutionOptions executionOptions =
148-
new ExecutionOptions.Builder()
149-
.setNotifyOnCompletion(true)
150-
.setConflictStrategy(
151-
ExecutionOptions
152-
.CONFLICT_STRATEGY_KEEP_REMOTE)
153-
.build();
122+
// It is not likely that resolving a conflict will result in another
123+
// conflict, but it can happen if the file changed again while this
124+
// conflict was resolved. Since we already implemented conflict
125+
// resolution and we never want to miss user data, we commit here
126+
// with execution options in conflict-aware mode (otherwise we would
127+
// overwrite server content).
128+
ExecutionOptions executionOptions =
129+
new ExecutionOptions.Builder()
130+
.setNotifyOnCompletion(true)
131+
.setConflictStrategy(
132+
ExecutionOptions
133+
.CONFLICT_STRATEGY_KEEP_REMOTE)
134+
.build();
154135

155-
// Commit resolved contents.
156-
MetadataChangeSet modifiedMetadataChangeSet =
157-
mConflictedCompletionEvent.getModifiedMetadataChangeSet();
158-
return mDriveResourceClient.commitContents(contentsForWrite,
159-
modifiedMetadataChangeSet, executionOptions);
160-
}
136+
// Commit resolved contents.
137+
MetadataChangeSet modifiedMetadataChangeSet =
138+
mConflictedCompletionEvent.getModifiedMetadataChangeSet();
139+
return mDriveResourceClient.commitContents(contentsForWrite,
140+
modifiedMetadataChangeSet, executionOptions);
161141
})
162-
.addOnSuccessListener(new OnSuccessListener<Void>() {
163-
@Override
164-
public void onSuccess(Void aVoid) {
165-
mConflictedCompletionEvent.dismiss();
166-
Log.d(TAG, "resolved list");
167-
sendResult(mModifiedContent);
168-
}
142+
.addOnSuccessListener(aVoid -> {
143+
mConflictedCompletionEvent.dismiss();
144+
Log.d(TAG, "resolved list");
145+
sendResult(mModifiedContent);
169146
})
170-
.addOnFailureListener(new OnFailureListener() {
171-
@Override
172-
public void onFailure(@NonNull Exception e) {
173-
// The contents cannot be reopened at this point, probably due to
174-
// connectivity, so by snoozing the event we will get it again later.
175-
Log.d(TAG, "Unable to write resolved content, snoozing completion event.",
176-
e);
177-
mConflictedCompletionEvent.snooze();
178-
if (mDriveContents != null) {
179-
mDriveResourceClient.discardContents(mDriveContents);
180-
}
147+
.addOnFailureListener(e -> {
148+
// The contents cannot be reopened at this point, probably due to
149+
// connectivity, so by snoozing the event we will get it again later.
150+
Log.d(TAG, "Unable to write resolved content, snoozing completion event.",
151+
e);
152+
mConflictedCompletionEvent.snooze();
153+
if (mDriveContents != null) {
154+
mDriveResourceClient.discardContents(mDriveContents);
181155
}
182156
});
183157
// [END resolve_conflict]
184158
}
185159

186160
/**
187-
* Notify the UI that the list should be updated
161+
* Notify the UI that the list should be updated.
188162
*
189163
* @param resolution Resolved grocery list.
190164
*/

0 commit comments

Comments
 (0)