Search in sources :

Example 1 with CallbackContext

use of org.apache.cordova.CallbackContext in project cordova-android by apache.

the class MessageChannelMultipageTest method testThatCachedCallbackIdIsValid.

//test that after a page load the cached callback id and the live callback id match
//this is to prevent a regression
//the issue was that CordovaWebViewImpl's cached instance of CoreAndroid would become stale on page load
//this is because the cached instance was not being cleared when the pluginManager was reset on page load
//the plugin manager would get a new instance which would be updated with a new callback id
//the cached instance's message channel callback id would become stale
//effectively this caused message channel events to not be delivered
@Test
public void testThatCachedCallbackIdIsValid() throws Throwable {
    final CordovaWebView cordovaWebView = testActivity.getWebInterface();
    Class cordovaWebViewImpl = CordovaWebViewImpl.class;
    //send a test event - this initializes cordovaWebViewImpl.appPlugin (the cached instance of CoreAndroid)
    Method method = cordovaWebViewImpl.getDeclaredMethod("sendJavascriptEvent", String.class);
    method.setAccessible(true);
    method.invoke(cordovaWebView, "testEvent");
    sleep(1000);
    //load a page - this resets the plugin manager and nulls cordovaWebViewImpl.appPlugin
    //(previously this resets plugin manager but did not null cordovaWebViewImpl.appPlugin, leading to the issue)
    mActivityRule.runOnUiThread(new Runnable() {

        public void run() {
            cordovaWebView.loadUrl(START_URL);
        }
    });
    assertEquals(START_URL, testActivity.onPageFinishedUrl.take());
    //send a test event - this initializes cordovaWebViewImpl.appPlugin (the cached instance of CoreAndroid)
    method.invoke(cordovaWebView, "testEvent");
    sleep(1000);
    //get reference to package protected class CoreAndroid
    Class coreAndroid = Class.forName("org.apache.cordova.CoreAndroid");
    //get cached CoreAndroid
    Field appPluginField = cordovaWebViewImpl.getDeclaredField("appPlugin");
    appPluginField.setAccessible(true);
    Object cachedAppPlugin = appPluginField.get(cordovaWebView);
    //get cached CallbackContext
    Field messageChannelField = coreAndroid.getDeclaredField("messageChannel");
    messageChannelField.setAccessible(true);
    CallbackContext cachedCallbackContext = (CallbackContext) messageChannelField.get(cachedAppPlugin);
    //get live CoreAndroid
    PluginManager pluginManager = cordovaWebView.getPluginManager();
    Field coreAndroidPluginNameField = coreAndroid.getField("PLUGIN_NAME");
    String coreAndroidPluginName = (String) coreAndroidPluginNameField.get(null);
    Object liveAppPlugin = pluginManager.getPlugin(coreAndroidPluginName);
    //get live CallbackContext
    CallbackContext liveCallbackContext = (CallbackContext) messageChannelField.get(liveAppPlugin);
    //get callback id from live callbackcontext
    String liveCallbackId = (liveCallbackContext != null) ? liveCallbackContext.getCallbackId() : null;
    //get callback id from cached callbackcontext
    String cachedCallbackId = (cachedCallbackContext != null) ? cachedCallbackContext.getCallbackId() : null;
    //verify that the live message channel has been initialized
    assertNotNull(liveCallbackId);
    //verify that the cached message channel and the live message channel have the same id
    assertEquals(liveCallbackId, cachedCallbackId);
}
Also used : PluginManager(org.apache.cordova.PluginManager) Field(java.lang.reflect.Field) CallbackContext(org.apache.cordova.CallbackContext) CordovaWebView(org.apache.cordova.CordovaWebView) Method(java.lang.reflect.Method) CordovaWebViewImpl(org.apache.cordova.CordovaWebViewImpl) Test(org.junit.Test)

Example 2 with CallbackContext

use of org.apache.cordova.CallbackContext in project phonegap-facebook-plugin by Wizcorp.

the class PluginManager method execHelper.

