Skip to content

Commit

Permalink
Issue #308 sdcard problems might be fixable now
Browse files Browse the repository at this point in the history
If two ExternalFilesDirs are available, the non-removable is going to be
used now. Also, if setting a download directory in the preferences
screen fails, a fallback directory will be suggested.
  • Loading branch information
yeriomin committed Jan 8, 2018
1 parent caf6fb9 commit f3d7b5d
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public boolean onContextItemSelected(MenuItem item) {

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (isGranted(requestCode, permissions, grantResults)) {
if (YalpStorePermissionManager.isGranted(requestCode, permissions, grantResults)) {
Log.i(getClass().getSimpleName(), "User granted the write permission");
new ButtonDownload(this, DetailsActivity.app).download();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@

public class DebugHttpClientAdapter extends NativeHttpClientAdapter {

static private final String DEBUG_DIRECTORY = "yalp-store-debug";
static private File dumpDirectory;

public DebugHttpClientAdapter() {
dumpDirectory = Environment.getExternalStorageDirectory();
dumpDirectory = new File(Environment.getExternalStorageDirectory(), DEBUG_DIRECTORY);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ protected void onCreate(Bundle savedInstanceState) {

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (isGranted(requestCode, permissions, grantResults)) {
if (YalpStorePermissionManager.isGranted(requestCode, permissions, grantResults)) {
Log.i(getClass().getSimpleName(), "User granted the write permission");
if (null == downloadOrInstallFragment && null != app) {
downloadOrInstallFragment = new DownloadOrInstall(this, app);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ protected void onCreate(Bundle savedInstanceState) {
finish();
return;
}
if (!checkPermission()) {
if (!new YalpStorePermissionManager(this).checkPermission()) {
startActivity(DetailsActivity.getDetailsIntent(this, packageName));
finish();
return;
Expand Down
29 changes: 28 additions & 1 deletion app/src/main/java/com/github/yeriomin/yalpstore/Paths.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
package com.github.yeriomin.yalpstore;

import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.preference.PreferenceManager;

import java.io.File;

public class Paths {

static public final String FALLBACK_DIRECTORY = "Android/data/" + BuildConfig.APPLICATION_ID + "/files";

static public File getStorageRoot(Context context) {
File storageRoot = Environment.getExternalStorageDirectory();
File[] externalFilesDirs = getExternalFilesDirs(context);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
|| externalFilesDirs.length < 2
|| (Environment.isExternalStorageEmulated(storageRoot) && !Environment.isExternalStorageRemovable(storageRoot))
) {
return storageRoot;
}
for (File file: externalFilesDirs) {
if (Environment.isExternalStorageEmulated(file) && !Environment.isExternalStorageRemovable(file)) {
return new File(file.getAbsolutePath().replace(FALLBACK_DIRECTORY, ""));
}
}
return storageRoot;
}

static public File getYalpPath(Context context) {
return new File(
Environment.getExternalStorageDirectory(),
getStorageRoot(context),
PreferenceManager.getDefaultSharedPreferences(context).getString(PreferenceActivity.PREFERENCE_DOWNLOAD_DIRECTORY, "")
);
}
Expand All @@ -29,4 +49,11 @@ static public File getObbPath(String packageName, int version, boolean main) {
String filename = (main ? "main" : "patch") + "." + String.valueOf(version) + "." + packageName + ".obb";
return new File(obbDir, filename);
}

static private File[] getExternalFilesDirs(Context context) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
? context.getExternalFilesDirs(null)
: new File[] {new File(Environment.getExternalStorageDirectory(), FALLBACK_DIRECTORY)}
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.PreferenceManager;
import android.util.Log;

import com.github.yeriomin.yalpstore.fragment.preference.Blacklist;
import com.github.yeriomin.yalpstore.fragment.preference.CheckUpdates;
Expand Down Expand Up @@ -84,6 +85,14 @@ public void onCreate(Bundle savedInstanceState) {
new DownloadDirectory(this).setPreference((EditTextPreference) findPreference(PREFERENCE_DOWNLOAD_DIRECTORY)).draw();
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (!YalpStorePermissionManager.isGranted(requestCode, permissions, grantResults)) {
Log.i(getClass().getSimpleName(), "User denied the write permission");
finish();
}
}

private void drawBlackList() {
Blacklist blacklistFragment = new Blacklist(this);
blacklistFragment.setBlackOrWhite((ListPreference) findPreference(PREFERENCE_UPDATE_LIST_WHITE_OR_BLACK));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void loadApps() {

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (isGranted(requestCode, permissions, grantResults)) {
if (YalpStorePermissionManager.isGranted(requestCode, permissions, grantResults)) {
Log.i(getClass().getSimpleName(), "User granted the write permission");
launchUpdateAll();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.github.yeriomin.yalpstore;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
Expand All @@ -9,7 +8,6 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
Expand All @@ -26,8 +24,6 @@

public abstract class YalpStoreActivity extends Activity {

private static final int PERMISSIONS_REQUEST_CODE = 384;

static protected boolean logout = false;

public static void cascadeFinish() {
Expand Down Expand Up @@ -136,31 +132,6 @@ public void unregisterReceiver(BroadcastReceiver receiver) {
}
}

protected boolean isGranted(int requestCode, String permissions[], int[] grantResults) {
return requestCode == PERMISSIONS_REQUEST_CODE
&& grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
;
}

public boolean checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(getClass().getSimpleName(), "Checking if write permission is granted");
return checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
return true;
}

public void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(getClass().getSimpleName(), "Requesting the write permission");
requestPermissions(
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
PERMISSIONS_REQUEST_CODE
);
}
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void addQueryTextListener(MenuItem searchItem) {
SearchView searchView = (SearchView) searchItem.getActionView();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.github.yeriomin.yalpstore;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import java.lang.ref.WeakReference;

public class YalpStorePermissionManager {

private static final int PERMISSIONS_REQUEST_CODE = 384;

private WeakReference<Activity> activityRef = new WeakReference<>(null);

public YalpStorePermissionManager(Activity activity) {
this.activityRef = new WeakReference<>(activity);
}

static public boolean isGranted(int requestCode, String permissions[], int[] grantResults) {
return requestCode == PERMISSIONS_REQUEST_CODE
&& grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
;
}

public boolean checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && null != activityRef.get()) {
Log.i(getClass().getSimpleName(), "Checking if write permission is granted");
return activityRef.get().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
return true;
}

public void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && null != activityRef.get()) {
Log.i(getClass().getSimpleName(), "Requesting the write permission");
activityRef.get().requestPermissions(
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
PERMISSIONS_REQUEST_CODE
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.github.yeriomin.yalpstore.Paths;
import com.github.yeriomin.yalpstore.R;
import com.github.yeriomin.yalpstore.YalpStoreActivity;
import com.github.yeriomin.yalpstore.YalpStorePermissionManager;
import com.github.yeriomin.yalpstore.model.App;
import com.github.yeriomin.yalpstore.selfupdate.UpdaterFactory;
import com.github.yeriomin.yalpstore.task.playstore.PurchaseTask;
Expand Down Expand Up @@ -52,17 +53,18 @@ protected void onButtonClick(View v) {
}

public void checkAndDownload() {
YalpStorePermissionManager permissionManager = new YalpStorePermissionManager(activity);
if (app.getVersionCode() == 0 && !(activity instanceof ManualDownloadActivity)) {
activity.startActivity(new Intent(activity, ManualDownloadActivity.class));
} else if (activity.checkPermission()) {
} else if (permissionManager.checkPermission()) {
Log.i(getClass().getSimpleName(), "Write permission granted");
download();
View buttonCancel = activity.findViewById(R.id.cancel);
if (null != buttonCancel) {
buttonCancel.setVisibility(View.VISIBLE);
}
} else {
activity.requestPermission();
permissionManager.requestPermission();
}
}

Expand All @@ -88,7 +90,7 @@ public void download() {
AndroidAppDeliveryData.newBuilder().setDownloadUrl(UpdaterFactory.get(activity).getUrlString(app.getVersionCode())).build()
);
} else {
boolean writePermission = activity.checkPermission();
boolean writePermission = new YalpStorePermissionManager(activity).checkPermission();
Log.i(getClass().getSimpleName(), "Write permission granted - " + writePermission);
if (writePermission && prepareDownloadsDir()) {
getPurchaseTask().execute();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.github.yeriomin.yalpstore.fragment.preference;

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.util.Log;
Expand All @@ -11,6 +12,7 @@
import com.github.yeriomin.yalpstore.Paths;
import com.github.yeriomin.yalpstore.PreferenceActivity;
import com.github.yeriomin.yalpstore.R;
import com.github.yeriomin.yalpstore.YalpStorePermissionManager;

import java.io.File;
import java.io.IOException;
Expand All @@ -27,16 +29,30 @@ public DownloadDirectory setPreference(EditTextPreference preference) {
@Override
public void draw() {
preference.setSummary(Paths.getYalpPath(activity).getAbsolutePath());
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
YalpStorePermissionManager permissionManager = new YalpStorePermissionManager(activity);
if (!permissionManager.checkPermission()) {
permissionManager.requestPermission();
}
return true;
}
});
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
String newValue = (String) o;
boolean result = checkNewValue(newValue);
if (!result) {
ContextUtil.toast(activity, R.string.error_downloads_directory_not_writable);
if (ContextUtil.isAlive(activity) && !((EditTextPreference) preference).getText().equals(Paths.FALLBACK_DIRECTORY)) {
getFallbackDialog().show();
} else {
ContextUtil.toast(activity, R.string.error_downloads_directory_not_writable);
}
} else {
try {
preference.setSummary(new File(Environment.getExternalStorageDirectory(), newValue).getCanonicalPath());
preference.setSummary(new File(Paths.getStorageRoot(activity), newValue).getCanonicalPath());
} catch (IOException e) {
Log.i(getClass().getName(), "checkNewValue returned true, but drawing the path \"" + newValue + "\" in the summary failed... strange");
return false;
Expand All @@ -47,12 +63,13 @@ public boolean onPreferenceChange(Preference preference, Object o) {

private boolean checkNewValue(String newValue) {
try {
File newDir = new File(Environment.getExternalStorageDirectory(), newValue).getCanonicalFile();
if (!newDir.getCanonicalPath().startsWith(Environment.getExternalStorageDirectory().getCanonicalPath())) {
File storageRoot = Paths.getStorageRoot(activity);
File newDir = new File(storageRoot, newValue).getCanonicalFile();
if (!newDir.getCanonicalPath().startsWith(storageRoot.getCanonicalPath())) {
return false;
}
if (newDir.exists()) {
return true;
return newDir.canWrite();
}
if (activity.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
return newDir.mkdirs();
Expand All @@ -62,6 +79,31 @@ private boolean checkNewValue(String newValue) {
return false;
}
}

private AlertDialog getFallbackDialog() {
return new AlertDialog.Builder(activity)
.setMessage(
activity.getString(R.string.error_downloads_directory_not_writable)
+ "\n\n"
+ activity.getString(R.string.pref_message_fallback, Paths.FALLBACK_DIRECTORY)
)
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
preference.setText(Paths.FALLBACK_DIRECTORY);
preference.getOnPreferenceChangeListener().onPreferenceChange(preference, Paths.FALLBACK_DIRECTORY);
dialog.dismiss();
}
})
.create()
;
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import com.github.yeriomin.yalpstore.ContextUtil;
import com.github.yeriomin.yalpstore.R;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.github.yeriomin.yalpstore.R;
import com.github.yeriomin.yalpstore.UpdatableAppsActivity;
import com.github.yeriomin.yalpstore.YalpStoreApplication;
import com.github.yeriomin.yalpstore.YalpStorePermissionManager;
import com.github.yeriomin.yalpstore.model.App;
import com.github.yeriomin.yalpstore.selfupdate.UpdaterFactory;
import com.github.yeriomin.yalpstore.task.InstalledAppsTask;
Expand Down Expand Up @@ -80,10 +81,11 @@ private void toggleUpdateAll(boolean enable) {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (activity.checkPermission()) {
YalpStorePermissionManager permissionManager = new YalpStorePermissionManager(activity);
if (permissionManager.checkPermission()) {
activity.launchUpdateAll();
} else {
activity.requestPermission();
permissionManager.requestPermission();
}
}
});
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,5 @@
<string name="flagging_title">Пожаловаться</string>
<string name="content_flagged">Возражение отправлено.</string>
<string name="apps_by">"Приложения от %1$s"</string>
<string name="pref_message_fallback">Использовать резервную директорию (%1$s)?</string>
</resources>
Loading

0 comments on commit f3d7b5d

Please sign in to comment.