I'm new in Android dev and I'm developing an Android App using Eclipse. I provided a functionality to Synchronize database on Dropbox. To do it, Dropbox give me a key value to use for authentication. This key have to be inserted in AndroidManifest.xml
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:configChanges="orientation|keyboard"
android:launchMode="singleTask" >
<intent-filter>
<!-- Change this to be db- followed by your app key -->
<data android:scheme="db-xxxxxxxxxx" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
But using this logic, the end user will not be able to change this value to synchronize database on his dropbox account, and not on my. I've made a preference screen to store the key in Application Preferences, but I' don't find code where the value is read from Android Manifest. I think it's about here but I'm new and I don't understand how to edit my code:
public void startAuthentication(Context context) {
AppKeyPair appKeyPair = getAppKeyPair();
// Check if the app has set up its manifest properly.
Intent testIntent = new Intent(Intent.ACTION_VIEW);
String scheme = "db-" + appKeyPair.key;
String uri = scheme + "://" + AuthActivity.AUTH_VERSION + "/test";
testIntent.setData(Uri.parse(uri));
PackageManager pm = context.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(testIntent, 0);
if (0 == activities.size()) {
throw new IllegalStateException("URI scheme in your app's " +
"manifest is not set up correctly. You should have a " +
"com.dropbox.client2.android.AuthActivity with the " +
"scheme: " + scheme);
} else if (activities.size() > 1) {
// Check to make sure there's no other app with this scheme.
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Security alert");
builder.setMessage("Another app on your phone may be trying to " +
"pose as the app you are currently using. The malicious " +
"app cannot access your account, but linking to Dropbox " +
"has been disabled as a precaution. Please contact " +
"support#dropbox.com.");
builder.setPositiveButton("OK", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.show();
return;
} else {
// Just one activity registered for the URI scheme. Now make sure
// it's within the same package so when we return from web auth
// we're going back to this app and not some other app.
String authPackage = activities.get(0).activityInfo.packageName;
if (!context.getPackageName().equals(authPackage)) {
throw new IllegalStateException("There must be an " +
"AuthActivity within your app's package registered " +
"for your URI scheme (" + scheme + "). However, it " +
"appears that an activity in a different package is " +
"registered for that scheme instead. If you have " +
"multiple apps that all want to use the same access" +
"token pair, designate one of them to do " +
"authentication and have the other apps launch it " +
"and then retrieve the token pair from it.");
}
}
// Start Dropbox auth activity.
Intent intent = new Intent(context, AuthActivity.class);
intent.putExtra(AuthActivity.EXTRA_INTERNAL_CONSUMER_KEY,
appKeyPair.key);
intent.putExtra(AuthActivity.EXTRA_INTERNAL_CONSUMER_SECRET,
appKeyPair.secret);
if (!(context instanceof Activity)) {
// If starting the intent outside of an Activity, must include
// this. See startActivity(). Otherwise, we prefer to stay in
// the same task.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
Can you help me?
Thank you in advance
I think that you may be misunderstanding what that key is used for. It is not used for choosing which account to sync files with.
The key you want to change is an APP API key. Each user does not need a unique key unless you are targeting at developers who would have their own API keys already. This is used to identify your app and shut it down, among other things, if it's causing trouble for Dropbox.
The specific instance of this key you are trying to edit is what gets control back to your app after a user authenticates with their personal account. This needs to be kept in sync with the key you use for authentication when calling AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
You will not be able to modify the the data tag in that intent filter at runtime.
The object appKeyPair.key contains the key that you want.
I d'ont know what AppKeyPair appKeyPair = getAppKeyPair(); does, but I think you can remove it and put a simple string from the shared preferences instead of calling appKeyPair.key.
Related
I am launching my app from the browser and if the app is not already loaded/running then it launches the app through onCreate and collects the intent.data and does the right thing. If the app is already running then launching the app from the browser bypasses the onCreate and goes right to onResume which I "believe" is expected behavior. But the intent.data associated with the launch from the browser is null. I was hoping that the intent data would be overwritten with the new intent data from scheme url string so that I can relaunch the webview inside the app with the new parameters. Is there some way that I can push this new data into the app when it is launched (i.e., resumed) by the browser?
// JS Browser code with arguments to be passed to the app.
var r = Math.random();
window.open("myScheme://caca.com/?mode=driver" + "&ec=" + ec + "&uh=" + $("#userHandle").val() + "&at=0" + "&random=" + r);
// Xamarin
onResume(...) {
...
try
{
// currentActivity.Intent.Data != null if app is not already running
// is null if already running
Android.Net.Uri data = currentActivity.Intent.Data;
string scheme = data.Scheme;
DebugToast("scheme " + scheme, ToastLength.Long);
if (scheme == "myScheme")
{
// force the cookies so the web app will come up as we specify
SetStorageValue("browserLaunched", "true");
SetStorageValue("mode", data.GetQueryParameter("mode"));
SetStorageValue("ec", data.GetQueryParameter("ec"));
SetStorageValue("uh", data.GetQueryParameter("uh"));
SetStorageValue("authToken", data.GetQueryParameter("at"));
SetStorageValue("at", data.GetQueryParameter("at"));
DebugToast("parms " + data.GetQueryParameter("mode") + " " + data.GetQueryParameter("ec") + " " + data.GetQueryParameter("uh") + " " + data.GetQueryParameter("at"), ToastLength.Long);
// restart the web view with arguments above
...
}
}
catch
{
....
}
}
Homer Simpson D'oh!. Needed to add 'onNewIntent()' to activity which receives the "um er dah" new Intent with the appropriate data attached.
I've got a tricky question here. I need users to make a payment to a bank (namely Barclaycard) in UK. To do so, I have a https URL , I add the parameters (such as amount to pay, order reference, etc) to the URL, start this http connection as an Intent.ActionView, which will redirect the user to the browser where he can enter his credit card details on the bank's webpage and make the payment to our account successfully. So far so good ?
The code I use is below (I changed values for privacy reasons) The problem is, I need to get back to the app when the user has completed/failed/cancelled the payment. Barclaycardautomatically redirects to a particular URL when the payment has succeeded, another one if it failed. Is there no way of knowing when Barclaycard payment has succeeded so that then I would go back to the android app somehow ?
Button cardbutton = (Button) findViewById(R.id.card_button);
cardbutton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
String preHashString = new String();
String proHashString = new String();
String SHAPassPhrase = new String();
SHAPassPhrase = "GSvTh£h70ZkHdAq9b"; // FOR TEST ENVIRONMENT
preHashString = preHashString + "AMOUNT=" + String.valueOf((int) (order.getPaymentAmount() * 100.00)) + SHAPassPhrase;
preHashString = preHashString + "BGCOLOR=cccccc" + SHAPassPhrase;
preHashString = preHashString + "CN=" + user.getString("name") + SHAPassPhrase;
preHashString = preHashString + "CURRENCY=GBP" + SHAPassPhrase;
preHashString = preHashString + "LANGUAGE=en_US" + SHAPassPhrase;
preHashString = preHashString + "ORDERID=" + order.getOrderId() + SHAPassPhrase;
try
{
proHashString = SHA1(preHashString);
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
String redirecturl = "https://mdepayments.epdq.co.uk/ncol/test/orderstandard.asp";
redirecturl += "?AMOUNT=" + String.valueOf((int) (order.getPaymentAmount() * 100));
redirecturl += "&CN=" + user.getString("name");
redirecturl += "&CURRENCY=GBP";
redirecturl += "&LANGUAGE=en_US";
redirecturl += "&ORDERID=" + order.getOrderId();
redirecturl += "&SHASIGN=" + proHashString;
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(redirecturl));
startActivity(i);
}
});
You can have your own Webview in place inside your app, with some done / close button somewhere.. Then you can track all urls getting open in your WebView and do your stuff accordingly..User will stay in your app always..that solves your purpose..
For tracking all urls inside your WebView you need to register one WebViewClient and ovveride below function
public boolean shouldOverrideUrlLoading (WebView view, String url)
Have a look at WebView here and WebViewClient here
You should never be doing such things on user device. Someone can decompile your code and change it, so your app will "think" they made the payment.
This may lead to small problems like they using app for free to severe problems like you being forced to make all the payments.
Either use server-side solution or in-app-purchase from Google.
If your user gets redirected to a new URL you could use a ContentObserver that observes the bookmark history for any changes:
public class UrlObserver extends ContentObserver {
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// check last URL in history
}
}
Reading the history can be done by:
private static final Uri CONTENT_URI = Browser.BOOKMARKS_URI;
Cursor cursor = context.getContentResolver().query(
CONTENT_URI, Browser.HISTORY_PROJECTION, null, null, null);
Registration of the content observer works with:
UrlObserver observer = new UrlObserver();
context.getContentResolver().registerContentObserver(CONTENT_URI, true, observer);
Once a particular URL has been detected, you can invoke an intent to bring your activity back to front.
This is a sample app which might help you in this case.
I'm not 100% sure what happens if the same site is used for the form transmission. It might be that the content observer won't trigger. In that case you might find some useful log entries.
Note: Chrome and the Android standard browser use different URLs for the query. Search the internet to find the right one.
Hope this helps .... Cheers!
I need to authenticate multiple accounts
I have searched the forum, and it seems like it is possible
So I gave it a try, but I failed
I had tried using the same API APP_KEY & APP_SECRET, it failed
Both my session return the same access tokens pair
So I try using different API APP_KEY & APP_SECRET, under same Dropbox account, it failed too
So I try again using different API APP_KEY & APP_SECRET from different Dropbox accounts, it still failed
Anyone can provide me a solution? Thanks in advance
Below is my code, mainly comes from the DBroulette example
onCreate (android)
AndroidAuthSession session = buildSession();
mApi = new DropboxAPI<AndroidAuthSession>(session);
AndroidAuthSession session2 = buildSession2();
mApi2 = new DropboxAPI<AndroidAuthSession>(session2);
onResume (android)
AndroidAuthSession session = mApi.getSession();
if (session.isLinked()) {
dbsetLoggedIn(true);
} else {
dbsetLoggedIn(false);
}
if (session.authenticationSuccessful()) {
try {
session.finishAuthentication();
TokenPair tokens = session.getAccessTokenPair();
dbstoreKeys(tokens.key, tokens.secret);
dbsetLoggedIn(true);
statusTv.append("Dropbox authentication successful\n");
} catch (IllegalStateException e) {
Log.i("Dropbox Error", "Error authenticating", e);
}
}
AndroidAuthSession session2 = mApi2.getSession();
if (session2.isLinked()) {
dbsetLoggedIn2(true);
} else {
dbsetLoggedIn2(false);
}
if (session2.authenticationSuccessful()) {
try {
session2.finishAuthentication();
TokenPair tokens = session2.getAccessTokenPair();
dbstoreKeys2(tokens.key, tokens.secret);
dbsetLoggedIn2(true);
statusTv.append("2Dropbox authentication successful\n");
} catch (IllegalStateException e) {
Log.i("Dropbox Error", "Error authenticating", e);
}
}
OTHERS CODES
private AndroidAuthSession buildSession() {
AppKeyPair appKeyPair = new AppKeyPair(Constants.APP_KEY, Constants.APP_SECRET);
AndroidAuthSession session;
String[] stored = getKeys();
if (stored != null) {
AccessTokenPair accessToken = new AccessTokenPair(stored[0], stored[1]);
session = new AndroidAuthSession(appKeyPair, Constants.ACCESS_TYPE, accessToken);
} else {
session = new AndroidAuthSession(appKeyPair, Constants.ACCESS_TYPE);
}
return session;
}
private AndroidAuthSession buildSession2() {
AppKeyPair appKeyPair = new AppKeyPair(Constants.APP_KEY2, Constants.APP_SECRET2);
AndroidAuthSession session;
String[] stored = getKeys2();
if (stored != null) {
AccessTokenPair accessToken = new AccessTokenPair(stored[0], stored[1]);
session = new AndroidAuthSession(appKeyPair, Constants.ACCESS_TYPE, accessToken);
} else {
session = new AndroidAuthSession(appKeyPair, Constants.ACCESS_TYPE);
}
return session;
}
private String[] getKeys() {
SharedPreferences prefs = getSharedPreferences(Constants.ACCOUNT_PREFS_NAME, 0);
String key = prefs.getString(Constants.ACCESS_KEY_NAME, null);
String secret = prefs.getString(Constants.ACCESS_SECRET_NAME, null);
if (key != null && secret != null) {
String[] ret = new String[2];
ret[0] = key;
ret[1] = secret;
return ret;
} else {
return null;
}
}
private String[] getKeys2() {
SharedPreferences prefs = getSharedPreferences(Constants.ACCOUNT_PREFS_NAME, 0);
String key = prefs.getString(Constants.ACCESS_KEY_NAME2, null);
String secret = prefs.getString(Constants.ACCESS_SECRET_NAME2, null);
if (key != null && secret != null) {
String[] ret = new String[2];
ret[0] = key;
ret[1] = secret;
return ret;
} else {
return null;
}
}
I noticed that I MAYBE need to add something into the manifest in the adding another
BUT I cannot add second activity in android manifest with different APP KEY because it will cause duplicated error
How can I do it?
<activity
android:name="com.dropbox.client2.android.AuthActivity"
android:configChanges="orientation|keyboard"
android:launchMode="singleTask" >
<intent-filter>
<data android:scheme="db-XXXXXXXXXXXX" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I'm not sure if this would help you a little bit in your use case, but maybe it could be a workaround to write your own authenticator to use the Android build-in account management to seperate the authentication processes.
Here is an example: http://udinic.wordpress.com/2013/04/24/write-your-own-android-authenticator/
I ran into a similar requirement and this is how I worked around.
1st App
Get access for your first application using the normal dropbox flow.
Note:
A likely case for 2 dropbox applications requirement could be accessing user account from your server using a different dropbox application. Please note that you can share the access tokens from 1st app with your server and reuse these credentials safely, provided you are using the same dropbox application on server. If you can't live with that, continue reading.
2nd App
Option 1: Using another Android app
Create another Android App just for the oAuth flow for 2nd dropbox app.
Use Intent to trigger oAuthflow in app2 from app1.
Again, use intent to send back token data from app2 to app1
A few tips, if you are going to use this:
Make the background of App2 oAuth Activity transparent
Remove Intent change animations for app1 <-> app2 transitions
Trigger oAuth in App2 Activity's onCreate
Option 2: If you are keep on doing this with only one Android app, I found a possible workaround as described below.
Prompt your user to open this url:
https://www.dropbox.com/1/oauth2/authorize?response_type=code&client_id=APP2_CLIENT_ID
They will have to copy back an authorization code returned by Dropbox
This authorization code can be used to obtain access_tokens for 2nd app
If you are going to use the 2nd app in a server side context, simply share the authorization code with your server. You can obtain tokens from authorization code, in a python flow, like this:
flow = client.DropboxOAuth2FlowNoRedirect(app2_key, app2_secret)
authorize_url = flow.start()
access_token, user_id = flow.finish(auth_code_from_client)
For more generic ways to obtain access_tokens from authorization keys, look at this
Dropbox API is having some issues or you can say a trick that you need to use in order to do multiple logins.
1. Declare sAuthenticatedUid as String[]
private static final String[] sAuthenticatedUid = { "dummy"}; // Keeping only one Auth Id to keep last authenticated item
2. Start OAuth using different method
Use session.startOAuth2Authentication(act, "", sAuthenticatedUid) for authentication instead of startOAuth2Authentication()
3. Maintain Variables on authentication Success
sAuthenticatedUid[0] = sessionApi.getSession().finishAuthentication(); // Save the last successful UID
String oauth2AccessToken = sessionApi.getSession().getOAuth2AccessToken();
AuthActivity.result = null; // Reset this so that we can login again, call only after finishAuthentication()
AuthActivity is com.dropbox.client2.android.AuthActivity which stores the result from last authentication and can create problems as this is static variable.
You should be able to do as many logins as you want now.
I am new to android programming.
I got my app with Gmail account sends emails.
What I need now is how to receive new emails from G mail?
Or at least how to get a notification that there is a new mail in my inbox?
I don't want to use Gmail app from market or embedded email android app or so...I'm making my own app that manages Gmail accounts (like some kind of widget in my own app).
In order to implement this functionality ,first you need to establish the connection with the gmail server,then you need to check the inbox folder for new messages. If find then send the notification to the user using NotificationManager. please follow this links http://www.jondev.net/articles/Sending_Emails_without_User_Intervention_%28no_Intents%29_in_Android and another link is
Sending Email in Android using JavaMail API without using the default/built-in app
Try this:
Properties props = new Properties();
//IMAPS protocol
props.setProperty(“mail.store.protocol”, “imaps”);
//Set host address
props.setProperty(“mail.imaps.host”, imaps.gmail.com);
//Set specified port
props.setProperty(“mail.imaps.port”, “993″);
//Using SSL
props.setProperty(“mail.imaps.socketFactory.class”, “javax.net.ssl.SSLSocketFactory”);
props.setProperty(“mail.imaps.socketFactory.fallback”, “false”);
//Setting IMAP session
Session imapSession = Session.getInstance(props);
Store store = imapSession.getStore(“imaps”);
//Connect to server by sending username and password.
//Example mailServer = imap.gmail.com, username = abc, password = abc
store.connect(mailServer, account.username, account.password);
//Get all mails in Inbox Forlder
inbox = store.getFolder(“Inbox”);
inbox.open(Folder.READ_ONLY);
//Return result to array of message
Message[] result = inbox.getMessages();
You need to first grant permission to "Notification accept " so your app can receive any notifications from device apps.
You need to follow the steps below to enable the "Notification accept" permission:
Setting => Apps => Special access => Notification accept
You need to give your application permission in AndroidManifest.xml:
<service android:name="com.secondclone.UINotificationService"
android:label="#string/app_name_notification"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService"
/>
</intent-filter>
</service>
Then, you write down the conditions to only receive notifications for new email notifications
/* This is the class that helps you receive notifications when there are new emails */
public class UINotificationService extends NotificationListenerService {
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn)
{
// Get notification of new messages of the Gmail app com.google.android.gm
if (sbn.getPackageName().equals("com.google.android.gm"))
{
/* What you need to handle when a new email is here */
Bundle extras = sbn.getNotification().extras;
if (!contentGmail.equals(extras.getCharSequence("android.bigText").toString()))
{
contentGmail = Objects.requireNonNull(extras.getCharSequence("android.bigText")).toString();
// This is the recipient's Gmail name information.
String mreceiver = extras.getString("android.subText");
// This is the sender's name.
String mSender = extras.getString("android.title");
// This is the Email subject.
String mSubject = Objects.requireNonNull(extras.getCharSequence("android.text")).toString();
// This is the text of this new mail.
String mContent = Objects.requireNonNull(extras.getCharSequence("android.bigText")).toString();
//Notification.EXTRA_TEXT
time = sbn.getPostTime() / 1000;
Log.i("tsMail", "Sender = " + mSender + " Receiver= " + receiver + " Content Gmail= " + mContent );
}
}
}
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.i("Msg","Notification Removed");
}
}
I'm making an app that can launch other apps. I've got it launching apps fine using Spinners, however, I would also like to give the user the ability to launch direct dials from it.
As it is right now I've got "hot key" buttons that the user can configure. Currently, when the user wants to configure one of these "hot keys" I use a spinner to let them choose from all the installed applications on their phone. For starters, I would like it if they are able to view both installed applications and shortcuts in the spinner so that they can map a direct dial to one of these "hot keys."
So my main questions are, how can I go about looking up all the defined shortcuts available and execute them and how could I create my own direct dials in my app?
To dial a number directly
startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + NUMBER)));
here is a simple function for this
public static void go2Call(Context context, String phoneNo) {
Intent intent = null;
Uri destUri = null;
/*
* http://developer.android.com/guide/appendix/g-app-intents.html
<uses-permission id="android.permission.CALL_PHONE" />
tel: phone_number
*/
if(DEBUG)Log.d(TAG, "go2Call ->" + "phoneNo:"+phoneNo);
phoneNo = PhoneNumberUtils.convertKeypadLettersToDigits(phoneNo);
if(DEBUG)Log.d(TAG, "go2Call ->" + "phoneNo(normalized):"+phoneNo);
if ( !TextUtils.isEmpty(phoneNo) ) {
destUri = Uri.parse("tel:" + phoneNo);
}
if (destUri!=null) {
intent = new Intent( Intent.ACTION_VIEW, destUri );
}
if ( intent!=null && isIntentAvailable(context, intent) ) {
context.startActivity(intent);
}
else {
// TODO: display error msg
Log.w(TAG, "error pr intent not available! ->" + "phoneNo:"+phoneNo);
}
}