private void execHelper(final String service, final String action, final String callbackId, final String rawArgs) {
    CordovaPlugin plugin = getPlugin(service);
    if (plugin == null) {
        Log.d(TAG, "exec() call to unknown plugin: " + service);
        PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
        app.sendPluginResult(cr, callbackId);
        return;
    }
    try {
        CallbackContext callbackContext = new CallbackContext(callbackId, app);
        long pluginStartTime = System.currentTimeMillis();
        boolean wasValidAction = plugin.execute(action, rawArgs, callbackContext);
        long duration = System.currentTimeMillis() - pluginStartTime;
        if (duration > SLOW_EXEC_WARNING_THRESHOLD) {
            Log.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool().");
        }
        if (!wasValidAction) {
            PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION);
            app.sendPluginResult(cr, callbackId);
        }
    } catch (JSONException e) {
        PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
        app.sendPluginResult(cr, callbackId);
    }
}
Also used : PluginResult(org.apache.cordova.PluginResult) CordovaPlugin(org.apache.cordova.CordovaPlugin) CallbackContext(org.apache.cordova.CallbackContext) JSONException(org.json.JSONException)

Example 3 with CallbackContext

use of org.apache.cordova.CallbackContext in project phonegap-facebook-plugin by Wizcorp.

the class ConnectPlugin method execute.

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    if (action.equals("login")) {
        Log.d(TAG, "login FB");
        // Get the permissions
        String[] arrayPermissions = new String[args.length()];
        for (int i = 0; i < args.length(); i++) {
            arrayPermissions[i] = args.getString(i);
        }
        List<String> permissions = null;
        if (arrayPermissions.length > 0) {
            permissions = Arrays.asList(arrayPermissions);
        }
        // Get the currently active session
        Session session = Session.getActiveSession();
        // Set a pending callback to cordova
        loginContext = callbackContext;
        PluginResult pr = new PluginResult(PluginResult.Status.NO_RESULT);
        pr.setKeepCallback(true);
        loginContext.sendPluginResult(pr);
        // Check if the active session is open
        if (checkActiveSession(session)) {
            // Reauthorize flow
            boolean publishPermissions = false;
            boolean readPermissions = false;
            // Figure out if this will be a read or publish reauthorize
            if (permissions == null) {
                // No permissions, read
                readPermissions = true;
            }
            // is being requested
            for (String permission : arrayPermissions) {
                if (isPublishPermission(permission)) {
                    publishPermissions = true;
                } else {
                    readPermissions = true;
                }
                // Break if we have a mixed bag, as this is an error
                if (publishPermissions && readPermissions) {
                    break;
                }
            }
            if (publishPermissions && readPermissions) {
                callbackContext.error("Cannot ask for both read and publish permissions.");
            } else {
                // Set up the new permissions request
                Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(cordova.getActivity(), permissions);
                // Set up the activity result callback to this class
                cordova.setActivityResultCallback(this);
                // Check for write permissions, the default is read (empty)
                if (publishPermissions) {
                    // Request new publish permissions
                    session.requestNewPublishPermissions(newPermissionsRequest);
                } else {
                    // Request new read permissions
                    session.requestNewReadPermissions(newPermissionsRequest);
                }
            }
        } else {
            // Initial login, build a new session open request.
            // - Create a new session and set the application ID
            session = new Session.Builder(cordova.getActivity()).setApplicationId(applicationId).build();
            // Set up the activity result callback to this class
            cordova.setActivityResultCallback(this);
            Session.setActiveSession(session);
            // - Create the request
            Session.OpenRequest openRequest = new Session.OpenRequest(cordova.getActivity());
            // - Set the permissions
            openRequest.setPermissions(permissions);
            // - Set the status change call back
            openRequest.setCallback(new Session.StatusCallback() {

                @Override
                public void call(Session session, SessionState state, Exception exception) {
                    onSessionStateChange(state, exception);
                }
            });
            // Can only ask for read permissions initially
            session.openForRead(openRequest);
        }
        return true;
    } else if (action.equals("logout")) {
        Session session = Session.getActiveSession();
        if (checkActiveSession(session)) {
            session.closeAndClearTokenInformation();
            userID = null;
            callbackContext.success();
        } else {
            if (session != null) {
                // Session was existing, but was not open
                callbackContext.error("Session not open.");
            } else {
                callbackContext.error("No valid session found, must call init and login before logout.");
            }
        }
        return true;
    } else if (action.equals("getLoginStatus")) {
        Session session = Session.getActiveSession();
        if (userID == null && Session.getActiveSession() != null && session.isOpened()) {
            // We have no userID but a valid session, so must update the user info
            // (Probably app was force stopped)
            final CallbackContext _callbackContext = callbackContext;
            getUserInfo(session, new GraphUserCallback() {

                @Override
                public void onCompleted(GraphUser user, Response response) {
                    // recursive call to generate the correct response JSON
                    if (response.getError() != null) {
                        _callbackContext.error(getFacebookRequestErrorResponse(response.getError()));
                    } else {
                        userID = user.getId();
                        _callbackContext.success(getResponse());
                    }
                }
            });
        } else {
            callbackContext.success(getResponse());
        }
        return true;
    } else if (action.equals("getAccessToken")) {
        Session session = Session.getActiveSession();
        if (checkActiveSession(session)) {
            callbackContext.success(session.getAccessToken());
        } else {
            if (session == null) {
                callbackContext.error("No valid session found, must call init and login before logout.");
            } else {
                // Session not open
                callbackContext.error("Session not open.");
            }
        }
        return true;
    } else if (action.equals("logEvent")) {
        if (args.length() == 0) {
            // Not enough parameters
            callbackContext.error("Invalid arguments");
            return true;
        }
        String eventName = args.getString(0);
        if (args.length() == 1) {
            logger.logEvent(eventName);
        } else {
            // Arguments is greater than 1
            JSONObject params = args.getJSONObject(1);
            Bundle parameters = new Bundle();
            Iterator<?> iterator = params.keys();
            while (iterator.hasNext()) {
                try {
                    // Try get a String
                    String key = (String) iterator.next();
                    String value = params.getString(key);
                    parameters.putString(key, value);
                } catch (Exception e) {
                    // Maybe it was an int
                    Log.w(TAG, "Type in AppEvent parameters was not String for key: " + (String) iterator.next());
                    try {
                        String key = (String) iterator.next();
                        int value = params.getInt(key);
                        parameters.putInt(key, value);
                    } catch (Exception e2) {
                        // Nope
                        Log.e(TAG, "Unsupported type in AppEvent parameters for key: " + (String) iterator.next());
                    }
                }
            }
            if (args.length() == 2) {
                logger.logEvent(eventName, parameters);
            }
            if (args.length() == 3) {
                double value = args.getDouble(2);
                logger.logEvent(eventName, value, parameters);
            }
        }
        callbackContext.success();
        return true;
    } else if (action.equals("logPurchase")) {
        /*
             * While calls to logEvent can be made to register purchase events,
             * there is a helper method that explicitly takes a currency indicator.
             */
        if (args.length() != 2) {
            callbackContext.error("Invalid arguments");
            return true;
        }
        int value = args.getInt(0);
        String currency = args.getString(1);
        logger.logPurchase(BigDecimal.valueOf(value), Currency.getInstance(currency));
        callbackContext.success();
        return true;
    } else if (action.equals("showDialog")) {
        Bundle collect = new Bundle();
        JSONObject params = null;
        try {
            params = args.getJSONObject(0);
        } catch (JSONException e) {
            params = new JSONObject();
        }
        final ConnectPlugin me = this;
        Iterator<?> iter = params.keys();
        while (iter.hasNext()) {
            String key = (String) iter.next();
            if (key.equals("method")) {
                try {
                    this.method = params.getString(key);
                } catch (JSONException e) {
                    Log.w(TAG, "Nonstring method parameter provided to dialog");
                }
            } else {
                try {
                    collect.putString(key, params.getString(key));
                } catch (JSONException e) {
                    // Need to handle JSON parameters
                    Log.w(TAG, "Nonstring parameter provided to dialog discarded");
                }
            }
        }
        this.paramBundle = new Bundle(collect);
        //The Share dialog prompts a person to publish an individual story or an Open Graph story to their timeline.
        //This does not require Facebook Login or any extended permissions, so it is the easiest way to enable sharing on web.
        boolean isShareDialog = this.method.equalsIgnoreCase("share") || this.method.equalsIgnoreCase("share_open_graph");
        //If is a Share dialog but FB app is not installed the WebDialog Builder fails. 
        //In Android all WebDialogs require a not null Session object.
        boolean canPresentShareDialog = isShareDialog && (FacebookDialog.canPresentShareDialog(me.cordova.getActivity(), FacebookDialog.ShareDialogFeature.SHARE_DIALOG));
        //Must be an active session when is not a Shared dialog or if the Share dialog cannot be presented.
        boolean requiresAnActiveSession = (!isShareDialog) || (!canPresentShareDialog);
        if (requiresAnActiveSession) {
            Session session = Session.getActiveSession();
            if (!checkActiveSession(session)) {
                callbackContext.error("No active session");
                return true;
            }
        }
        // Begin by sending a callback pending notice to Cordova
        showDialogContext = callbackContext;
        PluginResult pr = new PluginResult(PluginResult.Status.NO_RESULT);
        pr.setKeepCallback(true);
        showDialogContext.sendPluginResult(pr);
        // Setup callback context
        final OnCompleteListener dialogCallback = new OnCompleteListener() {

            @Override
            public void onComplete(Bundle values, FacebookException exception) {
                if (exception != null) {
                    handleError(exception, showDialogContext);
                } else {
                    handleSuccess(values);
                }
            }
        };
        if (this.method.equalsIgnoreCase("feed")) {
            Runnable runnable = new Runnable() {

                public void run() {
                    WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(me.cordova.getActivity(), Session.getActiveSession(), paramBundle)).setOnCompleteListener(dialogCallback).build();
                    feedDialog.show();
                }
            };
            cordova.getActivity().runOnUiThread(runnable);
        } else if (this.method.equalsIgnoreCase("apprequests")) {
            Runnable runnable = new Runnable() {

                public void run() {
                    WebDialog requestsDialog = (new WebDialog.RequestsDialogBuilder(me.cordova.getActivity(), Session.getActiveSession(), paramBundle)).setOnCompleteListener(dialogCallback).build();
                    requestsDialog.show();
                }
            };
            cordova.getActivity().runOnUiThread(runnable);
        } else if (isShareDialog) {
            if (canPresentShareDialog) {
                Runnable runnable = new Runnable() {

                    public void run() {
                        // Publish the post using the Share Dialog
                        FacebookDialog shareDialog = new FacebookDialog.ShareDialogBuilder(me.cordova.getActivity()).setName(paramBundle.getString("name")).setCaption(paramBundle.getString("caption")).setDescription(paramBundle.getString("description")).setLink(paramBundle.getString("href")).setPicture(paramBundle.getString("picture")).build();
                        uiHelper.trackPendingDialogCall(shareDialog.present());
                    }
                };
                this.trackingPendingCall = true;
                cordova.getActivity().runOnUiThread(runnable);
            } else {
                // Fallback. For example, publish the post using the Feed Dialog
                Runnable runnable = new Runnable() {

                    public void run() {
                        WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(me.cordova.getActivity(), Session.getActiveSession(), paramBundle)).setOnCompleteListener(dialogCallback).build();
                        feedDialog.show();
                    }
                };
                cordova.getActivity().runOnUiThread(runnable);
            }
        } else if (this.method.equalsIgnoreCase("send")) {
            Runnable runnable = new Runnable() {

                public void run() {
                    FacebookDialog.MessageDialogBuilder builder = new FacebookDialog.MessageDialogBuilder(me.cordova.getActivity());
                    if (paramBundle.containsKey("link"))
                        builder.setLink(paramBundle.getString("link"));
                    if (paramBundle.containsKey("caption"))
                        builder.setCaption(paramBundle.getString("caption"));
                    if (paramBundle.containsKey("name"))
                        builder.setName(paramBundle.getString("name"));
                    if (paramBundle.containsKey("picture"))
                        builder.setPicture(paramBundle.getString("picture"));
                    if (paramBundle.containsKey("description"))
                        builder.setDescription(paramBundle.getString("description"));
                    // Check for native FB Messenger application
                    if (builder.canPresent()) {
                        FacebookDialog dialog = builder.build();
                        dialog.present();
                    } else {
                        // Not found
                        trackingPendingCall = false;
                        String errMsg = "Messaging unavailable.";
                        Log.e(TAG, errMsg);
                        showDialogContext.error(errMsg);
                    }
                }

                ;
            };
            this.trackingPendingCall = true;
            cordova.getActivity().runOnUiThread(runnable);
        } else {
            callbackContext.error("Unsupported dialog method.");
        }
        return true;
    } else if (action.equals("graphApi")) {
        graphContext = callbackContext;
        PluginResult pr = new PluginResult(PluginResult.Status.NO_RESULT);
        pr.setKeepCallback(true);
        graphContext.sendPluginResult(pr);
        graphPath = args.getString(0);
        JSONArray arr = args.getJSONArray(1);
        final List<String> permissionsList = new ArrayList<String>();
        for (int i = 0; i < arr.length(); i++) {
            permissionsList.add(arr.getString(i));
        }
        boolean publishPermissions = false;
        boolean readPermissions = false;
        if (permissionsList.size() > 0) {
            for (String permission : permissionsList) {
                if (isPublishPermission(permission)) {
                    publishPermissions = true;
                } else {
                    readPermissions = true;
                }
                // Break if we have a mixed bag, as this is an error
                if (publishPermissions && readPermissions) {
                    break;
                }
            }
            if (publishPermissions && readPermissions) {
                graphContext.error("Cannot ask for both read and publish permissions.");
            } else {
                Session session = Session.getActiveSession();
                if (session.getPermissions().containsAll(permissionsList)) {
                    makeGraphCall();
                } else {
                    // Set up the new permissions request
                    Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(cordova.getActivity(), permissionsList);
                    // Set up the activity result callback to this class
                    cordova.setActivityResultCallback(this);
                    // Check for write permissions, the default is read (empty)
                    if (publishPermissions) {
                        // Request new publish permissions
                        session.requestNewPublishPermissions(newPermissionsRequest);
                    } else {
                        // Request new read permissions
                        session.requestNewReadPermissions(newPermissionsRequest);
                    }
                }
            }
        } else {
            makeGraphCall();
        }
        return true;
    }
    return false;
}
Also used : SessionState(com.facebook.SessionState) PluginResult(org.apache.cordova.PluginResult) GraphUserCallback(com.facebook.Request.GraphUserCallback) FacebookDialog(com.facebook.widget.FacebookDialog) FacebookException(com.facebook.FacebookException) CallbackContext(org.apache.cordova.CallbackContext) ArrayList(java.util.ArrayList) List(java.util.List) GraphUser(com.facebook.model.GraphUser) Bundle(android.os.Bundle) WebDialog(com.facebook.widget.WebDialog) JSONArray(org.json.JSONArray) JSONException(org.json.JSONException) FacebookOperationCanceledException(com.facebook.FacebookOperationCanceledException) JSONException(org.json.JSONException) FacebookServiceException(com.facebook.FacebookServiceException) FacebookException(com.facebook.FacebookException) FacebookDialogException(com.facebook.FacebookDialogException) FacebookAuthorizationException(com.facebook.FacebookAuthorizationException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) Response(com.facebook.Response) OnCompleteListener(com.facebook.widget.WebDialog.OnCompleteListener) JSONObject(org.json.JSONObject) Session(com.facebook.Session)

