improved permission request

This commit is contained in:
Mariotaku Lee 2016-12-13 11:06:07 +08:00
parent 9b1b29c077
commit a34b576060
14 changed files with 244 additions and 182 deletions

View File

@ -175,7 +175,7 @@ dependencies {
compile "com.github.mariotaku.CommonsLibrary:io:$mariotaku_commons_library_version"
compile "com.github.mariotaku.CommonsLibrary:text:$mariotaku_commons_library_version"
compile "com.github.mariotaku.CommonsLibrary:text-kotlin:$mariotaku_commons_library_version"
compile 'com.github.mariotaku:KPreferences:0.9.2'
compile 'com.github.mariotaku:KPreferences:0.9.4'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'nl.komponents.kovenant:kovenant:3.3.0'
compile 'nl.komponents.kovenant:kovenant-android:3.3.0'

View File

@ -19,9 +19,7 @@
package org.mariotaku.twidere.util;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.content.ContextCompat;
import org.apache.commons.lang3.ArrayUtils;
@ -38,10 +36,6 @@ public class PermissionUtils {
return 0;
}
public static boolean hasPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
public static boolean hasPermission(String[] permissions, int[] grantResults, String permission) {
return getPermission(permissions, grantResults, permission) == PackageManager.PERMISSION_GRANTED;
}

View File

@ -35,4 +35,8 @@ operator fun Bundle.set(key: String, value: Parcelable?) {
operator fun Bundle.set(key: String, value: Array<out Parcelable>?) {
return putParcelableArray(key, value)
}
operator fun Bundle.set(key: String, value: Array<String>?) {
return putStringArray(key, value)
}

View File

@ -0,0 +1,17 @@
package org.mariotaku.ktextension
import android.content.Context
import android.content.pm.PackageManager
import android.support.v4.content.ContextCompat
/**
* Created by mariotaku on 2016/12/13.
*/
fun Context.checkAllSelfPermissionsGranted(vararg permissions: String): Boolean {
return permissions.none { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }
}
fun Context.checkAnySelfPermissionsGranted(vararg permissions: String): Boolean {
return permissions.any { ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED }
}

View File

@ -19,12 +19,10 @@
package org.mariotaku.twidere.activity
import android.Manifest
import android.accounts.AccountManager
import android.app.Activity
import android.app.Dialog
import android.content.*
import android.content.pm.PackageManager
import android.graphics.Canvas
import android.graphics.PorterDuff.Mode
import android.graphics.Rect
@ -34,9 +32,7 @@ import android.os.AsyncTask
import android.os.Bundle
import android.os.Parcelable
import android.provider.BaseColumns
import android.support.v4.app.ActivityCompat
import android.support.v4.app.DialogFragment
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.support.v7.view.SupportMenuInflater
import android.support.v7.widget.*
@ -49,7 +45,6 @@ import android.text.style.SuggestionSpan
import android.text.style.UpdateAppearance
import android.util.Log
import android.view.*
import android.view.ActionMode.Callback
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.widget.EditText
@ -66,6 +61,8 @@ import org.apache.commons.lang3.ObjectUtils
import org.mariotaku.abstask.library.AbstractTask
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.commons.io.StreamUtils
import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.checkAnySelfPermissionsGranted
import org.mariotaku.ktextension.setItemChecked
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.twidere.BuildConfig
@ -73,8 +70,10 @@ import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.ArrayRecyclerAdapter
import org.mariotaku.twidere.adapter.BaseRecyclerViewAdapter
import org.mariotaku.twidere.constant.KeyboardShortcutConstants
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.PermissionRequestDialog
import org.mariotaku.twidere.fragment.PermissionRequestDialog.PermissionRequestCancelCallback
import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras
@ -96,8 +95,10 @@ import java.io.*
import java.lang.ref.WeakReference
import java.util.*
import javax.inject.Inject
import android.Manifest.permission as AndroidPermission
class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener, OnLongClickListener, Callback, ATEToolbarCustomizer {
class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener, OnLongClickListener,
ActionMode.Callback, PermissionRequestCancelCallback, ATEToolbarCustomizer {
// Utility classes
@Inject
@ -225,8 +226,16 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
super.onStart()
imageUploaderUsed = !ServicePickerPreference.isNoneValue(preferences.getString(KEY_MEDIA_UPLOADER, null))
statusShortenerUsed = !ServicePickerPreference.isNoneValue(preferences.getString(KEY_STATUS_SHORTENER, null))
if (preferences.getBoolean(KEY_ATTACH_LOCATION)) {
requestOrUpdateLocation()
if (preferences[attachLocationKey]) {
if (checkAnySelfPermissionsGranted(AndroidPermission.ACCESS_COARSE_LOCATION, AndroidPermission.ACCESS_FINE_LOCATION)) {
try {
startLocationUpdateIfEnabled()
} catch (e: SecurityException) {
locationSwitch.checkedPosition = LOCATION_OPTIONS.indexOf(LOCATION_VALUE_NONE)
}
} else {
locationSwitch.checkedPosition = LOCATION_OPTIONS.indexOf(LOCATION_VALUE_NONE)
}
}
setMenu()
updateTextCount()
@ -904,8 +913,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
private fun handleIntent(intent: Intent): Boolean {
val action = intent.action ?: return false
shouldSaveAccounts = false
mentionUser = intent.getParcelableExtra<ParcelableUser>(EXTRA_USER)
inReplyToStatus = intent.getParcelableExtra<ParcelableStatus>(EXTRA_STATUS)
mentionUser = intent.getParcelableExtra(EXTRA_USER)
inReplyToStatus = intent.getParcelableExtra(EXTRA_STATUS)
when (action) {
INTENT_ACTION_REPLY -> {
return handleReplyIntent(inReplyToStatus)
@ -914,7 +923,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
return handleQuoteIntent(inReplyToStatus)
}
INTENT_ACTION_EDIT_DRAFT -> {
draft = intent.getParcelableExtra<Draft>(EXTRA_DRAFT)
draft = intent.getParcelableExtra(EXTRA_DRAFT)
return handleEditDraftIntent(draft)
}
INTENT_ACTION_MENTION -> {
@ -1146,28 +1155,38 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (PermissionUtils.getPermission(permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || PermissionUtils.getPermission(permissions, grantResults, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
try {
startLocationUpdateIfEnabled()
} catch (e: SecurityException) {
// That should not happen
}
when (requestCode) {
REQUEST_ATTACH_LOCATION_PERMISSION -> {
if (checkAnySelfPermissionsGranted(AndroidPermission.ACCESS_FINE_LOCATION, AndroidPermission.ACCESS_COARSE_LOCATION)) {
try {
startLocationUpdateIfEnabled()
} catch (e: SecurityException) {
// That should not happen
}
} else {
Toast.makeText(this, R.string.cannot_get_location, Toast.LENGTH_SHORT).show()
val editor = preferences.edit()
editor.putBoolean(KEY_ATTACH_LOCATION, false)
editor.putBoolean(KEY_ATTACH_PRECISE_LOCATION, false)
editor.apply()
locationSwitch.checkedPosition = ArrayUtils.indexOf(LOCATION_OPTIONS,
LOCATION_VALUE_NONE)
} else {
Toast.makeText(this, R.string.cannot_get_location, Toast.LENGTH_SHORT).show()
kPreferences.edit {
this[attachLocationKey] = false
this[attachPreciseLocationKey] = false
}
locationSwitch.checkedPosition = LOCATION_OPTIONS.indexOf(LOCATION_VALUE_NONE)
}
}
}
}
override fun onPermissionRequestCancelled(requestCode: Int) {
when (requestCode) {
REQUEST_ATTACH_LOCATION_PERMISSION -> {
locationSwitch.checkedPosition = LOCATION_OPTIONS.indexOf(LOCATION_VALUE_NONE)
}
}
}
private fun setRecentLocation(location: ParcelableLocation?) {
if (location != null) {
val attachPreciseLocation = preferences.getBoolean(KEY_ATTACH_PRECISE_LOCATION)
val attachPreciseLocation = kPreferences[attachPreciseLocationKey]
if (attachPreciseLocation) {
locationText.text = ParcelableLocationUtils.getHumanReadableString(location, 3)
} else {
@ -1192,11 +1211,11 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
@Throws(SecurityException::class)
private fun startLocationUpdateIfEnabled(): Boolean {
if (locationListener != null) return true
val attachLocation = preferences.getBoolean(KEY_ATTACH_LOCATION)
val attachLocation = kPreferences[attachLocationKey]
if (!attachLocation) {
return false
}
val attachPreciseLocation = preferences.getBoolean(KEY_ATTACH_PRECISE_LOCATION)
val attachPreciseLocation = kPreferences[attachPreciseLocationKey]
val criteria = Criteria()
if (attachPreciseLocation) {
criteria.accuracy = Criteria.ACCURACY_FINE
@ -1225,21 +1244,21 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
private fun requestOrUpdateLocation() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (checkAnySelfPermissionsGranted(AndroidPermission.ACCESS_COARSE_LOCATION, AndroidPermission.ACCESS_FINE_LOCATION)) {
try {
startLocationUpdateIfEnabled()
} catch (e: SecurityException) {
Toast.makeText(this, R.string.cannot_get_location, Toast.LENGTH_SHORT).show()
}
} else {
val permissions = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
ActivityCompat.requestPermissions(this, permissions, REQUEST_REQUEST_PERMISSIONS)
val permissions = arrayOf(AndroidPermission.ACCESS_COARSE_LOCATION, AndroidPermission.ACCESS_FINE_LOCATION)
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_compose_location),
permissions, REQUEST_ATTACH_LOCATION_PERMISSION)
}
}
private fun updateLocationState() {
val attachLocation = preferences.getBoolean(KEY_ATTACH_LOCATION)
val attachLocation = kPreferences[attachLocationKey]
locationIcon.isActivated = attachLocation
if (!attachLocation) {
locationText.setText(R.string.no_location)
@ -1268,8 +1287,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
editText.setSelection(textLength - (tweetLength - maxLength), textLength)
return
}
val attachLocation = preferences.getBoolean(KEY_ATTACH_LOCATION)
val attachPreciseLocation = preferences.getBoolean(KEY_ATTACH_PRECISE_LOCATION)
val attachLocation = kPreferences[attachLocationKey]
val attachPreciseLocation = kPreferences[attachPreciseLocationKey]
val accountKeys = accountsAdapter.selectedAccountKeys
val isPossiblySensitive = hasMedia && possiblySensitive
val update = ParcelableStatusUpdate()
@ -1285,7 +1304,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
update.is_possibly_sensitive = isPossiblySensitive
update.attachment_url = (draft?.action_extras as? UpdateStatusActionExtras)?.attachmentUrl
BackgroundOperationService.updateStatusesAsync(this, action, update)
if (preferences.getBoolean(KEY_NO_CLOSE_AFTER_TWEET_SENT, false) && inReplyToStatus == null) {
if (preferences[noCloseAfterTweetSentKey] && inReplyToStatus == null) {
possiblySensitive = false
shouldSaveAccounts = true
inReplyToStatus = null
@ -1390,7 +1409,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
setHasStableIds(true)
mInflater = activity.layoutInflater
selection = HashMap<UserKey, Boolean>()
isNameFirst = preferences.getBoolean(KEY_NAME_FIRST)
isNameFirst = preferences[nameFirstKey]
}
val imageLoader: MediaLoaderWrapper
@ -1605,8 +1624,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val textView = callback ?: return
val preferences = context.preferences
val attachLocation = preferences.getBoolean(KEY_ATTACH_LOCATION)
val attachPreciseLocation = preferences.getBoolean(KEY_ATTACH_PRECISE_LOCATION)
val attachLocation = preferences[attachLocationKey]
val attachPreciseLocation = preferences[attachPreciseLocationKey]
if (attachLocation) {
if (attachPreciseLocation) {
textView.text = ParcelableLocationUtils.getHumanReadableString(location, 3)
@ -1629,8 +1648,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
override fun afterExecute(textView: TextView?, addresses: List<Address>?) {
textView!!
val preferences = context.preferences
val attachLocation = preferences.getBoolean(KEY_ATTACH_LOCATION)
val attachPreciseLocation = preferences.getBoolean(KEY_ATTACH_PRECISE_LOCATION)
val attachLocation = preferences[attachLocationKey]
val attachPreciseLocation = preferences[attachPreciseLocationKey]
if (attachLocation) {
if (attachPreciseLocation) {
val location = params
@ -1896,6 +1915,9 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
private val LOCATION_OPTIONS = arrayOf(LOCATION_VALUE_NONE, LOCATION_VALUE_PLACE, LOCATION_VALUE_COORDINATE)
private const val REQUEST_ATTACH_LOCATION_PERMISSION = 301
private const val REQUEST_ATTACH_MEDIA_PERMISSION = 302
internal fun getDraftAction(intentAction: String?): String {
if (intentAction == null) {
return Draft.Action.UPDATE_STATUS

View File

@ -19,10 +19,8 @@
package org.mariotaku.twidere.activity
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
@ -30,12 +28,16 @@ import android.os.Environment.getExternalStorageDirectory
import android.support.v4.app.ActivityCompat
import android.support.v4.app.DialogFragment
import android.widget.Toast
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.checkAllSelfPermissionsGranted
import org.mariotaku.ktextension.convert
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.REQUEST_REQUEST_PERMISSIONS
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.fragment.FileSelectorDialogFragment
import org.mariotaku.twidere.util.PermissionUtils
import java.io.File
import android.Manifest.permission as AndroidPermissions
class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback {
@ -68,8 +70,7 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_REQUEST_PERMISSIONS) {
executeAfterFragmentResumed {
if (PermissionUtils.getPermission(permissions, grantResults, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& PermissionUtils.getPermission(permissions, grantResults, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (checkAllSelfPermissionsGranted(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
showPickFileDialog()
} else {
finishWithDeniedMessage()
@ -80,17 +81,15 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent = intent
val action = intent.action
if (INTENT_ACTION_PICK_FILE != action && INTENT_ACTION_PICK_DIRECTORY != action) {
finish()
return
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (checkAllSelfPermissionsGranted(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
showPickFileDialog()
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
val permissions = arrayOf(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions, REQUEST_REQUEST_PERMISSIONS)
} else {
finishWithDeniedMessage()
@ -104,19 +103,13 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback
}
private fun showPickFileDialog() {
val intent = intent
val data = intent.data
val action = intent.action
var initialDirectory: File? = if (data != null) File(data.path) else getExternalStorageDirectory()
if (initialDirectory == null) {
initialDirectory = File("/")
}
val initialDirectory = intent?.data?.path?.convert(::File) ?: getExternalStorageDirectory() ?: File("/")
val f = FileSelectorDialogFragment()
val args = Bundle()
args.putString(EXTRA_ACTION, action)
args.putString(EXTRA_PATH, initialDirectory.absolutePath)
args.putStringArray(EXTRA_FILE_EXTENSIONS, intent.getStringArrayExtra(EXTRA_FILE_EXTENSIONS))
f.arguments = args
f.arguments = Bundle {
this[EXTRA_ACTION] = intent.action
this[EXTRA_PATH] = initialDirectory.absolutePath
this[EXTRA_FILE_EXTENSIONS] = intent.getStringArrayExtra(EXTRA_FILE_EXTENSIONS)
}
f.show(supportFragmentManager, "select_file")
}

View File

@ -16,7 +16,6 @@
package org.mariotaku.twidere.activity
import android.Manifest
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Intent
@ -24,7 +23,10 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.support.v4.app.*
import android.support.v4.app.DialogFragment
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.hasRunningLoadersSafe
import android.support.v4.view.ViewPager
import android.support.v7.widget.Toolbar
import android.view.Menu
@ -33,6 +35,7 @@ import android.widget.Toast
import com.afollestad.appthemeengine.Config
import com.afollestad.appthemeengine.customizers.ATEToolbarCustomizer
import kotlinx.android.synthetic.main.activity_media_viewer.*
import org.mariotaku.ktextension.checkAllSelfPermissionsGranted
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.mediaviewer.library.*
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment.EXTRA_MEDIA_URI
@ -53,6 +56,7 @@ import org.mariotaku.twidere.util.PermissionUtils
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import java.io.File
import javax.inject.Inject
import android.Manifest.permission as AndroidPermissions
class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomizer, IMediaViewerActivity {
@ -62,7 +66,7 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
lateinit var mMediaDownloader: MediaDownloader
private var saveToStoragePosition = -1
private var mShareMediaPosition = -1
private var shareMediaPosition = -1
private var mHelper: IMediaViewerActivity.Helper? = null
@ -171,7 +175,7 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
REQUEST_PERMISSION_SAVE_MEDIA -> {
if (PermissionUtils.hasPermission(permissions, grantResults, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (PermissionUtils.hasPermission(permissions, grantResults, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
saveToStorage()
} else {
Toast.makeText(this, R.string.save_media_no_storage_permission_message, Toast.LENGTH_LONG).show()
@ -179,7 +183,7 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
return
}
REQUEST_PERMISSION_SHARE_MEDIA -> {
if (!PermissionUtils.hasPermission(permissions, grantResults, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (!PermissionUtils.hasPermission(permissions, grantResults, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, R.string.share_media_no_storage_permission_message, Toast.LENGTH_LONG).show()
}
shareMedia()
@ -295,44 +299,42 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
private fun requestAndSaveToStorage(position: Int) {
saveToStoragePosition = position
if (PermissionUtils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
saveToStorage()
} else {
val permissions: Array<String>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
} else {
permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
}
ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_SAVE_MEDIA)
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_save_media),
permissions, REQUEST_PERMISSION_SAVE_MEDIA)
}
}
private fun requestAndShareMedia(position: Int) {
mShareMediaPosition = position
if (PermissionUtils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
shareMediaPosition = position
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
shareMedia()
} else {
val permissions: Array<String>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
} else {
permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
}
ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_SHARE_MEDIA)
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_share_media),
permissions, REQUEST_PERMISSION_SHARE_MEDIA)
}
}
private fun shareMedia() {
if (mShareMediaPosition == -1) return
if (shareMediaPosition == -1) return
val viewPager = findViewPager()
val adapter = viewPager.adapter
val f = adapter.instantiateItem(viewPager, mShareMediaPosition) as? CacheDownloadMediaViewerFragment ?: return
val result = f.downloadResult
if (result == null || result.cacheUri == null) {
// TODO show error
return
}
val f = adapter.instantiateItem(viewPager, shareMediaPosition) as? CacheDownloadMediaViewerFragment ?: return
val cacheUri = f.downloadResult?.cacheUri ?: return
val destination = ShareProvider.getFilesDir(this) ?: return
val type: String
when (f) {
@ -341,7 +343,7 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
is GifPageFragment -> type = CacheProvider.Type.IMAGE
else -> throw UnsupportedOperationException("Unsupported fragment $f")
}
val task = object : SaveFileTask(this@MediaViewerActivity, result.cacheUri!!, destination,
val task = object : SaveFileTask(this@MediaViewerActivity, cacheUri, destination,
CacheProvider.CacheFileTypeCallback(this@MediaViewerActivity, type)) {
private val PROGRESS_FRAGMENT_TAG = "progress"
@ -351,7 +353,6 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
val fm = (activity as FragmentActivity).supportFragmentManager
val fragment = fm.findFragmentByTag(PROGRESS_FRAGMENT_TAG) as? DialogFragment
fragment?.dismiss()
Unit
}
}
@ -361,7 +362,6 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
val fragment = ProgressDialogFragment()
fragment.isCancelable = false
fragment.show((activity as FragmentActivity).supportFragmentManager, PROGRESS_FRAGMENT_TAG)
Unit
}
}
@ -388,7 +388,7 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
Toast.makeText(activity, R.string.error_occurred, Toast.LENGTH_SHORT).show()
}
}
AsyncTaskUtils.executeTask<SaveFileTask, Any>(task)
AsyncTaskUtils.executeTask(task)
}
private fun saveToStorage() {

View File

@ -30,7 +30,6 @@ import android.os.AsyncTask
import android.os.Build
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.support.v4.view.ViewPager
import android.support.v7.app.AlertDialog
import android.support.v7.preference.Preference
import android.view.LayoutInflater
@ -39,6 +38,7 @@ import android.view.View.OnClickListener
import android.view.ViewGroup
import com.afollestad.appthemeengine.Config
import com.afollestad.appthemeengine.util.ATEUtil
import kotlinx.android.synthetic.main.activity_settings_wizard.*
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.SupportTabsAdapter
@ -48,6 +48,7 @@ import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.fragment.BasePreferenceFragment
import org.mariotaku.twidere.fragment.BaseSupportFragment
import org.mariotaku.twidere.fragment.ProgressDialogFragment
import org.mariotaku.twidere.fragment.wizard.WizardWelcomePageFragment
import org.mariotaku.twidere.model.Tab
import org.mariotaku.twidere.model.TabValuesCreator
import org.mariotaku.twidere.model.tab.TabConfiguration
@ -56,25 +57,21 @@ import org.mariotaku.twidere.preference.WizardPageNavPreference
import org.mariotaku.twidere.provider.TwidereDataStore.Tabs
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.content.ContentResolverUtils
import org.mariotaku.twidere.view.LinePageIndicator
class SettingsWizardActivity : BaseActivity() {
private var viewPager: ViewPager? = null
private var indicator: LinePageIndicator? = null
private var adapter: SupportTabsAdapter? = null
private lateinit var adapter: SupportTabsAdapter
private var task: AbsInitialSettingsTask? = null
fun applyInitialSettings() {
if (task != null && task!!.status == AsyncTask.Status.RUNNING) return
if (task?.status == AsyncTask.Status.RUNNING) return
task = InitialSettingsTask(this)
AsyncTaskUtils.executeTask<AbsInitialSettingsTask, Any>(task)
}
fun applyInitialTabSettings() {
if (task != null && task!!.status == AsyncTask.Status.RUNNING) return
if (task?.status == AsyncTask.Status.RUNNING) return
task = InitialTabSettingsTask(this)
AsyncTaskUtils.executeTask<AbsInitialSettingsTask, Any>(task)
}
@ -89,32 +86,23 @@ class SettingsWizardActivity : BaseActivity() {
}
fun gotoFinishPage() {
if (viewPager == null || adapter == null) return
val last = adapter!!.count - 1
viewPager!!.currentItem = Math.max(last, 0)
val last = adapter.count - 1
viewPager.currentItem = Math.max(last, 0)
}
fun gotoLastPage() {
if (viewPager == null || adapter == null) return
gotoPage(pageCount - 2)
}
fun gotoNextPage() {
if (viewPager == null || adapter == null) return
val current = viewPager!!.currentItem
viewPager!!.currentItem = TwidereMathUtils.clamp(current + 1, adapter!!.count - 1, 0)
val current = viewPager.currentItem
viewPager.currentItem = TwidereMathUtils.clamp(current + 1, adapter.count - 1, 0)
}
override fun onBackPressed() {
super.onBackPressed()
}
override fun onContentChanged() {
super.onContentChanged()
viewPager = findViewById(R.id.pager) as ViewPager
indicator = findViewById(R.id.indicator) as LinePageIndicator
}
override fun getStatusBarColor(): Int {
if (VALUE_THEME_NAME_DARK == ateKey) return Color.BLACK
return ATEUtil.darkenColor(ThemeUtils.getColorBackground(this))
@ -142,25 +130,25 @@ class SettingsWizardActivity : BaseActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings_wizard)
adapter = SupportTabsAdapter(this, supportFragmentManager, null)
viewPager!!.adapter = adapter
viewPager!!.isEnabled = false
indicator!!.setViewPager(viewPager)
indicator!!.selectedColor = Config.accentColor(this, ateKey)
viewPager.adapter = adapter
viewPager.isEnabled = false
indicator.setViewPager(viewPager)
indicator.selectedColor = Config.accentColor(this, ateKey)
initPages()
val initialPage = intent.getIntExtra(IntentConstants.EXTRA_PAGE, -1)
if (initialPage != -1) {
viewPager!!.setCurrentItem(initialPage, false)
viewPager.setCurrentItem(initialPage, false)
}
}
private fun initPages() {
adapter!!.addTab(cls = WizardPageWelcomeFragment::class.java, name = getString(R.string.wizard_page_welcome_title))
adapter!!.addTab(cls = WizardPageThemeFragment::class.java, name = getString(R.string.theme))
adapter!!.addTab(cls = WizardPageTabsFragment::class.java, name = getString(R.string.tabs))
adapter!!.addTab(cls = WizardPageCardsFragment::class.java, name = getString(R.string.cards))
adapter!!.addTab(cls = WizardPageUsageStatisticsFragment::class.java, name = getString(R.string.usage_statistics))
adapter!!.addTab(cls = WizardPageHintsFragment::class.java, name = getString(R.string.hints))
adapter!!.addTab(cls = WizardPageFinishedFragment::class.java, name = getString(R.string.wizard_page_finished_title))
adapter.addTab(cls = WizardWelcomePageFragment::class.java, name = getString(R.string.wizard_page_welcome_title))
adapter.addTab(cls = WizardPageThemeFragment::class.java, name = getString(R.string.theme))
adapter.addTab(cls = WizardPageTabsFragment::class.java, name = getString(R.string.tabs))
adapter.addTab(cls = WizardPageCardsFragment::class.java, name = getString(R.string.cards))
adapter.addTab(cls = WizardPageUsageStatisticsFragment::class.java, name = getString(R.string.usage_statistics))
adapter.addTab(cls = WizardPageHintsFragment::class.java, name = getString(R.string.hints))
adapter.addTab(cls = WizardPageFinishedFragment::class.java, name = getString(R.string.wizard_page_finished_title))
}
private fun openImportSettingsDialog() {
@ -248,7 +236,7 @@ class SettingsWizardActivity : BaseActivity() {
private fun restartWithCurrentPage() {
val intent = intent
intent.putExtra(EXTRA_PAGE, viewPager!!.currentItem)
intent.putExtra(EXTRA_PAGE, viewPager.currentItem)
setIntent(intent)
recreate()
}
@ -424,54 +412,6 @@ class SettingsWizardActivity : BaseActivity() {
get() = R.xml.preferences_theme
}
class WizardPageWelcomeFragment : BaseWizardPageFragment(), Preference.OnPreferenceClickListener {
fun applyInitialSettings() {
val a = activity
if (a is SettingsWizardActivity) {
a.applyInitialSettings()
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
findPreference(WIZARD_PREFERENCE_KEY_NEXT_PAGE).onPreferenceClickListener = this
findPreference(WIZARD_PREFERENCE_KEY_USE_DEFAULTS).onPreferenceClickListener = this
findPreference(WIZARD_PREFERENCE_KEY_IMPORT_SETTINGS).onPreferenceClickListener = this
}
override fun onPreferenceClick(preference: Preference): Boolean {
val key = preference.key
if (WIZARD_PREFERENCE_KEY_NEXT_PAGE == key) {
gotoNextPage()
} else if (WIZARD_PREFERENCE_KEY_USE_DEFAULTS == key) {
applyInitialSettings()
} else if (WIZARD_PREFERENCE_KEY_IMPORT_SETTINGS == key) {
openImportSettingsDialog()
}
return true
}
override val headerSummary: Int
get() = R.string.wizard_page_welcome_text
override val headerTitle: Int
get() = R.string.wizard_page_welcome_title
override val nextPageTitle: Int
get() = 0
override val preferenceResource: Int
get() = R.xml.settings_wizard_page_welcome
private fun openImportSettingsDialog() {
val a = activity
if (a is SettingsWizardActivity) {
a.openImportSettingsDialog()
}
}
}
internal abstract class AbsInitialSettingsTask(protected val activity: SettingsWizardActivity) : AsyncTask<Any, Any, Boolean>() {
override fun doInBackground(vararg params: Any): Boolean {
@ -544,11 +484,11 @@ class SettingsWizardActivity : BaseActivity() {
}
private fun gotoPage(page: Int) {
viewPager!!.currentItem = TwidereMathUtils.clamp(page, 0, pageCount - 1)
viewPager.currentItem = TwidereMathUtils.clamp(page, 0, pageCount - 1)
}
private val pageCount: Int
get() = adapter!!.count
get() = adapter.count
internal class InitialTabSettingsTask(activity: SettingsWizardActivity) : AbsInitialSettingsTask(activity) {

View File

@ -4,8 +4,9 @@ import android.content.SharedPreferences
import android.os.Build
import android.text.TextUtils
import org.mariotaku.kpreferences.*
import org.mariotaku.twidere.Constants.KEY_NO_CLOSE_AFTER_TWEET_SENT
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_CREDENTIALS_TYPE
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_ATTACH_PRECISE_LOCATION
import org.mariotaku.twidere.extension.getNonEmptyString
import org.mariotaku.twidere.model.CustomAPIConfig
import org.mariotaku.twidere.model.account.cred.Credentials
@ -29,6 +30,9 @@ val linkHighlightOptionKey = KStringKey(KEY_LINK_HIGHLIGHT_OPTION, VALUE_LINK_HI
val statusShortenerKey = KNullableStringKey(KEY_STATUS_SHORTENER, null)
val mediaUploaderKey = KNullableStringKey(KEY_MEDIA_UPLOADER, null)
val newDocumentApiKey = KBooleanKey(KEY_NEW_DOCUMENT_API, Build.VERSION.SDK_INT == Build.VERSION_CODES.M)
val attachLocationKey = KBooleanKey(KEY_ATTACH_LOCATION, false)
val attachPreciseLocationKey = KBooleanKey(KEY_ATTACH_PRECISE_LOCATION, false)
val noCloseAfterTweetSentKey = KBooleanKey(KEY_NO_CLOSE_AFTER_TWEET_SENT, false)
val loadItemLimitKey = KIntKey(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT)
val defaultFeatureLastUpdated = KLongKey("default_feature_last_updated", -1)

View File

@ -0,0 +1,52 @@
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_MESSAGE
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_PERMISSIONS
/**
* Created by mariotaku on 2016/12/13.
*/
class PermissionRequestDialog : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
val permissions = arguments.getStringArray(EXTRA_PERMISSIONS)
val requestCode = arguments.getInt(EXTRA_REQUEST_CODE)
builder.setMessage(arguments.getString(EXTRA_MESSAGE))
builder.setPositiveButton(android.R.string.ok) { dialog, which ->
ActivityCompat.requestPermissions(activity, permissions, requestCode)
}
builder.setNegativeButton(R.string.action_later) { dialog, which ->
val callback = parentFragment as? PermissionRequestCancelCallback ?: activity as?
PermissionRequestCancelCallback ?: return@setNegativeButton
callback.onPermissionRequestCancelled(requestCode)
}
return builder.create()
}
interface PermissionRequestCancelCallback {
fun onPermissionRequestCancelled(requestCode: Int)
}
companion object {
const val EXTRA_REQUEST_CODE = "request_code"
fun show(fragmentManager: FragmentManager, message: String, permissions: Array<String>, requestCode: Int): PermissionRequestDialog {
val df = PermissionRequestDialog()
df.arguments = Bundle {
this[EXTRA_MESSAGE] = message
this[EXTRA_PERMISSIONS] = permissions
this[EXTRA_REQUEST_CODE] = requestCode
}
df.show(fragmentManager, "request_permission_message")
return df
}
}
}

View File

@ -0,0 +1,18 @@
package org.mariotaku.twidere.fragment.wizard
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.mariotaku.twidere.R
import org.mariotaku.twidere.fragment.BaseSupportFragment
/**
* Created by mariotaku on 2016/12/13.
*/
class WizardWelcomePageFragment : BaseSupportFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_wizard_page_welcome, container, false)
}
}

View File

@ -24,7 +24,7 @@
tools:context=".activity.SettingsWizardActivity">
<org.mariotaku.twidere.view.ExtendedViewPager
android:id="@+id/pager"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
@ -37,4 +37,9 @@
app:lineWidth="@dimen/line_indicator_line_width_wizard"
app:strokeWidth="@dimen/line_indicator_stroke_width_wizard"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:text="@string/action_skip"/>
</merge>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</RelativeLayout>

View File

@ -826,4 +826,11 @@
<string name="filter_everywhere">Filter everywhere</string>
<string name="filter_everywhere_description">These will be filtered in Twidere:\n &#xb7;User\'s tweets\n &#xb7;Tweets mentioning this user\n &#xb7;Retweets/Quotes of this user</string>
<string name="message_toast_added_to_filter">Added to filter.</string>
<!-- Verb. Used for skip some settings -->
<string name="action_skip">Skip</string>
<!-- Used for decide something later, like permission request -->
<string name="action_later">Later</string>
<string name="message_permission_request_compose_location">Twidere needs location permission for adding location to tweets.</string>
<string name="message_permission_request_save_media">Twidere needs storage permission for saving media.</string>
<string name="message_permission_request_share_media">Twidere needs storage permission for sharing media to some apps.</string>
</resources>