list = locationManager.getProviders(true);
253 |
254 | if (list.contains(LocationManager.GPS_PROVIDER)) {
255 | return true;
256 | } else if (list.contains(LocationManager.NETWORK_PROVIDER)) {
257 | return true;
258 | } else {
259 | if (!locationManager.isProviderEnabled("gps")) {
260 | locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0L, 0F, new
261 | LocationListener() {
262 | @Override
263 | public void onLocationChanged(Location location) {
264 | locationManager.removeUpdates(this);
265 | }
266 |
267 | @Override
268 | public void onStatusChanged(String provider, int status, Bundle extras) {
269 | locationManager.removeUpdates(this);
270 | granted = true;
271 | }
272 |
273 | @Override
274 | public void onProviderEnabled(String provider) {
275 | locationManager.removeUpdates(this);
276 | }
277 |
278 | @Override
279 | public void onProviderDisabled(String provider) {
280 | locationManager.removeUpdates(this);
281 | }
282 | });
283 | }
284 | return granted;
285 | }
286 | }
287 |
288 | /**
289 | * use sensors, {@link android.Manifest.permission#BODY_SENSORS}
290 | *
291 | * @param activity
292 | * @return true if success
293 | * @throws Exception
294 | */
295 | private static boolean checkBodySensors(Activity activity) throws Exception {
296 | SensorManager sensorManager = (SensorManager) activity.getSystemService(SENSOR_SERVICE);
297 | Sensor sensor = sensorManager.getDefaultSensor((Sensor.TYPE_ACCELEROMETER));
298 | SensorEventListener listener = new SensorEventListener() {
299 | @Override
300 | public void onSensorChanged(SensorEvent event) {
301 | }
302 |
303 | @Override
304 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
305 | }
306 | };
307 | sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
308 | sensorManager.unregisterListener(listener, sensor);
309 |
310 | return true;
311 | }
312 |
313 | /**
314 | * read phone state, {@link android.Manifest.permission#READ_PHONE_STATE}
315 | *
316 | * in {@link com.joker.api.support.manufacturer.XIAOMI} or
317 | * {@link com.joker.api.support.manufacturer.OPPO} :
318 | * -> {@link TelephonyManager#getDeviceId()} will be null if deny permission
319 | *
320 | * in {@link com.joker.api.support.manufacturer.MEIZU} :
321 | * -> {@link TelephonyManager#getSubscriberId()} will be null if deny permission
322 | *
323 | * @param activity
324 | * @return true if success
325 | * @throws Exception
326 | */
327 | @SuppressLint("HardwareIds")
328 | private static boolean checkReadPhoneState(Activity activity) throws Exception {
329 | TelephonyManager service = (TelephonyManager) activity.getSystemService
330 | (TELEPHONY_SERVICE);
331 | if (PermissionsPageManager.isMEIZU()) {
332 | return !TextUtils.isEmpty(service.getSubscriberId());
333 | } else if (PermissionsPageManager.isXIAOMI() || PermissionsPageManager.isOPPO()) {
334 | return !TextUtils.isEmpty(service.getDeviceId());
335 | } else {
336 | return !TextUtils.isEmpty(service.getDeviceId()) || !TextUtils.isEmpty(service
337 | .getSubscriberId());
338 | }
339 | }
340 |
341 | /**
342 | * read call log, {@link android.Manifest.permission#READ_CALL_LOG}
343 | *
344 | * @param activity
345 | * @return true if success
346 | * @throws Exception
347 | */
348 | private static boolean checkReadCallLog(Activity activity) throws Exception {
349 | Cursor cursor = activity.getContentResolver().query(Uri.parse
350 | ("content://call_log/calls"), null, null,
351 | null, null);
352 | if (cursor != null) {
353 | if (ManufacturerSupportUtil.isForceManufacturer()) {
354 | if (isNumberIndexInfoIsNull(cursor, cursor.getColumnIndex(CallLog.Calls.NUMBER))) {
355 | cursor.close();
356 | return false;
357 | }
358 | }
359 | cursor.close();
360 | return true;
361 | } else {
362 | return false;
363 | }
364 | }
365 |
366 | /**
367 | * write and delete contacts info, {@link android.Manifest.permission#WRITE_CONTACTS}
368 | * and we should get read contacts permission first.
369 | *
370 | * @param activity
371 | * @return true if success
372 | * @throws Exception
373 | */
374 | private static boolean checkWriteContacts(Activity activity) throws Exception {
375 | if (checkReadContacts(activity)) {
376 | // write some info
377 | ContentValues values = new ContentValues();
378 | ContentResolver contentResolver = activity.getContentResolver();
379 | Uri rawContactUri = contentResolver.insert(ContactsContract.RawContacts
380 | .CONTENT_URI, values);
381 | long rawContactId = ContentUris.parseId(rawContactUri);
382 | values.put(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds
383 | .StructuredName.CONTENT_ITEM_TYPE);
384 | values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId);
385 | values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, TAG);
386 | values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, TAG_NUMBER);
387 | contentResolver.insert(ContactsContract.Data.CONTENT_URI, values);
388 |
389 | // delete info
390 | Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
391 | ContentResolver resolver = activity.getContentResolver();
392 | Cursor cursor = resolver.query(uri, new String[]{ContactsContract.Contacts.Data._ID},
393 | "display_name=?", new String[]{TAG}, null);
394 | if (cursor != null) {
395 | if (cursor.moveToFirst()) {
396 | int id = cursor.getInt(0);
397 | resolver.delete(uri, "display_name=?", new String[]{TAG});
398 | uri = Uri.parse("content://com.android.contacts/data");
399 | resolver.delete(uri, "raw_contact_id=?", new String[]{id + ""});
400 | }
401 | cursor.close();
402 | }
403 | return true;
404 | } else {
405 | return false;
406 | }
407 | }
408 |
409 | /**
410 | * read contacts, {@link android.Manifest.permission#READ_CONTACTS}
411 | *
412 | * @param activity
413 | * @return true if success
414 | * @throws Exception
415 | */
416 | private static boolean checkReadContacts(Activity activity) throws Exception {
417 | Cursor cursor = activity.getContentResolver().query(ContactsContract.CommonDataKinds.Phone
418 | .CONTENT_URI, null, null, null, null);
419 | if (cursor != null) {
420 | if (ManufacturerSupportUtil.isForceManufacturer()) {
421 | if (isNumberIndexInfoIsNull(cursor, cursor.getColumnIndex(ContactsContract.CommonDataKinds
422 | .Phone.NUMBER))) {
423 | cursor.close();
424 | return false;
425 | }
426 | }
427 | cursor.close();
428 | return true;
429 | } else {
430 | return false;
431 | }
432 | }
433 |
434 | /**
435 | * in {@link com.joker.api.support.manufacturer.XIAOMI}
436 | * 1.denied {@link android.Manifest.permission#READ_CONTACTS} permission
437 | * ---->cursor.getCount == 0
438 | * 2.granted {@link android.Manifest.permission#READ_CONTACTS} permission
439 | * ---->cursor.getCount return real count in contacts
440 | *
441 | * so when there are no user or permission denied, it will return 0
442 | *
443 | * @param cursor
444 | * @param numberIndex
445 | * @return true if can not get info
446 | */
447 | private static boolean isNumberIndexInfoIsNull(Cursor cursor, int numberIndex) {
448 | if (cursor.getCount() > 0) {
449 | while (cursor.moveToNext()) {
450 | return TextUtils.isEmpty(cursor.getString(numberIndex));
451 | }
452 | return false;
453 | } else {
454 | return true;
455 | }
456 | }
457 | }
458 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/apply/util/AudioRecordManager.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.apply.util;
2 |
3 | import android.media.AudioFormat;
4 | import android.media.AudioRecord;
5 | import android.media.MediaRecorder;
6 |
7 | import java.io.DataOutputStream;
8 | import java.io.File;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 |
12 | /**
13 | * Created by joker on 2017/8/17.
14 | */
15 |
16 | public class AudioRecordManager {
17 | public File file;
18 | private AudioRecord mRecorder;
19 | private DataOutputStream dos;
20 | private Thread recordThread;
21 | private boolean isStart = false;
22 | private int bufferSize;
23 | /**
24 | * record thread
25 | */
26 | Runnable recordRunnable = new Runnable() {
27 | @Override
28 | public void run() {
29 | try {
30 | android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
31 | int bytesRecord;
32 | byte[] tempBuffer = new byte[bufferSize];
33 | mRecorder.startRecording();
34 | while (isStart) {
35 | if (mRecorder != null) {
36 | bytesRecord = mRecorder.read(tempBuffer, 0, bufferSize);
37 | if (bytesRecord == AudioRecord.ERROR_INVALID_OPERATION || bytesRecord ==
38 | AudioRecord.ERROR_BAD_VALUE) {
39 | continue;
40 | }
41 | if (bytesRecord != 0 && bytesRecord != -1) {
42 | dos.write(tempBuffer, 0, bytesRecord);
43 | } else {
44 | break;
45 | }
46 | }
47 | }
48 | } catch (Exception e) {
49 | e.printStackTrace();
50 | }
51 | }
52 |
53 | };
54 | private long length;
55 |
56 | public AudioRecordManager() {
57 | bufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat
58 | .ENCODING_PCM_16BIT);
59 | mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO,
60 | AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);
61 | }
62 |
63 | public boolean getSuccess() {
64 | return length > 0;
65 | }
66 |
67 | /**
68 | * destroy record thread
69 | */
70 | private void destroyThread() {
71 | try {
72 | isStart = false;
73 | if (recordThread != null && recordThread.getState() != Thread.State.TERMINATED) {
74 | try {
75 | recordThread.interrupt();
76 | } catch (Exception e) {
77 | e.printStackTrace();
78 | recordThread = null;
79 | }
80 | }
81 | recordThread = null;
82 | } catch (Exception e) {
83 | e.printStackTrace();
84 | } finally {
85 | recordThread = null;
86 | }
87 | }
88 |
89 | /**
90 | * start record thread
91 | */
92 | private void startThread() {
93 | isStart = true;
94 | if (recordThread == null) {
95 | recordThread = new Thread(recordRunnable);
96 | recordThread.start();
97 | }
98 | }
99 |
100 | /**
101 | * save file
102 | *
103 | * @throws IOException
104 | */
105 | private void setPath(String path) throws IOException {
106 | file = new File(path);
107 | deleteFile();
108 | file.createNewFile();
109 | dos = new DataOutputStream(new FileOutputStream(file, true));
110 | }
111 |
112 | /**
113 | * start record
114 | *
115 | * @param path
116 | * @throws IOException
117 | */
118 | public void startRecord(String path) throws IOException, InterruptedException {
119 | setPath(path);
120 | startThread();
121 | }
122 |
123 | /**
124 | * stop record
125 | *
126 | * @throws IOException
127 | * @throws InterruptedException
128 | */
129 | public void stopRecord() throws IOException, InterruptedException {
130 | // specially for OPPO、XIAOMI、MEIZU、HUAWEI and so on
131 | Thread.sleep(250);
132 | destroyThread();
133 | if (mRecorder != null) {
134 | if (mRecorder.getState() == AudioRecord.STATE_INITIALIZED) {
135 | mRecorder.stop();
136 | }
137 | if (mRecorder != null) {
138 | mRecorder.release();
139 | }
140 | }
141 | if (dos != null) {
142 | dos.flush();
143 | dos.close();
144 | }
145 | length = file.length();
146 | deleteFile();
147 | }
148 |
149 | private void deleteFile() {
150 | if (file.exists()) {
151 | file.delete();
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/apply/util/SupportUtil.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.apply.util;
2 |
3 | import android.app.Activity;
4 | import android.support.v4.app.ActivityCompat;
5 |
6 | import com.joker.api.wrapper.PermissionWrapper;
7 |
8 | /**
9 | * Created by joker on 2017/8/19.
10 | */
11 |
12 | public class SupportUtil {
13 | public static boolean pageListenerNonNull(PermissionWrapper wrapper) {
14 | return wrapper.getPermissionPageListener() != null;
15 | }
16 |
17 | public static boolean nonShowRationale(PermissionWrapper wrapper) {
18 | return !ActivityCompat.shouldShowRequestPermissionRationale(getActivity(wrapper), wrapper.getRequestPermission());
19 | }
20 |
21 | private static Activity getActivity(PermissionWrapper wrapper) {
22 | Activity activity;
23 | if (wrapper.getContext() instanceof android.app.Fragment) {
24 | activity = ((android.app.Fragment) wrapper.getContext()).getActivity();
25 | } else if (wrapper.getContext() instanceof android.support.v4.app.Fragment) {
26 | activity = ((android.support.v4.app.Fragment) wrapper.getContext()).getActivity();
27 | } else {
28 | activity = (Activity) wrapper.getContext();
29 | }
30 |
31 | return activity;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/ManufacturerSupportUtil.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support;
2 |
3 | import android.os.Build;
4 |
5 | import java.util.Arrays;
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | import static com.joker.api.support.PermissionsPageManager.MANUFACTURER_MEIZU;
10 | import static com.joker.api.support.PermissionsPageManager.MANUFACTURER_OPPO;
11 | import static com.joker.api.support.PermissionsPageManager.MANUFACTURER_XIAOMI;
12 |
13 | /**
14 | * Created by joker on 2017/9/16.
15 | */
16 |
17 | public class ManufacturerSupportUtil {
18 | private static String[] forceManufacturers = {MANUFACTURER_XIAOMI, MANUFACTURER_MEIZU};
19 | private static Set forceSet = new HashSet<>(Arrays.asList(forceManufacturers));
20 | private static String[] underMHasPermissionsRequestManufacturer = {MANUFACTURER_XIAOMI,
21 | MANUFACTURER_MEIZU, MANUFACTURER_OPPO};
22 | private static Set underMSet = new HashSet<>(Arrays.asList
23 | (underMHasPermissionsRequestManufacturer));
24 |
25 | /**
26 | * those manufacturer that need request by some special measures, above
27 | * {@link android.os.Build.VERSION_CODES#M}
28 | *
29 | * @return
30 | */
31 | public static boolean isForceManufacturer() {
32 | return forceSet.contains(PermissionsPageManager.getManufacturer());
33 | }
34 |
35 | /**
36 | * those manufacturer that need request permissions under {@link android.os.Build.VERSION_CODES#M},
37 | * above {@link android.os.Build.VERSION_CODES#LOLLIPOP}
38 | *
39 | * @return
40 | */
41 | public static boolean isUnderMHasPermissionRequestManufacturer() {
42 | return underMSet.contains(PermissionsPageManager.getManufacturer());
43 | }
44 |
45 | public static boolean isLocationMustNeedGpsManufacturer() {
46 | return PermissionsPageManager.getManufacturer().equalsIgnoreCase(MANUFACTURER_OPPO);
47 | }
48 |
49 | /**
50 | * 1.is under {@link android.os.Build.VERSION_CODES#M}, above
51 | * {@link android.os.Build.VERSION_CODES#LOLLIPOP}
52 | * 2.has permissions check
53 | * 3.open under check
54 | *
55 | * now, we know {@link PermissionsPageManager#isXIAOMI()}, {@link PermissionsPageManager#isMEIZU()}
56 | *
57 | * @param isUnderMNeedChecked {@link com.joker.api.wrapper.Wrapper#requestUnderM(boolean)}
58 | * @return
59 | */
60 | public static boolean isUnderMNeedChecked(boolean isUnderMNeedChecked) {
61 | return isUnderMHasPermissionRequestManufacturer() && isUnderMNeedChecked &&
62 | isAndroidL();
63 | }
64 |
65 | /**
66 | * Build version code is under 6.0 but above 5.0
67 | *
68 | * @return
69 | */
70 | public static boolean isAndroidL() {
71 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES
72 | .LOLLIPOP && Build.VERSION.SDK_INT < Build.VERSION_CODES.M;
73 | }
74 |
75 | public static Set getForceSet() {
76 | return forceSet;
77 | }
78 |
79 | public static Set getUnderMSet() {
80 | return underMSet;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/PermissionsPageManager.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Build;
6 | import android.util.Log;
7 |
8 | import com.joker.api.support.manufacturer.HUAWEI;
9 | import com.joker.api.support.manufacturer.MEIZU;
10 | import com.joker.api.support.manufacturer.OPPO;
11 | import com.joker.api.support.manufacturer.PermissionsPage;
12 | import com.joker.api.support.manufacturer.Protogenesis;
13 | import com.joker.api.support.manufacturer.VIVO;
14 | import com.joker.api.support.manufacturer.XIAOMI;
15 |
16 | /**
17 | * Created by joker on 2017/8/4.
18 | */
19 |
20 | public class PermissionsPageManager {
21 | /**
22 | * Build.MANUFACTURER
23 | */
24 | static final String MANUFACTURER_HUAWEI = "HUAWEI";
25 | static final String MANUFACTURER_XIAOMI = "XIAOMI";
26 | static final String MANUFACTURER_OPPO = "OPPO";
27 | static final String MANUFACTURER_VIVO = "vivo";
28 | static final String MANUFACTURER_MEIZU = "meizu";
29 | static final String manufacturer = Build.MANUFACTURER;
30 |
31 | public static String getManufacturer() {
32 | return manufacturer;
33 | }
34 |
35 | public static Intent getIntent(Activity activity) {
36 | PermissionsPage permissionsPage = new Protogenesis(activity);
37 | try {
38 | if (MANUFACTURER_HUAWEI.equalsIgnoreCase(manufacturer)) {
39 | permissionsPage = new HUAWEI(activity);
40 | } else if (MANUFACTURER_OPPO.equalsIgnoreCase(manufacturer)) {
41 | permissionsPage = new OPPO(activity);
42 | } else if (MANUFACTURER_VIVO.equalsIgnoreCase(manufacturer)) {
43 | permissionsPage = new VIVO(activity);
44 | } else if (MANUFACTURER_XIAOMI.equalsIgnoreCase(manufacturer)) {
45 | permissionsPage = new XIAOMI(activity);
46 | } else if (MANUFACTURER_MEIZU.equalsIgnoreCase(manufacturer)) {
47 | permissionsPage = new MEIZU(activity);
48 | }
49 |
50 | return permissionsPage.settingIntent();
51 | } catch (Exception e) {
52 | Log.e("Permissions4M", "手机品牌为:" + manufacturer + "异常抛出,:" + e.getMessage());
53 | permissionsPage = new Protogenesis(activity);
54 | return ((Protogenesis) permissionsPage).settingIntent();
55 | }
56 | }
57 |
58 | public static Intent getSettingIntent(Activity activity) {
59 | return new Protogenesis(activity).settingIntent();
60 | }
61 |
62 | public static boolean isXIAOMI() {
63 | return getManufacturer().equalsIgnoreCase(MANUFACTURER_XIAOMI);
64 | }
65 |
66 | public static boolean isOPPO() {
67 | return getManufacturer().equalsIgnoreCase(MANUFACTURER_OPPO);
68 | }
69 |
70 | public static boolean isMEIZU() {
71 | return getManufacturer().equalsIgnoreCase(MANUFACTURER_MEIZU);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/HUAWEI.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.app.Activity;
4 | import android.content.ActivityNotFoundException;
5 | import android.content.ComponentName;
6 | import android.content.Intent;
7 | import android.content.pm.ActivityInfo;
8 | import android.content.pm.PackageInfo;
9 | import android.content.pm.PackageManager;
10 |
11 | /**
12 | * support:
13 | * 1.mate7 android:6.0/emui 4.0.1
14 | * 2.畅享7 android:7.0/emui 5.1
15 | *
16 | * manager permissions page, permissions manage page, or {@link Protogenesis#settingIntent()}
17 | *
18 | * Created by joker on 2017/8/4.
19 | */
20 |
21 | public class HUAWEI implements PermissionsPage {
22 | private final Activity context;
23 | private final String PKG = "com.huawei.systemmanager";
24 | private final String MANAGER_OUT_CLS = "com.huawei.permissionmanager.ui.MainActivity";
25 | // private final String SINGLE_CLS = "com.huawei.permissionmanager.ui.SingleAppActivity";
26 | // private final String SINGLE_TAG = "SingleAppActivity";
27 |
28 | public HUAWEI(Activity context) {
29 | this.context = context;
30 | }
31 |
32 | @Override
33 | public Intent settingIntent() throws ActivityNotFoundException {
34 | Intent intent = new Protogenesis(context).settingIntent();
35 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
36 | intent.putExtra(PACK_TAG, context.getPackageName());
37 | ComponentName comp = null;
38 | try {
39 | PackageInfo pi = context.getPackageManager().getPackageInfo(PKG,
40 | PackageManager.GET_ACTIVITIES);
41 | for (ActivityInfo activityInfo : pi.activities) {
42 | if (activityInfo.name.equals(MANAGER_OUT_CLS)) {
43 | comp = new ComponentName(PKG, MANAGER_OUT_CLS);
44 | }
45 | }
46 | if (comp != null) {
47 | intent.setComponent(comp);
48 | }
49 | } catch (PackageManager.NameNotFoundException e) {
50 | e.printStackTrace();
51 | return intent;
52 | }
53 |
54 | return intent;
55 |
56 | // need "com.huawei.systemmanager.permission.ACCESS_INTERFACE" permission
57 | // try {
58 | // PackageInfo pi = context.getPackageManager().getPackageInfo(PKG,
59 | // PackageManager.GET_ACTIVITIES);
60 | // for (ActivityInfo activityInfo : pi.activities) {
61 | // if (activityInfo.name.contains(SINGLE_TAG)) {
62 | // comp = new ComponentName(PKG, SINGLE_CLS);
63 | // }
64 | // }
65 | // } catch (PackageManager.NameNotFoundException e) {
66 | // e.printStackTrace();
67 | // }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/MEIZU.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.app.Activity;
4 | import android.content.ComponentName;
5 | import android.content.Intent;
6 |
7 | import com.joker.api.support.ManufacturerSupportUtil;
8 |
9 | /**
10 | * Created by joker on 2017/8/24.
11 | */
12 |
13 | public class MEIZU implements PermissionsPage {
14 | private final Activity activity;
15 | private final String N_MANAGER_OUT_CLS = "com.meizu.safe.permission.PermissionMainActivity";
16 | private final String L_MANAGER_OUT_CLS = "com.meizu.safe.SecurityMainActivity";
17 | private final String PKG = "com.meizu.safe";
18 |
19 | public MEIZU(Activity activity) {
20 | this.activity = activity;
21 | }
22 |
23 | @Override
24 | public Intent settingIntent() throws Exception {
25 | Intent intent = new Intent();
26 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
27 | intent.putExtra(PACK_TAG, activity.getPackageName());
28 | ComponentName comp = new ComponentName(PKG, getCls());
29 | intent.setComponent(comp);
30 |
31 | return intent;
32 | }
33 |
34 | private String getCls() {
35 | if (ManufacturerSupportUtil.isAndroidL()) {
36 | return L_MANAGER_OUT_CLS;
37 | } else {
38 | return N_MANAGER_OUT_CLS;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/OPPO.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.app.Activity;
4 | import android.content.ComponentName;
5 | import android.content.Intent;
6 |
7 | /**
8 | * support:
9 | * 1. oppo a57 android 6.0.1/coloros3.0
10 | *
11 | * manager home page, permissions manage page does not work!!!, or
12 | * {@link Protogenesis#settingIntent()}
13 | *
14 | * Created by joker on 2017/8/4.
15 | */
16 |
17 | public class OPPO implements PermissionsPage {
18 | private final Activity context;
19 | private final String PKG = "com.coloros.safecenter";
20 | private final String MANAGER_OUT_CLS = "com.coloros.safecenter.permission.singlepage" +
21 | ".PermissionSinglePageActivity";
22 |
23 | public OPPO(Activity context) {
24 | this.context = context;
25 | }
26 |
27 | @Override
28 | public Intent settingIntent() throws Exception {
29 | Intent intent = new Intent();
30 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
31 | intent.putExtra(PACK_TAG, context.getPackageName());
32 | ComponentName comp;
33 | comp = new ComponentName(PKG, MANAGER_OUT_CLS);
34 | // do not work!!
35 | // comp = new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission" + ".PermissionAppAllPermissionActivity");
36 | intent.setComponent(comp);
37 |
38 | return intent;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/PermissionsPage.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.content.Intent;
4 |
5 | /**
6 | * Created by joker on 2017/8/4.
7 | */
8 |
9 | public interface PermissionsPage {
10 | String PACK_TAG = "package";
11 |
12 | // normally, ActivityNotFoundException
13 | Intent settingIntent() throws Exception;
14 | }
15 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/Protogenesis.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.provider.Settings;
7 |
8 | /**
9 | * Created by joker on 2017/8/4.
10 | */
11 |
12 | public class Protogenesis implements PermissionsPage {
13 | private final Activity activity;
14 |
15 | public Protogenesis(Activity activity) {
16 | this.activity = activity;
17 | }
18 |
19 | // system details setting page
20 | @Override
21 | public Intent settingIntent() {
22 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
23 | Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
24 | intent.setData(uri);
25 |
26 | return intent;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/VIVO.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.app.Activity;
4 | import android.content.ComponentName;
5 | import android.content.Intent;
6 |
7 | /**
8 | * support:
9 | * 1.Y55A androi:6.0.1/Funtouch 2.6
10 | * 2.Xplay5A android: 5.1.1/Funtouch 3
11 | *
12 | * manager home page, or {@link Protogenesis#settingIntent()}
13 | *
14 | * Created by joker on 2017/8/4.
15 | */
16 |
17 | public class VIVO implements PermissionsPage {
18 | private final String MAIN_CLS = "com.iqoo.secure.MainActivity";
19 | private final String PKG = "com.iqoo.secure";
20 | private final Activity context;
21 |
22 | public VIVO(Activity context) {
23 | this.context = context;
24 | }
25 |
26 | @Override
27 | public Intent settingIntent() throws Exception {
28 | Intent intent = new Intent();
29 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
30 | intent.putExtra(PACK_TAG, context.getPackageName());
31 | ComponentName comp = new ComponentName(PKG, MAIN_CLS);
32 |
33 | // starting Intent { flg=0x10000000 cmp=com.iqoo.secure/.safeguard.PurviewTabActivity (has
34 | // extras) } from ProcessRecord
35 | // ComponentName comp = new ComponentName(PKG, "com.iqoo.secure.safeguard.PurviewTabActivity");
36 |
37 | // can enter, but blank
38 | // try {
39 | // PackageInfo pi = context.getPackageManager().getPackageInfo(PKG,
40 | // PackageManager.GET_ACTIVITIES);
41 | // for (ActivityInfo activityInfo : pi.activities) {
42 | // Log.e("TAG", "settingIntent: " + activityInfo.name);
43 | // if (activityInfo.name.contains(IN_CLS)) {
44 | // comp = new ComponentName(PKG, "com.iqoo.secure.safeguard
45 | // .SoftPermissionDetailActivity");
46 | // }
47 | // }
48 | // } catch (PackageManager.NameNotFoundException e) {
49 | // e.printStackTrace();
50 | // }
51 | intent.setComponent(comp);
52 |
53 | return intent;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/support/manufacturer/XIAOMI.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.support.manufacturer;
2 |
3 | import android.app.Activity;
4 | import android.content.ActivityNotFoundException;
5 | import android.content.ComponentName;
6 | import android.content.Intent;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.InputStreamReader;
11 |
12 | /**
13 | * support:
14 | * 1.hongmi 5X android:6.0.1/miui 8.2
15 | *
16 | * manager home page, or {@link Protogenesis#settingIntent()}
17 | *
18 | * Created by joker on 2017/8/4.
19 | */
20 |
21 | public class XIAOMI implements PermissionsPage {
22 | private final String PKG = "com.miui.securitycenter";
23 | // manager
24 | private final String MIUI8_MANAGER_OUT_CLS = "com.miui.securityscan.MainActivity";
25 | private final String MIUI7_MANAGER_OUT_CLS = "com.miui.permcenter.permissions" +
26 | ".AppPermissionsEditorActivity";
27 | // xiaomi permissions setting page
28 | private final String MIUI8_OUT_CLS = "com.android.settings.applications.InstalledAppDetailsTop";
29 | private final Activity context;
30 |
31 | public XIAOMI(Activity context) {
32 | this.context = context;
33 | }
34 |
35 | private static String getSystemProperty() {
36 | String line = "";
37 | BufferedReader input = null;
38 | try {
39 | Process p = Runtime.getRuntime().exec("getprop ro.miui.ui.version.name");
40 | input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
41 | line = input.readLine();
42 | } catch (IOException ex) {
43 | ex.printStackTrace();
44 | return "";
45 | } finally {
46 | if (input != null) {
47 | try {
48 | input.close();
49 | } catch (IOException e) {
50 | e.printStackTrace();
51 | }
52 | }
53 | }
54 | return line;
55 | }
56 |
57 | @Override
58 | public Intent settingIntent() throws ActivityNotFoundException {
59 | Intent intent = new Intent();
60 | String miuiInfo = getSystemProperty();
61 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
62 | if (miuiInfo.contains("7") || miuiInfo.contains("6")) {
63 | intent = new Intent("miui.intent.action.APP_PERM_EDITOR");
64 | intent.setClassName(PKG, MIUI7_MANAGER_OUT_CLS);
65 | intent.putExtra("extra_pkgname", context.getPackageName());
66 | } else {
67 | // miui 8
68 | intent.putExtra(PACK_TAG, context.getPackageName());
69 | ComponentName comp = new ComponentName(PKG, MIUI8_MANAGER_OUT_CLS);
70 | intent.setComponent(comp);
71 | }
72 |
73 | return intent;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/AbstractWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.app.Activity;
4 | import android.content.pm.PackageManager;
5 | import android.os.Build;
6 | import android.support.v4.content.ContextCompat;
7 |
8 | import com.joker.api.Permissions4M;
9 | import com.joker.api.apply.ForceApplyPermissions;
10 | import com.joker.api.apply.NormalApplyPermissions;
11 | import com.joker.api.apply.PermissionsChecker;
12 | import com.joker.api.support.ManufacturerSupportUtil;
13 |
14 | import java.lang.ref.WeakReference;
15 | import java.util.Arrays;
16 | import java.util.HashMap;
17 | import java.util.Map;
18 |
19 | /**
20 | * Created by joker on 2017/8/5.
21 | */
22 |
23 | public abstract class AbstractWrapper implements PermissionWrapper, Cloneable {
24 | private static final String PERMISSIONS_PROXY = "$$PermissionsProxy";
25 | @Permissions4M.PageType
26 | private static final int DEFAULT_PAGE_TYPE = Permissions4M.PageType.ANDROID_SETTING_PAGE;
27 | private static final int DEFAULT_REQUEST_CODE = -1;
28 | private static final boolean DEFAULT_IS_FORCE = true;
29 | private static final boolean DEFAULT_IS_ALLOWED = false;
30 | private static Map> wrapperMap = new HashMap<>();
31 | @Permissions4M.PageType
32 | private int pageType = DEFAULT_PAGE_TYPE;
33 | private int requestCode = DEFAULT_REQUEST_CODE;
34 | private int[] requestCodes;
35 | private String[] permissions;
36 | private String permission;
37 | private PermissionRequestListener permissionRequestListener;
38 | private PermissionPageListener permissionPageListener;
39 | private PermissionCustomRationaleListener permissionCustomRationaleListener;
40 | private boolean force = DEFAULT_IS_FORCE;
41 | private boolean allowed = DEFAULT_IS_ALLOWED;
42 | private boolean requestOnRationale;
43 |
44 | public AbstractWrapper() {
45 | }
46 |
47 | public static Map> getWrapperMap() {
48 | return wrapperMap;
49 | }
50 |
51 | @Override
52 | public PermissionsProxy getProxy(String className) {
53 | String proxyName = className + PERMISSIONS_PROXY;
54 | try {
55 | return (PermissionsProxy) Class.forName(proxyName).newInstance();
56 | } catch (IllegalAccessException e) {
57 | e.printStackTrace();
58 | } catch (InstantiationException e) {
59 | e.printStackTrace();
60 | } catch (ClassNotFoundException e) {
61 | e.printStackTrace();
62 | }
63 |
64 | return null;
65 | }
66 |
67 | @Override
68 | public Wrapper requestCode(int code) {
69 | if (code < 0) {
70 | throw new IllegalArgumentException("request code must bigger than 0, current is " + code);
71 | }
72 | this.requestCode = code;
73 | return this;
74 | }
75 |
76 | @Override
77 | public Wrapper requestCodes(int... codes) {
78 | this.requestCodes = codes;
79 | return this;
80 | }
81 |
82 | @Override
83 | public Wrapper requestPermission(String permission) {
84 | this.permission = permission;
85 | return this;
86 | }
87 |
88 | @Override
89 | public Wrapper requestPermissions(String... permissions) {
90 | this.permissions = permissions;
91 | return this;
92 | }
93 |
94 | @Override
95 | public Wrapper requestPageType(@Permissions4M.PageType int pageType) {
96 | this.pageType = pageType;
97 | return this;
98 | }
99 |
100 | @Override
101 | public Wrapper requestListener(PermissionRequestListener listener) {
102 | this.permissionRequestListener = listener;
103 | return this;
104 | }
105 |
106 | @Override
107 | public Wrapper requestPage(PermissionPageListener listener) {
108 | this.permissionPageListener = listener;
109 | return this;
110 | }
111 |
112 | @Override
113 | public Wrapper requestOnRationale() {
114 | requestOnRationale = true;
115 | return this;
116 | }
117 |
118 | @Override
119 | public Wrapper requestForce(boolean force) {
120 | this.force = force;
121 | return this;
122 | }
123 |
124 | @Override
125 | public Wrapper requestUnderM(boolean allow) {
126 | this.allowed = allow;
127 | return this;
128 | }
129 |
130 | @Override
131 | public Wrapper requestCustomRationaleListener(PermissionCustomRationaleListener listener) {
132 | this.permissionCustomRationaleListener = listener;
133 | return this;
134 | }
135 |
136 | @Override
137 | public int getRequestCode() {
138 | return requestCode;
139 | }
140 |
141 | @Override
142 | public int[] getRequestCodes() {
143 | return requestCodes;
144 | }
145 |
146 | @Override
147 | public String getRequestPermission() {
148 | return permission;
149 | }
150 |
151 | @Override
152 | public String[] getRequestPermissions() {
153 | return permissions;
154 | }
155 |
156 | @Override
157 | public int getPageType() {
158 | return pageType;
159 | }
160 |
161 | @Override
162 | public PermissionRequestListener getPermissionRequestListener() {
163 | return permissionRequestListener;
164 | }
165 |
166 | @Override
167 | public PermissionPageListener getPermissionPageListener() {
168 | return permissionPageListener;
169 | }
170 |
171 | @Override
172 | public PermissionCustomRationaleListener getPermissionCustomRationaleListener() {
173 | return permissionCustomRationaleListener;
174 | }
175 |
176 | @Override
177 | public boolean isRequestForce() {
178 | return force;
179 | }
180 |
181 | @Override
182 | public boolean isRequestOnRationale() {
183 | return requestOnRationale;
184 | }
185 |
186 | @Override
187 | public boolean isRequestUnderM() {
188 | return allowed;
189 | }
190 |
191 | @Override
192 | public void request() {
193 | if (isRequestOnRationale()) {
194 | addEntity(getRequestPermissions()[0], getRequestCodes()[0], false);
195 | originalRequest();
196 | } else {
197 | PermissionRequestListener requestListener = getPermissionRequestListener();
198 | if (requestListener != null) {
199 | initArrayAndEntity();
200 | requestPermissionWithListener();
201 | } else {
202 | addEntity(getRequestPermissions()[0], getRequestCodes()[0], true);
203 | requestPermissionWithAnnotation();
204 | }
205 | }
206 | }
207 |
208 | /**
209 | * init {@link #getRequestPermissions()} array and {@link #getRequestCodes()} array
210 | * and call {@link #addEntity(String, int, boolean)} method.
211 | */
212 | private void initArrayAndEntity() {
213 | String[] permissions = getRequestPermissions();
214 | String[] targetPermissions = new String[permissions.length];
215 | if (permissions.length != requestCodes.length) {
216 | throw new IllegalArgumentException("permissions' length is different from codes' length");
217 | }
218 | int[] requestCodes = getRequestCodes();
219 | int[] targetCodes = new int[requestCodes.length];
220 | for (int i = permissions.length - 1; i >= 0; i--) {
221 | targetPermissions[permissions.length - i - 1] = permissions[i];
222 | targetCodes[permissions.length - i - 1] = requestCodes[i];
223 | }
224 |
225 | for (int i = 0; i < targetPermissions.length; i++) {
226 | if (i == 0) {
227 | requestCodes(DEFAULT_REQUEST_CODE);
228 | requestPermissions("");
229 | } else {
230 | requestCodes(targetCodes[i - 1]);
231 | requestPermissions(targetPermissions[i - 1]);
232 | }
233 |
234 | addEntity(targetPermissions[i], targetCodes[i], true);
235 | }
236 | }
237 |
238 | /**
239 | * we normal use {@link PermissionWrapper#getRequestCode()} and
240 | * {@link PermissionWrapper#getRequestPermission()} not
241 | * {@link Wrapper#getRequestCodes()} or
242 | * {@link Wrapper#getRequestPermissions()}
243 | *
244 | *
245 | * add an entity to map
246 | * entity struct:
247 | * permission -> context
248 | *
249 | * @param permission
250 | * @param requestCode
251 | * @param add
252 | */
253 | private void addEntity(String permission, int requestCode, boolean add) {
254 | requestCode(requestCode);
255 | requestPermission(permission);
256 | // use a map to hold wrappers
257 | if (add) {
258 | try {
259 | // use clone() method!
260 | wrapperMap.put(new Key(getContext(), requestCode), new WeakReference<>(
261 | (PermissionWrapper) this.clone()));
262 | } catch (CloneNotSupportedException e) {
263 | e.printStackTrace();
264 | }
265 | }
266 | }
267 |
268 | void requestSync(Activity activity) {
269 | privateRequestSync(activity);
270 | }
271 |
272 | void requestSync(android.app.Fragment fragment) {
273 | privateRequestSync(fragment);
274 | }
275 |
276 | void requestSync(android.support.v4.app.Fragment fragment) {
277 | privateRequestSync(fragment);
278 | }
279 |
280 | @SuppressWarnings("unchecked")
281 | private void privateRequestSync(Object object) {
282 | getProxy(object.getClass().getName()).startSyncRequestPermissionsMethod(object);
283 | }
284 |
285 | /**
286 | * 1.under {@link android.os.Build.VERSION_CODES#M}, and it's not the
287 | * {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()} manufacturer (those are
288 | * some manufacturers that has permission manage under M) or it's the
289 | * {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()}, but under
290 | * {@link android.os.Build.VERSION_CODES#LOLLIPOP}
291 | *
292 | * 2.it's not the {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()}, and
293 | * Version Code is above than {@link android.os.Build.VERSION_CODES#M}
294 | *
295 | * 3.under {@link android.os.Build.VERSION_CODES#M}, and it's
296 | * {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()}
297 | */
298 | @SuppressWarnings("unchecked")
299 | private void requestPermissionWithAnnotation() {
300 | if (ManufacturerSupportUtil.isUnderMNeedChecked(isRequestUnderM())) {
301 | if (PermissionsChecker.isPermissionGranted(getActivity(), getRequestPermission())) {
302 | NormalApplyPermissions.grantedWithAnnotation(this);
303 | } else {
304 | ForceApplyPermissions.deniedWithAnnotationForUnderM(this);
305 | }
306 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
307 | String permission = getRequestPermission();
308 | if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager
309 | .PERMISSION_GRANTED) {
310 | tryRequestWithAnnotation();
311 | } else {
312 | mayGrantedWithAnnotation();
313 | }
314 | } else {
315 | NormalApplyPermissions.grantedWithAnnotation(this);
316 | }
317 | }
318 |
319 | private void mayGrantedWithAnnotation() {
320 | if (isRequestForce()) {
321 | ForceApplyPermissions.grantedWithAnnotation(this);
322 | } else {
323 | NormalApplyPermissions.grantedWithAnnotation(this);
324 | }
325 | }
326 |
327 | /**
328 | * 1.under {@link android.os.Build.VERSION_CODES#M}, and it's not the
329 | * {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()} manufacturer (those are
330 | * some manufacturers that has permission manage under M)
331 | *
332 | * 2.it's not the {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()}, and
333 | * Version Code is bigger than {@link android.os.Build.VERSION_CODES#M}
334 | *
335 | * 3.under {@link android.os.Build.VERSION_CODES#M}, and it's
336 | * {@link ManufacturerSupportUtil#isUnderMHasPermissionRequestManufacturer()}
337 | */
338 | public void requestPermissionWithListener() {
339 | if (ManufacturerSupportUtil.isUnderMNeedChecked(isRequestUnderM())) {
340 | if (PermissionsChecker.isPermissionGranted(getActivity(), getRequestPermission())) {
341 | NormalApplyPermissions.grantedWithListener(this);
342 | } else {
343 | ForceApplyPermissions.deniedWithListenerForUnderM(this);
344 | }
345 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
346 | if (ContextCompat.checkSelfPermission(getActivity(), getRequestPermission()) != PackageManager
347 | .PERMISSION_GRANTED) {
348 | tryRequestWithListener();
349 | } else {
350 | mayGrantedWithListener();
351 | }
352 | } else {
353 | NormalApplyPermissions.grantedWithListener(this);
354 | }
355 | }
356 |
357 | private void mayGrantedWithListener() {
358 | if (isRequestForce()) {
359 | ForceApplyPermissions.grantedWithListener(this);
360 | } else {
361 | NormalApplyPermissions.grantedWithListener(this);
362 | }
363 | }
364 |
365 | /**
366 | * request in second request, should use original request with no callback.
367 | */
368 | abstract void originalRequest();
369 |
370 | /**
371 | * use annotation request
372 | */
373 | abstract void tryRequestWithAnnotation();
374 |
375 | /**
376 | * use listener request
377 | */
378 | abstract void tryRequestWithListener();
379 |
380 | @Override
381 | public String toString() {
382 | return "AbstractWrapper{" +
383 | "pageType=" + pageType +
384 | ", requestCode=" + requestCode +
385 | ", requestCodes=" + Arrays.toString(requestCodes) +
386 | ", permissions=" + Arrays.toString(permissions) +
387 | ", permission='" + permission + '\'' +
388 | ", permissionRequestListener=" + permissionRequestListener +
389 | ", permissionPageListener=" + permissionPageListener +
390 | ", permissionCustomRationaleListener=" + permissionCustomRationaleListener +
391 | ", force=" + force +
392 | ", allowed=" + allowed +
393 | ", requestOnRationale=" + requestOnRationale +
394 | '}';
395 | }
396 |
397 | @Override
398 | protected Object clone() throws CloneNotSupportedException {
399 | return super.clone();
400 | }
401 |
402 | public static class Key {
403 | private int requestCode;
404 | private WeakReference object;
405 |
406 | public Key(Object object, int requestCode) {
407 | this.object = new WeakReference<>(object);
408 | this.requestCode = requestCode;
409 | }
410 |
411 | @Override
412 | public String toString() {
413 | return "Key{" +
414 | "requestCode=" + requestCode +
415 | ", object=" + object +
416 | '}';
417 | }
418 |
419 | @Override
420 | public boolean equals(Object obj) {
421 | return obj instanceof Key && ((Key) obj)
422 | .getObject().get() != null && object.get().getClass() != null && ((Key) obj)
423 | .getRequestCode() == requestCode && object.get().getClass().getName().equals(((Key)
424 | obj).getObject().get().getClass()
425 | .getName());
426 | }
427 |
428 | @Override
429 | public int hashCode() {
430 | return (object.get().hashCode() + requestCode) / 10;
431 | }
432 |
433 | public int getRequestCode() {
434 | return requestCode;
435 | }
436 |
437 | public void setRequestCode(int requestCode) {
438 | this.requestCode = requestCode;
439 | }
440 |
441 | public WeakReference getObject() {
442 | return object;
443 | }
444 |
445 | public void setObject(WeakReference object) {
446 | this.object = object;
447 | }
448 | }
449 | }
450 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/ActivityWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.support.v4.app.ActivityCompat;
6 |
7 | /**
8 | * Created by joker on 2017/8/5.
9 | */
10 |
11 | public class ActivityWrapper extends AbstractWrapper implements Wrapper {
12 | private final Activity activity;
13 |
14 | public ActivityWrapper(Activity activity) {
15 | this.activity = activity;
16 | }
17 |
18 | @Override
19 | public Object getContext() {
20 | return activity;
21 | }
22 |
23 | @Override
24 | public void requestSync() {
25 | requestSync(activity);
26 | }
27 |
28 | @Override
29 | void originalRequest() {
30 | ActivityCompat.requestPermissions(getActivity(), new String[]{getRequestPermission()},
31 | getRequestCode());
32 | }
33 |
34 | @SuppressWarnings("unchecked")
35 | @SuppressLint("NewApi")
36 | void tryRequestWithAnnotation() {
37 | int requestCode = getRequestCode();
38 | if ((getActivity()).shouldShowRequestPermissionRationale(getRequestPermission())) {
39 | Object context = getContext();
40 | if (!getProxy(context.getClass().getName()).customRationale(getActivity(),
41 | requestCode)) {
42 | getProxy(context.getClass().getName()).rationale(getActivity(), requestCode);
43 | ActivityCompat.requestPermissions(getActivity(), new String[]{getRequestPermission()},
44 | requestCode);
45 | }
46 | } else {
47 | ActivityCompat.requestPermissions(getActivity(), new String[]{getRequestPermission()},
48 | requestCode);
49 | }
50 | }
51 |
52 | @SuppressWarnings("unchecked")
53 | void tryRequestWithListener() {
54 | PermissionCustomRationaleListener customRationaleListener = getPermissionCustomRationaleListener();
55 | int requestCode = getRequestCode();
56 |
57 | if (customRationaleListener != null) {
58 | customRationaleListener.permissionCustomRationale(requestCode);
59 | } else {
60 | String requestPermission = getRequestPermission();
61 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
62 | PermissionRequestListener requestListener = getPermissionRequestListener();
63 | if (requestListener != null) {
64 | requestListener.permissionRationale(requestCode);
65 | }
66 | }
67 | ActivityCompat.requestPermissions(activity, new String[]{requestPermission},
68 | requestCode);
69 | }
70 | }
71 |
72 | @Override
73 | public Activity getActivity() {
74 | return (Activity) getContext();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/AnnotationWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.content.Intent;
4 |
5 | /**
6 | * Created by joker on 2017/8/16.
7 | */
8 |
9 | public interface AnnotationWrapper {
10 | /**
11 | * get the proxy class
12 | * @param className target class name
13 | * @return
14 | */
15 | PermissionsProxy getProxy(String className);
16 |
17 | interface PermissionsProxy {
18 | void rationale(T object, int code);
19 |
20 | void denied(T object, int code);
21 |
22 | void granted(T object, int code);
23 |
24 | void intent(T object, int code, Intent intent);
25 |
26 | boolean customRationale(T object, int code);
27 |
28 | void startSyncRequestPermissionsMethod(T object);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/FragmentBaseWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.annotation.SuppressLint;
4 |
5 | /**
6 | * Created by joker on 2017/8/17.
7 | */
8 |
9 | abstract class FragmentBaseWrapper extends AbstractWrapper implements Wrapper {
10 | public FragmentBaseWrapper() {
11 |
12 | }
13 |
14 | @SuppressWarnings("unchecked")
15 | @SuppressLint("NewApi")
16 | void tryRequestWithAnnotation() {
17 | Object context = getContext();
18 | int requestCode = getRequestCode();
19 | String requestPermission = getRequestPermission();
20 | if (context instanceof android.support.v4.app.Fragment) {
21 | if (((android.support.v4.app.Fragment) context).shouldShowRequestPermissionRationale
22 | (requestPermission)) {
23 | if (!getProxy(context.getClass().getName()).customRationale(context, requestCode)) {
24 | getProxy(context.getClass().getName()).rationale(context, requestCode);
25 | originalRequest();
26 | }
27 | } else {
28 | originalRequest();
29 | }
30 | } else {
31 | if (((android.app.Fragment) context).shouldShowRequestPermissionRationale
32 | (requestPermission)) {
33 | if (!getProxy(context.getClass().getName()).customRationale(context,
34 | requestCode)) {
35 | getProxy(context.getClass().getName()).rationale(context, requestCode);
36 | originalRequest();
37 | }
38 | } else {
39 | originalRequest();
40 | }
41 | }
42 | }
43 |
44 | @SuppressLint("NewApi")
45 | void tryRequestWithListener() {
46 | PermissionCustomRationaleListener customRationaleListener = getPermissionCustomRationaleListener();
47 | Object context = getContext();
48 | int requestCode = getRequestCode();
49 | String requestPermission = getRequestPermission();
50 | PermissionRequestListener requestListener = getPermissionRequestListener();
51 |
52 | if (context instanceof android.app.Fragment) {
53 | if (((android.app.Fragment) context).shouldShowRequestPermissionRationale
54 | (requestPermission)) {
55 | if (customRationaleListener != null) {
56 | customRationaleListener.permissionCustomRationale(getRequestCode());
57 | } else {
58 | requestListener.permissionRationale(requestCode);
59 | originalRequest();
60 | }
61 | } else {
62 | originalRequest();
63 | }
64 | } else {
65 | if (((android.support.v4.app.Fragment) context).shouldShowRequestPermissionRationale
66 | (requestPermission)) {
67 | if (customRationaleListener != null) {
68 | customRationaleListener.permissionCustomRationale(getRequestCode());
69 | } else {
70 | requestListener.permissionRationale(requestCode);
71 | originalRequest();
72 | }
73 | } else {
74 | originalRequest();
75 | }
76 | }
77 | }
78 |
79 | @Override
80 | @SuppressLint("NewApi")
81 | void originalRequest() {
82 | Object context = getContext();
83 | String permission = getRequestPermission();
84 | int code = getRequestCode();
85 | if (context instanceof android.app.Fragment) {
86 | ((android.app.Fragment) context).requestPermissions(new String[]{permission}, code);
87 | } else {
88 | ((android.support.v4.app.Fragment) context).requestPermissions(new
89 | String[]{permission}, code);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/FragmentWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.app.Activity;
4 |
5 | /**
6 | * Created by joker on 2017/8/5.
7 | */
8 |
9 | public class FragmentWrapper extends FragmentBaseWrapper implements Wrapper {
10 | private final android.app.Fragment fragment;
11 |
12 | public FragmentWrapper(android.app.Fragment fragment) {
13 | this.fragment = fragment;
14 | }
15 |
16 | @Override
17 | public Object getContext() {
18 | return fragment;
19 | }
20 |
21 | @Override
22 | public void requestSync() {
23 | requestSync(fragment);
24 | }
25 |
26 | @Override
27 | public Activity getActivity() {
28 | return ((android.app.Fragment) getContext()).getActivity();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/ListenerWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.content.Intent;
4 |
5 | /**
6 | * listener callback should implement this interface
7 | *
8 | * Created by joker on 2017/8/16.
9 | */
10 |
11 | public interface ListenerWrapper {
12 | /**
13 | * call back listener
14 | *
15 | * @param listener {@link PermissionPageListener}
16 | * @return
17 | */
18 | Wrapper requestListener(PermissionRequestListener listener);
19 |
20 | /**
21 | * according to {@link Wrapper#requestPageType(int)}, will return different Intent type
22 | *
23 | * @param listener {@link PermissionPageListener}
24 | * @return
25 | */
26 | Wrapper requestPage(PermissionPageListener listener);
27 |
28 | Wrapper requestCustomRationaleListener(PermissionCustomRationaleListener listener);
29 |
30 | PermissionRequestListener getPermissionRequestListener();
31 |
32 | PermissionPageListener getPermissionPageListener();
33 |
34 | PermissionCustomRationaleListener getPermissionCustomRationaleListener();
35 |
36 | interface PermissionRequestListener {
37 | void permissionGranted(int code);
38 |
39 | void permissionDenied(int code);
40 |
41 | void permissionRationale(int code);
42 | }
43 |
44 | interface PermissionPageListener {
45 | void pageIntent(int code, Intent intent);
46 | }
47 |
48 | interface PermissionCustomRationaleListener {
49 | void permissionCustomRationale(int code);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/PermissionWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | /**
4 | * Created by joker on 2017/9/2.
5 | */
6 |
7 | public interface PermissionWrapper extends Wrapper {
8 | String getRequestPermission();
9 |
10 | int getRequestCode();
11 |
12 | Wrapper requestPermission(String permission);
13 |
14 | Wrapper requestCode(int code);
15 | }
16 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/SupportFragmentWrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.app.Activity;
4 |
5 | /**
6 | * Created by joker on 2017/8/5.
7 | */
8 |
9 | public class SupportFragmentWrapper extends FragmentBaseWrapper implements Wrapper {
10 | private final android.support.v4.app.Fragment fragment;
11 |
12 | public SupportFragmentWrapper(android.support.v4.app.Fragment fragment) {
13 | this.fragment = fragment;
14 | }
15 |
16 | @Override
17 | public Object getContext() {
18 | return fragment;
19 | }
20 |
21 | @Override
22 | public void requestSync() {
23 | requestSync(fragment);
24 | }
25 |
26 | @Override
27 | public Activity getActivity() {
28 | return ((android.support.v4.app.Fragment) getContext()).getActivity();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/permissions4m-api/src/main/java/com/joker/api/wrapper/Wrapper.java:
--------------------------------------------------------------------------------
1 | package com.joker.api.wrapper;
2 |
3 | import android.app.Activity;
4 |
5 | import com.joker.api.Permissions4M;
6 |
7 | /**
8 | * Created by joker on 2017/8/5.
9 | */
10 |
11 | public interface Wrapper extends ListenerWrapper, AnnotationWrapper {
12 | /**
13 | * get activity
14 | *
15 | * @return
16 | */
17 | Activity getActivity();
18 |
19 | /**
20 | * request code
21 | *
22 | * @param code
23 | * @return
24 | */
25 | Wrapper requestCodes(int... code);
26 |
27 | /**
28 | * request permission
29 | *
30 | * @param permission {@link android.Manifest.permission}
31 | * @return
32 | */
33 | Wrapper requestPermissions(String... permission);
34 |
35 | /**
36 | * android setting page or phone manager page
37 | *
38 | * @param pageType {@link Permissions4M.PageType}
39 | * @return
40 | */
41 | Wrapper requestPageType(@Permissions4M.PageType int pageType);
42 |
43 | /**
44 | * whether should apply permission force
45 | *
46 | * @param force true if force
47 | * @return
48 | */
49 | Wrapper requestForce(boolean force);
50 |
51 | /**
52 | * called when use custom rationale, in case fall in to drop-dead
53 | *
54 | * custom rationale -> ensure button -> Permissions4M.request ->
55 | * if(custom rationale) -> custom rationale
56 | *
57 | * @return
58 | */
59 | Wrapper requestOnRationale();
60 |
61 | /**
62 | * allow the android(under {@link android.os.Build.VERSION_CODES#M}, above
63 | * {@link android.os.Build.VERSION_CODES#LOLLIPOP}) to request permission
64 | *
65 | * @param allow true if allow
66 | * @return
67 | */
68 | Wrapper requestUnderM(boolean allow);
69 |
70 | /**
71 | * get the context({@link android.app.Activity}, {@link android.app.Fragment},
72 | * {@link android.support.v4.app.Fragment})
73 | *
74 | * @return {@link android.app.Activity} or {@link android.app.Fragment} or
75 | * {@link android.support.v4.app.Fragment}
76 | */
77 | Object getContext();
78 |
79 | /**
80 | * request permission
81 | */
82 | void request();
83 |
84 | /**
85 | * multiple permission request by sync
86 | */
87 | void requestSync();
88 |
89 | int[] getRequestCodes();
90 |
91 | String[] getRequestPermissions();
92 |
93 | boolean isRequestOnRationale();
94 |
95 | boolean isRequestUnderM();
96 |
97 | @Permissions4M.PageType
98 | int getPageType();
99 |
100 | boolean isRequestForce();
101 | }
102 |
--------------------------------------------------------------------------------
/permissions4m-processor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/permissions4m-processor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | group = 'com.github.jokermonn'
5 |
6 | dependencies {
7 | compile fileTree(include: ['*.jar'], dir: 'libs')
8 | compile 'com.jokermonn:permissions4m-annotation:1.0.3'
9 | compile 'com.google.auto.service:auto-service:1.0-rc3'
10 | }
11 |
12 | sourceCompatibility = "1.7"
13 | targetCompatibility = "1.7"
14 |
--------------------------------------------------------------------------------
/permissions4m-processor/src/main/java/com/joker/processor/AnnotationProcessor.java:
--------------------------------------------------------------------------------
1 | package com.joker.processor;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.joker.annotation.PermissionsCustomRationale;
5 | import com.joker.annotation.PermissionsDenied;
6 | import com.joker.annotation.PermissionsGranted;
7 | import com.joker.annotation.PermissionsNonRationale;
8 | import com.joker.annotation.PermissionsRationale;
9 | import com.joker.annotation.PermissionsRequestSync;
10 |
11 | import java.io.IOException;
12 | import java.io.Writer;
13 | import java.lang.annotation.Annotation;
14 | import java.util.HashMap;
15 | import java.util.HashSet;
16 | import java.util.Map;
17 | import java.util.Set;
18 |
19 | import javax.annotation.processing.AbstractProcessor;
20 | import javax.annotation.processing.Filer;
21 | import javax.annotation.processing.ProcessingEnvironment;
22 | import javax.annotation.processing.Processor;
23 | import javax.annotation.processing.RoundEnvironment;
24 | import javax.lang.model.SourceVersion;
25 | import javax.lang.model.element.Element;
26 | import javax.lang.model.element.ExecutableElement;
27 | import javax.lang.model.element.Modifier;
28 | import javax.lang.model.element.TypeElement;
29 | import javax.lang.model.util.Elements;
30 | import javax.tools.Diagnostic;
31 | import javax.tools.JavaFileObject;
32 |
33 | @AutoService(Processor.class)
34 | public class AnnotationProcessor extends AbstractProcessor {
35 | private Map map = new HashMap<>();
36 | private Elements mUtils;
37 | private Filer mFiler;
38 |
39 | @Override
40 | public synchronized void init(ProcessingEnvironment processingEnv) {
41 | super.init(processingEnv);
42 | mUtils = processingEnv.getElementUtils();
43 | mFiler = processingEnv.getFiler();
44 | }
45 |
46 | @Override
47 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
48 | map.clear();
49 | if (!isAnnotatedWithClass(roundEnv, PermissionsRequestSync.class)) return false;
50 | if (!isAnnotatedWithMethod(roundEnv, PermissionsNonRationale.class)) return false;
51 | if (!isAnnotatedWithMethod(roundEnv, PermissionsGranted.class)) return false;
52 | if (!isAnnotatedWithMethod(roundEnv, PermissionsDenied.class)) return false;
53 | if (!isAnnotatedWithMethod(roundEnv, PermissionsRationale.class)) return false;
54 | if (!isAnnotatedWithMethod(roundEnv, PermissionsCustomRationale.class)) return false;
55 |
56 | Writer writer = null;
57 | for (ProxyInfo info : map.values()) {
58 | try {
59 | JavaFileObject file = mFiler.createSourceFile(info.getProxyName(), info.getElement());
60 | writer = file.openWriter();
61 | writer.write(info.generateJavaCode());
62 | writer.flush();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | } finally {
66 | if (writer != null) {
67 | try {
68 | writer.close();
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | }
74 | }
75 |
76 | return true;
77 | }
78 |
79 | /**
80 | * check the annotation is illegal or not
81 | *
82 | * @param roundEnv
83 | * @param clazz the annotation type
84 | * @return false if illegal
85 | */
86 | private boolean isAnnotatedWithClass(RoundEnvironment roundEnv, Class extends Annotation> clazz) {
87 | Set extends Element> elements = roundEnv.getElementsAnnotatedWith(clazz);
88 | for (Element element : elements) {
89 | if (isValid(element)) {
90 | return false;
91 | }
92 | TypeElement typeElement = (TypeElement) element;
93 | String typeName = typeElement.getQualifiedName().toString();
94 | ProxyInfo info = map.get(typeName);
95 | if (info == null) {
96 | info = new ProxyInfo(mUtils, typeElement);
97 | map.put(typeName, info);
98 | }
99 |
100 | Annotation annotation = element.getAnnotation(clazz);
101 | if (annotation instanceof PermissionsRequestSync) {
102 | String[] permissions = ((PermissionsRequestSync) annotation).permission();
103 | int[] value = ((PermissionsRequestSync) annotation).value();
104 | if (permissions.length != value.length) {
105 | error(element, "permissions's length not equals value's length");
106 | return false;
107 | }
108 | info.syncPermissions.put(value, permissions);
109 | } else {
110 | error(element, "%s not support.", element);
111 | return false;
112 | }
113 | }
114 |
115 | return true;
116 | }
117 |
118 | /**
119 | * check the annotation is illegal or not
120 | *
121 | * @param roundEnv
122 | * @param clazz the annotation type
123 | * @return false if illegal
124 | */
125 | private boolean isAnnotatedWithMethod(RoundEnvironment roundEnv, Class extends Annotation> clazz) {
126 | Set extends Element> elements = roundEnv.getElementsAnnotatedWith(clazz);
127 | for (Element element : elements) {
128 | if (isValid(element)) {
129 | return false;
130 | }
131 | ExecutableElement method = (ExecutableElement) element;
132 | TypeElement typeElement = (TypeElement) method.getEnclosingElement();
133 | String typeName = typeElement.getQualifiedName().toString();
134 | ProxyInfo info = map.get(typeName);
135 | if (info == null) {
136 | info = new ProxyInfo(mUtils, typeElement);
137 | map.put(typeName, info);
138 | }
139 |
140 | int size = method.getParameters().size();
141 | Annotation annotation = method.getAnnotation(clazz);
142 | String methodName = method.getSimpleName().toString();
143 | if (annotation instanceof PermissionsGranted) {
144 | int[] value = ((PermissionsGranted) annotation).value();
145 | if (value.length > 1 || size == 1) {
146 | info.grantedMap.put(methodName, value);
147 | } else {
148 | info.singleGrantMap.put(value[0], methodName);
149 | }
150 | } else if (annotation instanceof PermissionsDenied) {
151 | int[] value = ((PermissionsDenied) annotation).value();
152 | if (value.length > 1 || size == 1) {
153 | info.deniedMap.put(methodName, value);
154 | } else {
155 | info.singleDeniedMap.put(value[0], methodName);
156 | }
157 | } else if (annotation instanceof PermissionsRationale) {
158 | int[] value = ((PermissionsRationale) annotation).value();
159 | if (value.length > 1 || size == 1) {
160 | info.rationaleMap.put(methodName, value);
161 | } else {
162 | info.singleRationaleMap.put(value[0], methodName);
163 | }
164 | } else if (annotation instanceof PermissionsCustomRationale) {
165 | int[] value = ((PermissionsCustomRationale) annotation).value();
166 | if (value.length > 1 || size == 1) {
167 | info.customRationaleMap.put(methodName, value);
168 | } else {
169 | info.singleCustomRationaleMap.put(value[0], methodName);
170 | }
171 | } else if (annotation instanceof PermissionsNonRationale) {
172 | int[] value = ((PermissionsNonRationale) annotation).value();
173 | if (value.length > 1 || size == 2) {
174 | info.nonRationaleMap.put(methodName, value);
175 | } else {
176 | info.singleNonRationaleMap.put(value[0], methodName);
177 | }
178 | } else {
179 | error(method, "%s not support.", method);
180 | return false;
181 | }
182 | }
183 |
184 | return true;
185 | }
186 |
187 | /**
188 | * check the annotation is public or not
189 | *
190 | * @param element the annotation annotated
191 | * @return true if not public
192 | */
193 | private boolean isValid(Element element) {
194 | if (element.getModifiers().contains(Modifier.ABSTRACT) || element.getModifiers().contains
195 | (Modifier.PRIVATE)) {
196 | error(element, "%s must could not be abstract or private");
197 | return true;
198 | }
199 |
200 | return false;
201 | }
202 |
203 | private void error(Element element, String message, Object... args) {
204 | if (args.length > 0) {
205 | message = String.format(message, args);
206 | }
207 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message, element);
208 | }
209 |
210 | @Override
211 | public Set getSupportedAnnotationTypes() {
212 | Set set = new HashSet<>(16);
213 | set.add(PermissionsGranted.class.getCanonicalName());
214 | set.add(PermissionsDenied.class.getCanonicalName());
215 | set.add(PermissionsRationale.class.getCanonicalName());
216 | set.add(PermissionsCustomRationale.class.getCanonicalName());
217 | set.add(PermissionsRequestSync.class.getCanonicalName());
218 | set.add(PermissionsNonRationale.class.getName());
219 |
220 | return set;
221 | }
222 |
223 | @Override
224 | public SourceVersion getSupportedSourceVersion() {
225 | return SourceVersion.latestSupported();
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/permissions4m-processor/src/main/java/com/joker/processor/ProxyInfo.java:
--------------------------------------------------------------------------------
1 | package com.joker.processor;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import javax.lang.model.element.TypeElement;
7 | import javax.lang.model.util.Elements;
8 |
9 | /**
10 | * Created by joker on 2017/7/26.
11 | */
12 |
13 | class ProxyInfo {
14 | private static final String PERMISSIONS_PROXY = "PermissionsProxy";
15 | private static final String CONCAT = "$$";
16 | private final String packageName;
17 | private final TypeElement element;
18 | private final String proxyName;
19 | // methodName -> requestCodes
20 | Map grantedMap = new HashMap<>();
21 | Map deniedMap = new HashMap<>();
22 | Map rationaleMap = new HashMap<>();
23 | Map customRationaleMap = new HashMap<>();
24 | Map nonRationaleMap = new HashMap<>();
25 | // requestCode -> methodName
26 | Map singleGrantMap = new HashMap<>();
27 | Map singleDeniedMap = new HashMap<>();
28 | Map singleRationaleMap = new HashMap<>();
29 | Map singleCustomRationaleMap = new HashMap<>();
30 | Map singleNonRationaleMap = new HashMap<>();
31 | // sync request
32 | Map syncPermissions = new HashMap<>(1);
33 | private int firstRequestCode;
34 | private String firstRequestPermission;
35 |
36 | ProxyInfo(Elements util, TypeElement element) {
37 | this.element = element;
38 | packageName = util.getPackageOf(element).getQualifiedName().toString();
39 | String className = getClassName(element, packageName);
40 | proxyName = className + CONCAT + PERMISSIONS_PROXY;
41 | }
42 |
43 | String getProxyName() {
44 | return proxyName;
45 | }
46 |
47 | TypeElement getElement() {
48 | return element;
49 | }
50 |
51 | String generateJavaCode() {
52 | StringBuilder builder = new StringBuilder();
53 | builder.append("package ").append(packageName).append(";\n\n")
54 | .append("import com.joker.api.Permissions4M;\n")
55 | .append("import com.joker.api.wrapper.AnnotationWrapper.PermissionsProxy;\n")
56 | .append("import android.content.Intent;\n\n")
57 | .append("public class ").append(proxyName).append(" implements ").append
58 | (PERMISSIONS_PROXY).append
59 | ("<").append(element.getSimpleName()).append("> {\n");
60 |
61 | generateMethodCode(builder);
62 |
63 | builder.append("}\n");
64 |
65 | return builder.toString();
66 | }
67 |
68 | private void generateMethodCode(StringBuilder builder) {
69 | generateGrantedMethod(builder);
70 | generateDeniedMethod(builder);
71 | generateRationaleMethod(builder);
72 | generateCustomRationaleMethod(builder);
73 | generatePageIntent(builder);
74 | generateSyncRequestPermissionsMethod(builder);
75 | }
76 |
77 | private void generateSyncRequestPermissionsMethod(StringBuilder builder) {
78 | if (builder == null) {
79 | return;
80 | }
81 |
82 | builder.append("@Override\n").append("public void startSyncRequestPermissionsMethod(").append
83 | (element.getSimpleName()).append(" object) {\n")
84 | .append("Permissions4M.requestPermission(object, \"").append(firstRequestPermission)
85 | .append("\", ").append(firstRequestCode).append(");\n")
86 | .append("}");
87 | }
88 |
89 | private void generateCustomRationaleMethod(StringBuilder builder) {
90 | if (builder == null) {
91 | return;
92 | }
93 |
94 | builder.append("@Override\n").append("public boolean customRationale(").append(element
95 | .getSimpleName())
96 | .append(" object, int code) {\n")
97 | .append("switch(code) {");
98 | for (Map.Entry entry : customRationaleMap.entrySet()) {
99 | String methodName = entry.getKey();
100 | int[] ints = entry.getValue();
101 | for (int requestCode : ints) {
102 | builder.append("case ").append(requestCode).append(":\n");
103 | if (singleCustomRationaleMap.containsKey(requestCode)) {
104 | singleCustomRationaleMap.remove(requestCode);
105 | }
106 | }
107 | builder.append("{\n").append("object.").append(methodName).append("(code);\nreturn true;\n}\n");
108 | }
109 |
110 | for (Map.Entry entry : singleCustomRationaleMap.entrySet()) {
111 | int requestCode = entry.getKey();
112 | builder.append("case ").append(requestCode).append(":{\n")
113 | .append("object.").append(entry.getValue()).append("();" +
114 | "\nreturn true;\n}");
115 | }
116 |
117 | builder.append("default:\nreturn false;\n").append("}\n}\n\n");
118 | }
119 |
120 | private void generatePageIntent(StringBuilder builder) {
121 | if (builder == null) {
122 | return;
123 | }
124 |
125 | builder.append("@Override\n").append("public void intent(").append(element.getSimpleName())
126 | .append(" object, int code, Intent intent) {\n")
127 | .append("switch(code) {");
128 |
129 | for (Map.Entry entry : nonRationaleMap.entrySet()) {
130 | String methodName = entry.getKey();
131 | int[] values = entry.getValue();
132 | for (int value : values) {
133 | builder.append("case ").append(value).append(":\n");
134 | if (singleNonRationaleMap.containsKey(value)) {
135 | singleNonRationaleMap.remove(value);
136 | }
137 | }
138 | builder.append("{").append("object.").append(methodName).append("(code, intent);break;}\n");
139 | }
140 |
141 | for (Map.Entry entry : singleNonRationaleMap.entrySet()) {
142 | Integer integer = entry.getKey();
143 | builder.append("case ").append(integer).append(":{ object.").append(entry.getValue()).append
144 | ("(intent);break;}");
145 | }
146 |
147 | builder.append("default:\nbreak;\n").append("}\n}\n\n");
148 | }
149 |
150 | private void generateRationaleMethod(StringBuilder builder) {
151 | if (builder == null) {
152 | return;
153 | }
154 |
155 | builder.append("@Override\n").append("public void rationale(").append(element.getSimpleName())
156 | .append(" object, int code) {\n")
157 | .append("switch(code) {");
158 | for (Map.Entry entry : rationaleMap.entrySet()) {
159 | String methodName = entry.getKey();
160 | int[] ints = entry.getValue();
161 | for (int requestCode : ints) {
162 | builder.append("case ").append(requestCode).append(":\n{");
163 | builder.append("object.").append(methodName).append("(").append(requestCode).append(");\n");
164 | builder.append("break;}\n");
165 | if (singleRationaleMap.containsKey(requestCode)) {
166 | singleRationaleMap.remove(requestCode);
167 | }
168 | }
169 | }
170 |
171 | for (Map.Entry entry : singleRationaleMap.entrySet()) {
172 | int requestCode = entry.getKey();
173 | builder.append("case ").append(requestCode).append(": {\n")
174 | .append("object.").append(entry.getValue()).append("();\nbreak;\n}");
175 | }
176 |
177 | builder.append("default:\nbreak;\n").append("}\n}\n\n");
178 | }
179 |
180 | private void generateDeniedMethod(StringBuilder builder) {
181 | if (builder == null) {
182 | return;
183 | }
184 |
185 | builder.append("@Override\n").append("public void denied(").append(element.getSimpleName())
186 | .append(" object, int code) {\n")
187 | .append("switch(code) {");
188 | for (Map.Entry entry : deniedMap.entrySet()) {
189 | String methodName = entry.getKey();
190 | int[] ints = entry.getValue();
191 | for (int requestCode : ints) {
192 | builder.append("case ").append(requestCode).append(":\n{");
193 | builder.append("object.").append(methodName).append("(").append(requestCode).append(");\n");
194 | // judge whether need write request permission method
195 | addSyncRequestPermissionMethod(builder, requestCode);
196 | builder.append("break;}\n");
197 | if (singleDeniedMap.containsKey(requestCode)) {
198 | singleDeniedMap.remove(requestCode);
199 | }
200 | }
201 | }
202 |
203 | for (Map.Entry entry : singleDeniedMap.entrySet()) {
204 | int requestCode = entry.getKey();
205 | builder.append("case ").append(requestCode).append(": {\n")
206 | .append("object.").append(entry.getValue()).append("();\nbreak;\n}");
207 | }
208 |
209 | builder.append("default:\nbreak;\n").append("}\n}\n\n");
210 | }
211 |
212 | private void generateGrantedMethod(StringBuilder builder) {
213 | if (builder == null) {
214 | return;
215 | }
216 |
217 | builder.append("@Override\n").append("public void granted(").append(element.getSimpleName())
218 | .append(" object, int code) {\n")
219 | .append("switch(code) {");
220 | for (Map.Entry entry : grantedMap.entrySet()) {
221 | String methodName = entry.getKey();
222 | int[] ints = entry.getValue();
223 | for (int requestCode : ints) {
224 | builder.append("case ").append(requestCode).append(":\n{");
225 | builder.append("object.").append(methodName).append("(").append(requestCode).append(");\n");
226 | // judge whether need write request permission method
227 | addSyncRequestPermissionMethod(builder, requestCode);
228 | builder.append("break;}\n");
229 | if (singleGrantMap.containsKey(requestCode)) {
230 | singleGrantMap.remove(requestCode);
231 | }
232 | }
233 | }
234 |
235 | for (Map.Entry entry : singleGrantMap.entrySet()) {
236 | int requestCode = entry.getKey();
237 | builder.append("case ").append(requestCode).append(": {\n")
238 | .append("object.").append(entry.getValue()).append("();\nbreak;\n}");
239 | }
240 |
241 | builder.append("default:\nbreak;\n").append("}\n}\n\n");
242 | }
243 |
244 | private void addSyncRequestPermissionMethod(StringBuilder builder, int targetRequestCode) {
245 | // syncPermissions size is 1
246 | for (Map.Entry entry : syncPermissions.entrySet()) {
247 | int[] requestCodes = entry.getKey();
248 | String[] permissions = entry.getValue();
249 | int length = requestCodes.length;
250 | // when syncRequestPermission size is 1
251 | if (length == 1) {
252 | firstRequestCode = requestCodes[0];
253 | firstRequestPermission = permissions[0];
254 | } else {
255 | // when syncRequestPermission size bigger than 1
256 | for (int i = 0; i < length - 1; i++) {
257 | if (i == 0) {
258 | firstRequestCode = requestCodes[0];
259 | firstRequestPermission = permissions[0];
260 | }
261 | if (requestCodes[i] == targetRequestCode) {
262 | builder.append("Permissions4M.requestPermission(object,\"").append(permissions[i +
263 | 1]).append("\",").append(requestCodes[i + 1]).append(");\n");
264 | }
265 | }
266 | }
267 | }
268 | }
269 |
270 | private String getClassName(TypeElement element, String packageName) {
271 | int packageLen = packageName.length() + 1;
272 | return element.getQualifiedName().toString().substring(packageLen)
273 | .replace('.', '$');
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':permissions4m-api', ':permissions4m-annotation', ':permissions4m-processor'
2 |
--------------------------------------------------------------------------------