diff --git a/ChangeLog.txt b/ChangeLog.txt index 0350931cc..1ab1292fa 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,7 @@ +3.0.1 (2017-03-29) +--------------------------------------------- +- Add OpenWith support for official partners. + 3.0.0 (2017-03-17) --------------------------------------------- - Breaking changes: diff --git a/ReadMe.md b/ReadMe.md index 1794524cc..457428246 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,7 +14,7 @@ If you're using Maven, then edit your project's "pom.xml" and add this to the `< com.dropbox.core dropbox-core-sdk - 3.0.0 + 3.0.1 ``` @@ -23,7 +23,7 @@ If you are using Gradle, then edit your project's "build.gradle" and add this to ```groovy dependencies { // ... - compile 'com.dropbox.core:dropbox-core-sdk:3.0.0' + compile 'com.dropbox.core:dropbox-core-sdk:3.0.1' } ``` diff --git a/examples/android/src/main/AndroidManifest.xml b/examples/android/src/main/AndroidManifest.xml index fe918c0a4..8219a794d 100644 --- a/examples/android/src/main/AndroidManifest.xml +++ b/examples/android/src/main/AndroidManifest.xml @@ -12,24 +12,21 @@ android:label="@string/app_name" android:theme="@style/AppTheme" android:supportsRtl="false"> - + android:name=".UserActivity" + android:label="@string/app_name"> - - + android:name=".FilesActivity" + android:label="@string/title_activity_files" /> + android:launchMode="singleTask"> @@ -41,6 +38,15 @@ + + + + + + + - + \ No newline at end of file diff --git a/examples/android/src/main/java/com/dropbox/core/examples/android/DropboxActivity.java b/examples/android/src/main/java/com/dropbox/core/examples/android/DropboxActivity.java index 5f035e09a..79e52c666 100644 --- a/examples/android/src/main/java/com/dropbox/core/examples/android/DropboxActivity.java +++ b/examples/android/src/main/java/com/dropbox/core/examples/android/DropboxActivity.java @@ -27,6 +27,12 @@ protected void onResume() { } else { initAndLoadData(accessToken); } + + String uid = Auth.getUid(); + String storedUid = prefs.getString("user-id", null); + if (uid != null && !uid.equals(storedUid)) { + prefs.edit().putString("user-id", uid).apply(); + } } private void initAndLoadData(String accessToken) { diff --git a/examples/android/src/main/java/com/dropbox/core/examples/android/UserActivity.java b/examples/android/src/main/java/com/dropbox/core/examples/android/UserActivity.java index 21e19c7ca..904244346 100644 --- a/examples/android/src/main/java/com/dropbox/core/examples/android/UserActivity.java +++ b/examples/android/src/main/java/com/dropbox/core/examples/android/UserActivity.java @@ -1,5 +1,7 @@ package com.dropbox.core.examples.android; +import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.util.Log; @@ -8,6 +10,7 @@ import android.widget.TextView; import com.dropbox.core.android.Auth; +import com.dropbox.core.examples.android.internal.OpenWithActivity; import com.dropbox.core.v2.users.FullAccount; @@ -41,6 +44,15 @@ public void onClick(View v) { startActivity(FilesActivity.getIntent(UserActivity.this, "")); } }); + + Button openWithButton = (Button)findViewById(R.id.open_with); + openWithButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent openWithIntent = new Intent(UserActivity.this, OpenWithActivity.class); + startActivity(openWithIntent); + } + }); } @Override @@ -53,12 +65,14 @@ protected void onResume() { findViewById(R.id.name_text).setVisibility(View.VISIBLE); findViewById(R.id.type_text).setVisibility(View.VISIBLE); findViewById(R.id.files_button).setEnabled(true); + findViewById(R.id.open_with).setEnabled(true); } else { findViewById(R.id.login_button).setVisibility(View.VISIBLE); findViewById(R.id.email_text).setVisibility(View.GONE); findViewById(R.id.name_text).setVisibility(View.GONE); findViewById(R.id.type_text).setVisibility(View.GONE); findViewById(R.id.files_button).setEnabled(false); + findViewById(R.id.open_with).setEnabled(false); } } diff --git a/examples/android/src/main/java/com/dropbox/core/examples/android/internal/OpenWithActivity.java b/examples/android/src/main/java/com/dropbox/core/examples/android/internal/OpenWithActivity.java new file mode 100644 index 000000000..29e16c0b6 --- /dev/null +++ b/examples/android/src/main/java/com/dropbox/core/examples/android/internal/OpenWithActivity.java @@ -0,0 +1,202 @@ +package com.dropbox.core.examples.android.internal; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.os.Parcel; +import android.support.v7.widget.Toolbar; +import android.util.Base64; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import com.dropbox.core.android.Auth; +import com.dropbox.core.android.DbxOfficialAppConnector; +import com.dropbox.core.android.DropboxParseException; +import com.dropbox.core.android.DropboxUidNotInitializedException; +import com.dropbox.core.examples.android.DropboxActivity; +import com.dropbox.core.examples.android.R; + +/** + * This example is only for 3rd party apps who registered OpenWith feature at our server side who use + * intent action {@value DbxOfficialAppConnector#ACTION_DBXC_EDIT} and + * {@value DbxOfficialAppConnector#ACTION_DBXC_VIEW} to jump to their apps. Don't follow this if + * you don't need openwith or if you use regular {@value Intent#ACTION_EDIT} and + * {@value Intent#ACTION_VIEW}. + */ +public class OpenWithActivity extends DropboxActivity { + private DbxOfficialAppConnector mDoac; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_open_with); + + Toolbar toolbar = (Toolbar) findViewById(R.id.app_bar); + setSupportActionBar(toolbar); + + Button generateIntentButton = (Button)findViewById(R.id.generate_intent); + generateIntentButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EditText editText = (EditText) findViewById(R.id.editText); + String path = editText.getText().toString(); + //fake OpenWithIntent with some dummy parameters + Intent fakeOpenWithIntent = generateOpenWithIntent(path); + //encode the fake OpenWithIntent into UtmContent + String encodedFakeIntent = encodeOpenWithIntent(fakeOpenWithIntent); + try { + //test that decoding utmcontent works + Intent decodedIntent = DbxOfficialAppConnector + .generateOpenWithIntentFromUtmContent(encodedFakeIntent); + //start that fake OpenWithIntent. This will lead us to a new OpenWithActivity. + startActivity(decodedIntent); + } catch (DropboxParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + + Button mInstalled = (Button)findViewById(R.id.is_installed); + mInstalled.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + DbxOfficialAppConnector.DbxOfficialAppInstallInfo installInfo = + DbxOfficialAppConnector.isInstalled(OpenWithActivity.this); + showToast((installInfo != null)?installInfo.toString():"Not installed!"); + } + }); + + Button mGenLinked = (Button)findViewById(R.id.is_linked_any_button); + mGenLinked.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean isSigned = DbxOfficialAppConnector.isAnySignedIn(OpenWithActivity.this); + showToast("Any Signed in?:" + isSigned); + } + }); + + Button mSpecLinked = (Button)findViewById(R.id.is_linked_spec_button); + mSpecLinked.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean isSigned = mDoac.isSignedIn(OpenWithActivity.this); + showToast("Signed in?:" + isSigned); + } + }); + + Button mPreview = (Button)findViewById(R.id.preview_button); + mPreview.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EditText editText = (EditText) findViewById(R.id.editText); + String path = editText.getText().toString(); + Intent pIntent = mDoac.getPreviewFileIntent(OpenWithActivity.this, path, ""); + startActivity(pIntent); + } + }); + + Button mUpgrade = (Button)findViewById(R.id.upgrade_button); + mUpgrade.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent uIntent = mDoac.getUpgradeAccountIntent(OpenWithActivity.this); + startActivity(uIntent); + } + }); + + } + + /* Because it's just a fake intent, we just print it in Toast and do nothing here. As third + * party app you should take the intent from Dropbox official app and potentially go through + * the auth flow. Finally handle that file sent with this intent. + */ + private void handleFakeOpenWithIntent(Intent intent) { + if (intent.getAction() == DbxOfficialAppConnector.ACTION_DBXC_EDIT || + intent.getAction() == DbxOfficialAppConnector.ACTION_DBXC_VIEW) { + String path = intent.getStringExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_PATH); + String uid = intent.getStringExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_UID); + boolean read_only = intent.getBooleanExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_READ_ONLY, false); + String session_id = intent.getStringExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_SESSION_ID); + showToast(path + uid + read_only + session_id); + } + } + + protected Intent generateOpenWithIntent(String path) { + /* + * Generate an OpenWithIntent. + * Real 3rd party apps should never run this function as DropboxApp does this entirely + */ + String uid = Auth.getUid(); + + // fake the URI + // WARNING: URI FORMAT IS NOT FINALIZED AND MAY CHANGE AT ANY TIME + Uri.Builder builder = new Uri.Builder(); + builder.scheme("content"); + builder.authority("com.dropbox.android.FileCache"); + builder.appendPath("filecache"); + builder.appendPath(uid); + + for (String component : path.substring(1).split("/")) { + builder.appendPath(component); + } + Uri uri = builder.build(); + // end URI fakery + + Intent owpIntent = new Intent(DbxOfficialAppConnector.ACTION_DBXC_EDIT, uri); + + // extras + owpIntent.putExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_PATH, path); + owpIntent.putExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_UID, uid); + owpIntent.putExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_READ_ONLY, false); + owpIntent.putExtra(DbxOfficialAppConnector.EXTRA_DROPBOX_SESSION_ID, "generated"); + + owpIntent.setDataAndType(uri, "text/plain"); + + return owpIntent; + } + + protected String encodeOpenWithIntent(Intent owpIntent) { + /* + * Encode OpenWith intent + * Real 3rd party apps should never run this function as DropboxApp does this entirely + */ + + Bundle extras = owpIntent.getExtras(); + extras.putString("_action", owpIntent.getAction()); + extras.putParcelable("_uri", owpIntent.getData()); + extras.putString("_type", owpIntent.getType()); + + // marshall it! + final Parcel parcel = Parcel.obtain(); + parcel.writeBundle(extras); + byte[] b = parcel.marshall(); + parcel.recycle(); + return new String(Base64.encode(b, 0)); + } + + private void showToast(String msg) { + Toast error = Toast.makeText(this, msg, Toast.LENGTH_LONG); + error.show(); + } + + @Override + protected void loadData() { + try { + String uid = Auth.getUid(); + if (uid == null) { + SharedPreferences prefs = getSharedPreferences("dropbox-sample", MODE_PRIVATE); + uid = prefs.getString("user-id", null); + } + this.mDoac = new DbxOfficialAppConnector(uid); + } catch (DropboxUidNotInitializedException e) { + e.printStackTrace(); + return; + } + + handleFakeOpenWithIntent(getIntent()); + } +} diff --git a/examples/android/src/main/res/layout/activity_open_with.xml b/examples/android/src/main/res/layout/activity_open_with.xml new file mode 100644 index 000000000..790837506 --- /dev/null +++ b/examples/android/src/main/res/layout/activity_open_with.xml @@ -0,0 +1,72 @@ + + + + + + + + + + +