Skip to content

Commit

Permalink
Implement Android 6.0 runtime permissions
Browse files Browse the repository at this point in the history
Reorder and comment permissions

Runtime permission WIP

Show permission error message

Simplify

Calendar permissions

Handle service notification

request account manager permission

Remove debug

Default to light

SDK 10 fixes

Bump version
  • Loading branch information
jberkel committed Jan 22, 2018
1 parent 68fec9a commit 7236562
Show file tree
Hide file tree
Showing 35 changed files with 602 additions and 216 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
== 1.5.11 (1555) tbd

* Implemented runtime permissions for Android 6.0+
* Added dark/light theme switcher
* Modernized UI (Material/AppCompat)
* Simplify IMAP search logic to prevent timeouts
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ android {
applicationId "com.zegoggles.smssync"
minSdkVersion 9
targetSdkVersion 25
versionCode 1563
versionName "1.5.11-beta10"
versionCode 1564
versionName "1.5.11-beta11"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

Expand Down
72 changes: 59 additions & 13 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,74 @@
package="com.zegoggles.smssync"
android:description="@string/app_description">

<!-- “dangerous” permissions -->

<!-- android.permission-group.MESSAGES -->
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.INTERNET"/>

<!-- Allows the app to receive and process SMS messages. This means the app could monitor or delete
messages sent to your device without showing them to you. -->
<!-- android.permission-group.MESSAGES -->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>

<!-- android.permission-group.SOCIAL_INFO -->
<!-- introduced in API level 16 (Jelly Bean), previously part of READ_CONTACTS -->
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>

<!-- android.permission-group.SOCIAL_INFO -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<!--
http://stackoverflow.com/questions/11289568/monitoring-mms-received-like-sms-received-on-android
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
-->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<!-- android.permission-group.PERSONAL_INFO -->
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>

<!-- Allows the app to get the list of accounts known by the phone. This may include any accounts
created by applications you have installed. -->
<!-- android.permission-group.ACCOUNTS -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>

<!-- Allows the app to request authentication tokens. Removed in Android 6 -->
<!-- android.permission-group.ACCOUNTS -->
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>

<!-- Allows the app to write to the SD card. -->
<!-- android.permission-group.STORAGE -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<!-- Allows the app to create network sockets and use custom network protocols. The browser and
other applications provide means to send data to the internet, so this permission is not
required to send data to the internet. -->
<!-- android.permission-group.NETWORK -->
<uses-permission android:name="android.permission.INTERNET"/>

<!-- Allows the app to view information about network connections such as which networks
exist and are connected. -->
<!-- android.permission-group.NETWORK -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<!-- Allows the app to view information about Wi-Fi networking, such as whether Wi-Fi is enabled
and name of connected Wi-Fi devices. -->
<!-- android.permission-group.NETWORK -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

<!-- Allows the app to prevent the phone from going to sleep. -->
<!-- android.permission-group.AFFECTS_BATTERY -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<!-- Allows the app to have itself started as soon as the system has finished booting.
This can make it take longer to start the phone and allow the app to slow down the overall phone
by always running. -->
<!-- android.permission-group.APP_INFO -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>

<!-- Allows the app to access the phone features of the device.
This permission allows the app to determine the phone number and device
IDs, whether a call is active, and the remote number connected by a call. -->
<!-- android.permission-group.PHONE_CALLS -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>

<uses-feature android:name="android.hardware.telephony" android:required="false"/>
<uses-feature android:name="android.hardware.wifi" android:required="false"/>
Expand All @@ -35,7 +81,7 @@
<application android:icon="@drawable/ic_sms_backup"
android:label="@string/app_name"
android:description="@string/app_description"
android:theme="@style/SMSBackupPlusTheme.Dark"
android:theme="@style/SMSBackupPlusTheme.Light"
android:name="App"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_descriptor">
Expand Down
1 change: 1 addition & 0 deletions app/src/main/assets/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ <h2 style="margin-bottom: -14px">

<h3>New in this release:</h3>
<ul>
<li>Runtime permissions on Android 6.0+. It is recommended to run a manual backup after upgrade.</li>
<li>Improved backup schedule reliability (thanks <a href="https://github.com/MadsAndreasen">Mads Andreasen<a> for initial JobManager implementation)</li>
<li>Replaced WebView auth with browser</li>
<li>Improved restore experience (thanks <a href="https://github.com/angryziber">Anton Keks/angryziber</a>)</li>
Expand Down
7 changes: 0 additions & 7 deletions app/src/main/java/com/zegoggles/smssync/Consts.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@
public final class Consts {
private Consts() {}

/**
* Key in the intent extras for indication whether all unsynced messages should
* be skipped or not.
*/
public static final String KEY_SKIP_MESSAGES = "com.zegoggles.smssync.SkipMessages";


/** {@link android.provider.Telephony.Mms#CONTENT_URI} */
public static final Uri MMS_PROVIDER = Uri.parse("content://mms");
public static final String MMS_PART = "part";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.zegoggles.smssync.activity;

import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.zegoggles.smssync.R;

import java.util.ArrayList;
import java.util.List;

import static android.content.pm.PackageManager.PERMISSION_DENIED;

public enum AppPermission {
READ_SMS(Manifest.permission.READ_SMS, R.string.permission_read_sms),
READ_CALL_LOG(Manifest.permission.READ_CALL_LOG, R.string.permission_read_call_log),
READ_CONTACTS(Manifest.permission.READ_CONTACTS, R.string.permission_read_contacts),
UNKNOWN(null, R.string.permission_unknown);

final int descriptionResource;
final @Nullable String androidPermission;

AppPermission(String androidPermission, int descriptionResource) {
this.androidPermission = androidPermission;
this.descriptionResource = descriptionResource;
}

@Override
public String toString() {
return "AppPermission{" + androidPermission + '}';
}

public static AppPermission from(@NonNull String androidPermission) {
for (AppPermission appPermission : AppPermission.values()) {
if (androidPermission.equals(appPermission.androidPermission)) {
return appPermission;
}
}
return UNKNOWN;
}

public static List<AppPermission> from(@NonNull String[] androidPermissions) {
List<AppPermission> appPermissions = new ArrayList<AppPermission>();
for (String permission : androidPermissions) {
appPermissions.add(from(permission));
}
return appPermissions;
}

public static List<AppPermission> from(@NonNull String[] androidPermissions, @NonNull int[] grantResults) {
List<AppPermission> appPermissions = new ArrayList<AppPermission>();
for (int i=0; i<androidPermissions.length; i++) {
if (grantResults[i] == PERMISSION_DENIED) {
appPermissions.add(from(androidPermissions[i]));
}
}
return appPermissions;
}

public static boolean allGranted(@NonNull int[] grantResults) {
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_DENIED) {
return false;
}
}
return true;
}

public static String formatMissingPermissionDetails(Resources resources, String[] androidPermissions) {
return formatMissingPermissionDetails(resources, from(androidPermissions));
}

public static String formatMissingPermissionDetails(Resources resources, List<AppPermission> appPermissions) {
List<String> permissions = new ArrayList<String>();
for (AppPermission permission : appPermissions) {
permissions.add(resources.getString(permission.descriptionResource));
}
return resources.getQuantityString(R.plurals.status_permission_problem_details,
permissions.size(),
TextUtils.join(", ", permissions));
}
}
8 changes: 4 additions & 4 deletions app/src/main/java/com/zegoggles/smssync/activity/Dialogs.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
package com.zegoggles.smssync.activity;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
Expand Down Expand Up @@ -52,6 +50,8 @@
import static android.R.string.yes;
import static android.app.ProgressDialog.STYLE_SPINNER;
import static android.content.DialogInterface.BUTTON_NEGATIVE;
import static com.zegoggles.smssync.activity.MainActivity.REQUEST_CHANGE_DEFAULT_SMS_PACKAGE;
import static com.zegoggles.smssync.activity.MainActivity.REQUEST_WEB_AUTH;
import static com.zegoggles.smssync.activity.events.PerformAction.Actions.Backup;
import static com.zegoggles.smssync.activity.events.PerformAction.Actions.BackupSkip;

Expand Down Expand Up @@ -204,6 +204,8 @@ public void onClick(DialogInterface dialog, int which) {
public static class AccessTokenProgress extends BaseFragment {
@Override @NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
// NB: progress dialog is not AppCompat-ready, and will not appear themed
// correctly on older devices
ProgressDialog progress = new ProgressDialog(getContext());
progress.setTitle(null);
progress.setProgressStyle(STYLE_SPINNER);
Expand Down Expand Up @@ -259,7 +261,6 @@ public void onClick(DialogInterface dialog, int which) {
}

public static class WebConnect extends BaseFragment {
static final int REQUEST_WEB_AUTH = 3;
static final String INTENT = "intent";

@Override @NonNull
Expand Down Expand Up @@ -313,7 +314,6 @@ public void onClick(DialogInterface dialog, int which) {
}

public static class SmsDefaultPackage extends BaseFragment {
static final int REQUEST_CHANGE_DEFAULT_SMS_PACKAGE = 1;
static final String INTENT = "intent";

@Override @NonNull
Expand Down
Loading

0 comments on commit 7236562

Please sign in to comment.