Example 4 with CallbackContext

use of org.apache.cordova.CallbackContext in project jpHolo by teusink.

the class BatteryListener method execute.

/**
     * Executes the request.
     *
     * @param action        	The action to execute.
     * @param args          	JSONArry of arguments for the plugin.
     * @param callbackContext 	The callback context used when calling back into JavaScript.
     * @return              	True if the action was valid, false if not.
     */
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
    if (action.equals("start")) {
        if (this.batteryCallbackContext != null) {
            callbackContext.error("Battery listener already running.");
            return true;
        }
        this.batteryCallbackContext = callbackContext;
        // We need to listen to power events to update battery status
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        if (this.receiver == null) {
            this.receiver = new BroadcastReceiver() {

                @Override
                public void onReceive(Context context, Intent intent) {
                    updateBatteryInfo(intent);
                }
            };
            cordova.getActivity().registerReceiver(this.receiver, intentFilter);
        }
        // Don't return any result now, since status results will be sent when events come in from broadcast receiver
        PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
        pluginResult.setKeepCallback(true);
        callbackContext.sendPluginResult(pluginResult);
        return true;
    } else if (action.equals("stop")) {
        removeBatteryListener();
        // release status callback in JS side
        this.sendUpdate(new JSONObject(), false);
        this.batteryCallbackContext = null;
        callbackContext.success();
        return true;
    }
    return false;
}
Also used : Context(android.content.Context) CallbackContext(org.apache.cordova.CallbackContext) IntentFilter(android.content.IntentFilter) PluginResult(org.apache.cordova.PluginResult) JSONObject(org.json.JSONObject) Intent(android.content.Intent) BroadcastReceiver(android.content.BroadcastReceiver)

Aggregations

CallbackContext (org.apache.cordova.CallbackContext)4 PluginResult (org.apache.cordova.PluginResult)3 JSONException (org.json.JSONException)2 JSONObject (org.json.JSONObject)2 BroadcastReceiver (android.content.BroadcastReceiver)1 Context (android.content.Context)1 Intent (android.content.Intent)1 IntentFilter (android.content.IntentFilter)1 Bundle (android.os.Bundle)1 FacebookAuthorizationException (com.facebook.FacebookAuthorizationException)1 FacebookDialogException (com.facebook.FacebookDialogException)1 FacebookException (com.facebook.FacebookException)1 FacebookOperationCanceledException (com.facebook.FacebookOperationCanceledException)1 FacebookServiceException (com.facebook.FacebookServiceException)1 GraphUserCallback (com.facebook.Request.GraphUserCallback)1 Response (com.facebook.Response)1 Session (com.facebook.Session)1 SessionState (com.facebook.SessionState)1 GraphUser (com.facebook.model.GraphUser)1 FacebookDialog (com.facebook.widget.FacebookDialog)1