Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-20320]: Refactor requestPermissions #7948

Merged
merged 5 commits into from
Apr 19, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,8 @@ public void requestCalendarPermissions(@Kroll.argument(optional=true)KrollFuncti
if (hasCalendarPermissions()) {
return;
}
if (TiBaseActivity.oldCalendarCallbackContext == null) {
TiBaseActivity.oldCalendarCallbackContext = getKrollObject();
}
TiBaseActivity.oldCalendarPermissionCallback = permissionCallback;

TiBaseActivity.registerPermissionRequestCallback(TiC.PERMISSION_CODE_OLD_CALENDAR, permissionCallback, getKrollObject());

Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
currentActivity.requestPermissions(new String[]{Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR}, TiC.PERMISSION_CODE_OLD_CALENDAR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,8 @@ public void requestCalendarPermissions(@Kroll.argument(optional=true)KrollFuncti
if (hasCalendarPermissions()) {
return;
}
if (TiBaseActivity.calendarCallbackContext == null) {
TiBaseActivity.calendarCallbackContext = getKrollObject();
}
TiBaseActivity.calendarPermissionCallback = permissionCallback;

TiBaseActivity.registerPermissionRequestCallback(TiC.PERMISSION_CODE_CALENDAR, permissionCallback, getKrollObject());
Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
currentActivity.requestPermissions(new String[]{Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR}, TiC.PERMISSION_CODE_CALENDAR);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,8 @@ public void requestContactsPermissions(@Kroll.argument(optional=true)KrollFuncti
if (hasContactsPermissions()) {
return;
}
if (TiBaseActivity.contactsCallbackContext == null) {
TiBaseActivity.contactsCallbackContext = getKrollObject();
}
TiBaseActivity.contactsPermissionCallback = permissionCallback;

TiBaseActivity.registerPermissionRequestCallback(TiC.PERMISSION_CODE_CONTACTS, permissionCallback, getKrollObject());
Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
// Requesting for READ_CONTACTS will also enable WRITE_CONTACTS if the permission is set in the manifest.
currentActivity.requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, TiC.PERMISSION_CODE_CONTACTS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,9 @@ public void requestStoragePermissions(@Kroll.argument(optional=true)KrollFunctio
return;
}

if (TiBaseActivity.storageCallbackContext == null) {
TiBaseActivity.storageCallbackContext = getKrollObject();
}
TiBaseActivity.storagePermissionCallback = permissionCallback;
String[] permissions = new String[] {android.Manifest.permission.READ_EXTERNAL_STORAGE};
Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
TiBaseActivity.registerPermissionRequestCallback(TiC.PERMISSION_CODE_EXTERNAL_STORAGE, permissionCallback, getKrollObject());
currentActivity.requestPermissions(permissions, TiC.PERMISSION_CODE_EXTERNAL_STORAGE);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -643,16 +643,14 @@ public void requestLocationPermissions(@Kroll.argument(optional=true) Object typ
return;
}

if (TiBaseActivity.locationCallbackContext == null) {
TiBaseActivity.locationCallbackContext = getKrollObject();
}

KrollFunction permissionCB;
if (type instanceof KrollFunction && permissionCallback == null) {
TiBaseActivity.locationPermissionCallback = (KrollFunction) type;
permissionCB = (KrollFunction) type;
} else {
TiBaseActivity.locationPermissionCallback = permissionCallback;
permissionCB = permissionCallback;
}

TiBaseActivity.registerPermissionRequestCallback(TiC.PERMISSION_CODE_LOCATION, permissionCB, getKrollObject());
Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
currentActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, TiC.PERMISSION_CODE_LOCATION);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,6 @@ public void requestCameraPermissions(@Kroll.argument(optional=true)KrollFunction
return;
}

if (TiBaseActivity.cameraCallbackContext == null) {
TiBaseActivity.cameraCallbackContext = getKrollObject();
}
TiBaseActivity.cameraPermissionCallback = permissionCallback;
String[] permissions = null;
if (!hasCameraPermission() && !hasStoragePermission()) {
permissions = new String[] {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE};
Expand All @@ -365,8 +361,8 @@ public void requestCameraPermissions(@Kroll.argument(optional=true)KrollFunction
} else {
permissions = new String[] {Manifest.permission.READ_EXTERNAL_STORAGE};
}


TiBaseActivity.registerPermissionRequestCallback(TiC.PERMISSION_CODE_CAMERA,permissionCallback, getKrollObject());
Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
currentActivity.requestPermissions(permissions, TiC.PERMISSION_CODE_CAMERA);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
package org.appcelerator.titanium;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.appcelerator.kroll.KrollDict;
Expand Down Expand Up @@ -93,8 +96,33 @@ public abstract class TiBaseActivity extends AppCompatActivity
private TiWeakList<OnPrepareOptionsMenuEvent> onPrepareOptionsMenuListeners = new TiWeakList<OnPrepareOptionsMenuEvent>();
private APSAnalytics analytics = APSAnalytics.getInstance();

public static KrollObject storageCallbackContext, cameraCallbackContext, contactsCallbackContext, oldCalendarCallbackContext, calendarCallbackContext, locationCallbackContext;
public static KrollFunction storagePermissionCallback, cameraPermissionCallback, contactsPermissionCallback, oldCalendarPermissionCallback, calendarPermissionCallback, locationPermissionCallback;

public static class PermissionContextData {
private final Integer requestCode;
private final KrollObject context;
private final KrollFunction callback;

public PermissionContextData(Integer requestCode, KrollFunction callback,
KrollObject context) {
this.requestCode = requestCode;
this.callback = callback;
this.context = context;
}

public Integer getRequestCode() {
return requestCode;
}

public KrollFunction getCallback() {
return callback;
}

public KrollObject getContext() {
return context;
}
}

private static ConcurrentHashMap<Integer,PermissionContextData> callbackDataByPermission = new ConcurrentHashMap<Integer, PermissionContextData>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this cause any memory leaks on Activities (Windows)? Might need to check when using this, when the Window is closed, does the Activity get released by doing Heap dumps.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a check and there was no leak on WindowProxy by opening 10 windows and requesting (and denying) permissions using the code below:-

(function openWindow(n) {
    var win = Ti.UI.createWindow({
        backgroundColor : "#aaaaaa",
        layout : "vertical"
    });

    win.title = "Window # " + n;

    var label = Ti.UI.createLabel({
        text : "Window # " + n,
        color : "#ffffff",
        top : 20
    });

    win.add(label);
    label = null;

    var openButton = Ti.UI.createButton({
        title : "Open",
        color : "#ffffff",
        top : 20,
        _n: n
    });

    openButton.addEventListener('click', function onOpenByButton(evt) {
        openWindow(evt.source._n + 1);
    });

    win.add(openButton);
    openButton = null;

    var closeButton = Ti.UI.createButton({
        title : "Close",
        color : "#ffffff",
        top : 20
    });

    closeButton.addEventListener('click', function onCloseByButton(evt) {
        evt.source.getParent().close();
    });

    win.add(closeButton);

    win.open();
    Ti.Media.requestCameraPermissions(function(e) {
        if (e.success === true) {
                Ti.API.log("Success");
            } else {
                Ti.API.log("Access denied, error: " + e.error);
            }
    });
    win = null;
})(1);

Code is based on https://jira.appcelerator.org/browse/TIMOB-19891.

No leaks seen when hprof was inspected for WindowProxy.


protected View layout;
protected TiActivitySupportHelper supportHelper;
Expand Down Expand Up @@ -421,57 +449,64 @@ protected View createLayout()
return new TiCompositeLayout(this, arrangement, null);
}

private void permissionCallback(int[] grantResults, KrollFunction callback, KrollObject context, String permission) {
if (callback == null) {

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (!callbackDataByPermission.isEmpty()) {
handlePermissionRequestResult(requestCode, permissions, grantResults);
}

}

private void handlePermissionRequestResult(Integer requestCode, String[] permissions, int[] grantResults) {
PermissionContextData cbd = callbackDataByPermission.get(requestCode);
if (cbd == null) {
return;
}
boolean granted = true;

String deniedPermissions = "";
for (int i = 0; i < grantResults.length; ++i) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
granted = false;
break;
if (deniedPermissions.isEmpty()) {
deniedPermissions = permissions[i];
} else {
deniedPermissions = deniedPermissions + ", " + permissions[i];
}
}
}
if (granted) {
KrollDict response = new KrollDict();

KrollDict response = new KrollDict();

if (deniedPermissions.isEmpty()) {
response.putCodeAndMessage(0, null);
callback.callAsync(context, response);
} else {
KrollDict response = new KrollDict();
response.putCodeAndMessage(-1, "One or more permission(s) were denied");
response.putCodeAndMessage(-1, "Permission(s) denied: " + deniedPermissions);
}

KrollFunction callback = cbd.getCallback();
if (callback != null) {
KrollObject context = cbd.getContext();
if (context == null) {
Log.w(TAG, "Permission callback context object is null");
}
callback.callAsync(context, response);
} else {
Log.w(TAG, "Permission callback function has not been set");
}
}

@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case TiC.PERMISSION_CODE_CAMERA: {
permissionCallback(grantResults, cameraPermissionCallback, cameraCallbackContext, "Camera");
return;
}
case TiC.PERMISSION_CODE_OLD_CALENDAR: {
permissionCallback(grantResults, oldCalendarPermissionCallback, oldCalendarCallbackContext, "Calendar");
return;
}
case TiC.PERMISSION_CODE_CALENDAR: {
permissionCallback(grantResults, calendarPermissionCallback, calendarCallbackContext, "Calendar");
return;
}
case TiC.PERMISSION_CODE_LOCATION: {
permissionCallback(grantResults, locationPermissionCallback, locationCallbackContext, "Location");
return;
}
case TiC.PERMISSION_CODE_CONTACTS: {
permissionCallback(grantResults, contactsPermissionCallback, contactsCallbackContext, "Contacts");
return;
}
case TiC.PERMISSION_CODE_EXTERNAL_STORAGE: {
permissionCallback(grantResults, storagePermissionCallback, storageCallbackContext, "Storage");
return;
}

/**
* register permission request result callback for activity
*
* @param requestCode request code (8 Bit) to associate callback with request
* @param callback callback function which receives a KrollDict with success,
* code, optional message and requestCode
* @param context KrollObject as required by async callback pattern
*/
public static void registerPermissionRequestCallback(Integer requestCode, KrollFunction callback, KrollObject context) {
if (callback != null && context != null) {
callbackDataByPermission.put(requestCode, new PermissionContextData(requestCode, callback, context));
}
}

Expand Down