diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2017-10-08 20:54:49 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2017-10-08 20:54:49 +0900 |
commit | afb8ce292daabe75c11c094c1cd4d9a7a9a89c20 (patch) | |
tree | e1b893d1016be368d12faccb4676568348f1b2de | |
parent | 16fbf18a9273a1acea81a0200d6988b04b253303 (diff) | |
download | SmileEssence-afb8ce292daabe75c11c094c1cd4d9a7a9a89c20.tar.gz |
get intents back2017-10-08
4 files changed, 130 insertions, 190 deletions
diff --git a/app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt b/app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt deleted file mode 100644 index 2c202f37..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/IntentRouter.kt +++ /dev/null @@ -1,138 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2012-2014 lacolaco.net - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.lacolaco.smileessence - -import android.app.Activity -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.text.TextUtils -import android.widget.Toast -import net.lacolaco.smileessence.activity.MainActivity -import net.lacolaco.smileessence.command.CommandOpenUserDetail -import net.lacolaco.smileessence.entity.Tweet -import net.lacolaco.smileessence.logging.Logger -import net.lacolaco.smileessence.util.UIHandler -import net.lacolaco.smileessence.view.DialogHelper -import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment - -import java.util.regex.Matcher -import java.util.regex.Pattern - -object IntentRouter { - - // ------------------------------ FIELDS ------------------------------ - - private val TWITTER_HOST = "twitter.com" - private val TWITTER_STATUS_PATTERN = Pattern.compile("\\A(?:/#!)?/(?:\\w{1,15})/status(?:es)?/(\\d+)\\z", Pattern.CASE_INSENSITIVE) - private val TWITTER_USER_PATTERN = Pattern.compile("\\A(?:/#!)?/(\\w{1,15})/?\\z", Pattern.CASE_INSENSITIVE) - private val TWITTER_POST_PATTERN = Pattern.compile("\\A/(intent/tweet|share)\\z", Pattern.CASE_INSENSITIVE) - - // -------------------------- STATIC METHODS -------------------------- - - fun onNewIntent(activity: MainActivity, intent: Intent) { - Logger.debug("onNewIntent") - val uri = intent.data - if (uri != null) { - onUriIntent(activity, uri) - } else if (intent.action != null) { - when (intent.action) { - Intent.ACTION_SEND -> { - if ("text/plain" == intent.type) { - val extra = intent.extras - if (extra != null) { - val text = getText(extra) - openPostPage(activity, text) - } - } else if (intent.type.startsWith("image/")) { - val imageUri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM) - openPostPageWithImage(activity, imageUri) - } - } - } - } - } - - private fun onUriIntent(activity: MainActivity, uri: Uri) { - Logger.debug(uri.toString()) - - if (uri.host == TWITTER_HOST) { - val postMatcher = TWITTER_POST_PATTERN.matcher(uri.path) // /share and /intent/tweet: don't accept status parameter - if (postMatcher.find()) { - openPostPage(activity, extractText(uri)) - return - } - val statusMatcher = TWITTER_STATUS_PATTERN.matcher(uri.path) - if (statusMatcher.find()) { - Tweet.fetchTask(java.lang.Long.parseLong(statusMatcher.group(1)), activity.world.account) - .onDoneUI { tweet -> DialogHelper.showDialog(activity, StatusDetailDialogFragment.newInstance(tweet)) } - .onFail { x -> Application.toast(R.string.error_intent_status_cannot_load) } - .execute() - return - } - val userMatcher = TWITTER_USER_PATTERN.matcher(uri.path) - if (userMatcher.find()) { - showUserDialog(activity, userMatcher.group(1)) - } - } - } - - private fun getText(extra: Bundle): String { - val builder = StringBuilder() - if (!TextUtils.isEmpty(extra.getCharSequence(Intent.EXTRA_SUBJECT))) { - builder.append(extra.getCharSequence(Intent.EXTRA_SUBJECT)).append(" ") - } - builder.append(extra.getCharSequence(Intent.EXTRA_TEXT)) - return builder.toString() - } - - private fun extractText(uri: Uri): String { - var result = "" - val text = uri.getQueryParameter("text") - val url = uri.getQueryParameter("url") - val via = uri.getQueryParameter("via") - val hashtags = uri.getQueryParameter("hashtags") - - if (!TextUtils.isEmpty(text)) result += text - if (!TextUtils.isEmpty(url)) result += " " + url - if (!TextUtils.isEmpty(hashtags)) result += " " + hashtags.trim { it <= ' ' }.replace(",".toRegex(), " #") - if (!TextUtils.isEmpty(via)) result += " via @" + via - - return result - } - - private fun showUserDialog(activity: MainActivity, screenName: String) { - val openUserDetail = CommandOpenUserDetail(activity, screenName) - openUserDetail.execute() - } - - private fun openPostPage(activity: MainActivity, str: String) { - UIHandler().post { activity.world.postState.beginTransaction().setText(str).commitWithOpen(activity) } - } - - private fun openPostPageWithImage(activity: MainActivity, imageUri: Uri) { - UIHandler().post { activity.openPostPageWithImage(imageUri) } - } -} diff --git a/app/src/main/java/net/lacolaco/smileessence/World.kt b/app/src/main/java/net/lacolaco/smileessence/World.kt index 1522b465..638607d1 100644 --- a/app/src/main/java/net/lacolaco/smileessence/World.kt +++ b/app/src/main/java/net/lacolaco/smileessence/World.kt @@ -1,5 +1,6 @@ package net.lacolaco.smileessence +import android.content.Intent import android.support.annotation.StringRes import de.keyboardsurfer.android.widget.crouton.Configuration import de.keyboardsurfer.android.widget.crouton.Crouton @@ -31,6 +32,9 @@ class World(val account: Account) { private val resId: Int = 0 // XXX: Fetch from Account // XXX: Move to MainActivity val postState = PostState() + // XXX: Workaround for a bug in Android + @Deprecated("A temporary workaround") + var mainActivityIntent: Intent? = null // Timelines private val tweets = ArrayList<Tweet>() private val tweetNotifiers = WeakHashMap<Any, (Tweet) -> Unit>() diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt index 28a95a27..cdbc94d4 100644 --- a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt +++ b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt @@ -31,6 +31,7 @@ import android.net.Uri import android.os.Bundle import android.provider.MediaStore import android.support.v4.view.ViewPager +import android.text.TextUtils import android.view.Menu import android.view.MenuItem import android.view.WindowManager @@ -38,15 +39,21 @@ import android.widget.ImageView import de.keyboardsurfer.android.widget.crouton.Crouton import kotlinx.android.synthetic.main.layout_main.* import net.lacolaco.smileessence.* +import net.lacolaco.smileessence.command.CommandOpenUserDetail import net.lacolaco.smileessence.data.ExtractionWord +import net.lacolaco.smileessence.entity.Tweet import net.lacolaco.smileessence.logging.Logger import net.lacolaco.smileessence.twitter.task.Users import net.lacolaco.smileessence.util.BitmapURLTask +import net.lacolaco.smileessence.view.DialogHelper import net.lacolaco.smileessence.view.adapter.PageListAdapter import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment +import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment +import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment import net.lacolaco.smileessence.view.page.* import org.jetbrains.anko.browse import org.jetbrains.anko.startActivity; +import java.util.regex.Pattern class MainActivity : Activity(), ViewPager.OnPageChangeListener { val world: World by lazy { @@ -111,6 +118,65 @@ class MainActivity : Activity(), ViewPager.OnPageChangeListener { BitmapURLTask(world.account.user.profileImageUrl, currentAccountIconImageView).execute() } + private fun processIntent(intent: Intent) { + val uri = intent.getParcelableExtra<Uri>(KEY_ORIGINAL_DATA) + if (uri != null){ + if (uri.host == "twitter.com") { + // /share and /intent/tweet: don't accept status parameter + val postMatcher = TWITTER_POST_PATTERN.matcher(uri.path) + if (postMatcher.find()) { + var text = uri.getQueryParameter("text") ?: "" + val url = uri.getQueryParameter("url") + if (!TextUtils.isEmpty(url)) + text += " " + url + val hashtags = uri.getQueryParameter("hashtags") + if (!TextUtils.isEmpty(hashtags)) + text += " " + hashtags.trim { it <= ' ' }.replace(",".toRegex(), " #") + val via = uri.getQueryParameter("via") + if (!TextUtils.isEmpty(via)) + text += " via @" + via + world.postState.beginTransaction().setText(text).commitWithOpen(this) + return + } + val statusMatcher = TWITTER_STATUS_PATTERN.matcher(uri.path) + if (statusMatcher.find()) { + Tweet.fetchTask(java.lang.Long.parseLong(statusMatcher.group(1)), world.account) + .onDoneUI { tweet -> DialogHelper.showDialog(this, StatusDetailDialogFragment.newInstance(tweet)) } + .onFail { _ -> world.notifyError(R.string.error_intent_status_cannot_load) } + .execute() + return + } + val userMatcher = TWITTER_USER_PATTERN.matcher(uri.path) + if (userMatcher.find()) { + Users.GetTask(world.account, userMatcher.group(1)) + .onDoneUI { user -> + DialogHelper.showDialog(this, UserDetailDialogFragment.newInstance(user)) + } + .onFail { _ -> world.notifyError(R.string.notice_error_show_user) } + .execute() + return + } + } + } else when (intent.action) { + Intent.ACTION_SEND -> { + val type = intent.getStringExtra(KEY_ORIGINAL_TYPE) + if (type == "text/plain") { + val extra = intent.extras + if (extra != null) { + var text = extra.getCharSequence(Intent.EXTRA_TEXT).toString() + if (!TextUtils.isEmpty(extra.getCharSequence(Intent.EXTRA_SUBJECT))) { + text = extra.getCharSequence(Intent.EXTRA_SUBJECT).toString() + " " + text + } + world.postState.beginTransaction().setText(text).commitWithOpen(this) + return + } + } else if (type != null && type.startsWith("image/")) { + openPostPageWithImage(intent.getParcelableExtra(Intent.EXTRA_STREAM)) + } + } + } + } + // ------------------------ OVERRIDE METHODS ------------------------ override fun onBackPressed() { @@ -183,7 +249,7 @@ class MainActivity : Activity(), ViewPager.OnPageChangeListener { setTitle() // refresh all pages - for (i in 0..pagerAdapter.count - 1) { + for (i in 0 until pagerAdapter.count) { val pf = pagerAdapter.getCachedFragment(i) if (pf != null && pf.isAdded) { Logger.debug(String.format("PageFragment %s is already attached; refreshing", pf.javaClass.name)) @@ -194,7 +260,7 @@ class MainActivity : Activity(), ViewPager.OnPageChangeListener { // start user stream world.setupStreaming() - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } override fun onDestroy() { @@ -248,6 +314,17 @@ class MainActivity : Activity(), ViewPager.OnPageChangeListener { super.onResume() Application.currentWorld = world world.setMainActivityActive(true) + val intent = world.mainActivityIntent + if (intent != null) { + world.mainActivityIntent = null + processIntent(intent) + } + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + // With the current releases (~ 7) of Android, onNewIntent() doesn't seem to be called properly + if (false) processIntent(intent) } // --------------------- Interface OnPageChangeListener --------------------- @@ -263,5 +340,11 @@ class MainActivity : Activity(), ViewPager.OnPageChangeListener { companion object { val REQUEST_GET_PICTURE_FROM_GALLERY = 11 + val KEY_ORIGINAL_DATA = "originalData" + val KEY_ORIGINAL_TYPE = "originalType" + private val TWITTER_POST_PATTERN = Pattern.compile("\\A/(intent/tweet|share)\\z", Pattern.CASE_INSENSITIVE) + private val TWITTER_STATUS_PATTERN = Pattern.compile("\\A(?:/#!)?/(?:\\w{1,15})/status(?:es)?/(\\d+)\\z", Pattern.CASE_INSENSITIVE) + private val TWITTER_USER_PATTERN = Pattern.compile("\\A(?:/#!)?/(\\w{1,15})/?\\z", Pattern.CASE_INSENSITIVE) + } } diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt index 50cbe0aa..a279afed 100644 --- a/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt +++ b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.kt @@ -25,12 +25,12 @@ package net.lacolaco.smileessence.activity import android.app.Activity +import android.content.ComponentName import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle -import android.support.v4.app.ActivityCompat -import android.support.v4.content.ContextCompat +import android.os.Process import android.view.Menu import android.view.MenuItem import android.view.View @@ -48,30 +48,30 @@ import kotlinx.android.synthetic.main.list_item_account.view.* import kotlinx.coroutines.experimental.android.UI import kotlinx.coroutines.experimental.async import org.jetbrains.anko.coroutines.experimental.bg -import org.jetbrains.anko.intentFor import org.jetbrains.anko.startActivityForResult import java.util.ArrayList class ManageAccountsActivity : Activity() { private val adapter by lazy { EditAccountsAdapter() } + private lateinit var receivedIntent: Intent override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // Check if it is initiated from launcher - if (!intent.getBooleanExtra(INTENT_KEY_NOINIT, false)) { - val wextPermission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) - if (wextPermission != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION) - } + // Save the received intent + receivedIntent = Intent(intent) - // Skip this activity if app is already started - val currentWorld = Application.currentWorld - if (currentWorld != null) { - goToWorld(currentWorld) - return - } + // Check if it is initiated from launcher + if (android.os.Build.VERSION.SDK_INT >= 23 && + checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, Process.myPid(), + Process.myUid()) != PackageManager.PERMISSION_GRANTED) + requestPermissions(arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION) + + // Skip this activity if app is already started + if (Application.currentWorld != null && !intent.getBooleanExtra(INTENT_KEY_NOINIT, false)) { + goToWorld(Application.currentWorld!!) + return } setContentView(R.layout.layout_edit_list) @@ -97,10 +97,15 @@ class ManageAccountsActivity : Activity() { } } + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + receivedIntent = Intent(intent) + } + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { when (requestCode) { REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION -> { - if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // OK val currentWorld = Application.currentWorld if (currentWorld != null) { @@ -117,10 +122,13 @@ class ManageAccountsActivity : Activity() { private fun goToWorld(world: World) { // Continue the existing MainActivity - val intent = intentFor<MainActivity>() - intent.data = Uri.parse("smileessence://mainactivity/?user_id=" + world.account.userId) + receivedIntent.component = ComponentName(this, MainActivity::class.java) + receivedIntent.putExtra(MainActivity.KEY_ORIGINAL_DATA, receivedIntent.data) + receivedIntent.putExtra(MainActivity.KEY_ORIGINAL_TYPE, receivedIntent.type) + receivedIntent.data = Uri.parse("smileessence://mainactivity/?user_id=" + world.account.userId) finish() - startActivity(intent) + world.mainActivityIntent = receivedIntent + startActivity(receivedIntent) } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -153,15 +161,9 @@ class ManageAccountsActivity : Activity() { } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - REQUEST_OAUTH -> { - receiveOAuth(requestCode, resultCode, data) - } - else -> { - Logger.error("[BUG] unexpected activity result: reqCode=$requestCode, resCode=$resultCode") - } - } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) = when (requestCode) { + REQUEST_OAUTH -> receiveOAuth(requestCode, resultCode, data) + else -> Logger.error("[BUG] unexpected activity result: reqCode=$requestCode, resCode=$resultCode") } private fun receiveOAuth(requestCode: Int, resultCode: Int, data: Intent?) { @@ -183,23 +185,13 @@ class ManageAccountsActivity : Activity() { } private inner class EditAccountsAdapter : BaseAdapter() { - private val accounts: MutableList<Account> + private val accounts: MutableList<Account> = ArrayList(Account.all()) - init { - accounts = ArrayList(Account.all()) - } + override fun getCount(): Int = accounts.size - override fun getCount(): Int { - return accounts.size - } + override fun getItem(position: Int): Account = accounts[position] - override fun getItem(position: Int): Account { - return accounts[position] - } - - override fun getItemId(position: Int): Long { - return accounts[position].userId - } + override fun getItemId(position: Int): Long = accounts[position].userId override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val view = convertView ?: layoutInflater.inflate(R.layout.list_item_account, parent, false) @@ -209,14 +201,12 @@ class ManageAccountsActivity : Activity() { return view } - fun add(account: Account): Int { - if (!accounts.contains(account)) { - accounts.add(account) - notifyDataSetChanged() - return accounts.size - 1 - } else { - return accounts.indexOf(account) - } + fun add(account: Account): Int = if (!accounts.contains(account)) { + accounts.add(account) + notifyDataSetChanged() + accounts.size - 1 + } else { + accounts.indexOf(account) } fun removeAt(position: Int): Account? { @@ -230,5 +220,6 @@ class ManageAccountsActivity : Activity() { val INTENT_KEY_NOINIT = "noInit" private val REQUEST_OAUTH = 10 private val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 11 + } } |