Intent for app details page - android

My app relies heavily on a database for data and sometimes the database won't copy correctly, gets corrupted, or just throws a generic strop. Clearing the app data and then reopening the app seems to work well, but it's quite a chore to ask my users to dig through the settings pages, and I'm looking for a way to quickly get to the app details page (which shows the uninstall, move to SD, clear data etc.)
I've found the Settings.ACTION_APPLICATION_DETAILS_SETTINGS Intent action but get an ActivityNotFoundException when I try to launch it as described on my Desire Z. Can anyone help me out how to properly sort this?
Thanks
EDIT: As noted in the answers, this is only API9 and above, the code I now use if anyone wants it is below. Believe it works on API3 and above.
try {
Intent i = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:com.espian.formulae"));
startActivity(i);
} catch (ActivityNotFoundException ex) {
Intent i = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(i);
}

I know that this is way too late answer but it may help someone. Based on the platform (froyo) source I make one function that opens a specific package's settings page. It works in the emulator but I never tried on a real device. I don't know if it works on API < 8 either.
Here it is:
public boolean startFroyoInstalledAppDetailsActivity(String packagename) {
boolean result = false;
Intent i = new Intent();
i.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
i.setAction(Intent.ACTION_VIEW);
i.putExtra("pkg", packagename);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
cx.startActivity(i);
result = true;
} catch (Exception ex) {
result = false;
}
return result;
}
Based on your code I also make a Gingerbread version which works on real devices with API levels 9, 10, 11, 12, 13, 14 and 15 but it can be called safely from API 8 however in this case it will return false.
Here it is:
public boolean startGingerbreadInstalledAppDetailsActivity(String packagename) {
boolean result = false;
Intent i = new Intent();
i.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + packagename));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
cx.startActivity(i);
result = true;
} catch (Exception ex) {
result = false;
}
return result;
}

I'll post it as answer here in addition to my comment. That intent is only available as of API Level 9 (2.3). The Desire Z doesn't have 2.3... yet. ;)

Related

Looking up version and forcing an update in xamarin

There are many posts about doing this in java, but I found that NSoup (the port of the JSoup library) doesn't work for me, so I failed to port it to c#/Xamarin. For multiplayer functions of a game I'm working on, I need to make sure clients are synced before starting multiplayer matchmaking. This means I have to force the user to update the app if there's a new version available before they're allowed to invite other players to matches, join quick matches, etc..
So when a user presses the "quick match" button, for example, I need to:
Check for the version name (im incrementing version name, not code, for breaking changes)
Compare the version name from that to the current version name installed
3.
-If the newer version name is greater than the current one, I need to give the user the option to update their app, and send them to the google play store page for my app if they choose 'yes'. Then I'll just let them update from there and our work is done.
-If the versions are the same, allow whatever the button's functionality (i.e sending them to the waiting room for matchmaking) to proceed.
Create the methods necessary to check for updates and act accordingly:
private void CheckUpdate(Action doIfUpToDate)
{
if(NeedUpdate())
{
Android.App.AlertDialog.Builder alert = new Android.App.AlertDialog.Builder(this);
alert.SetTitle("New Update");
alert.SetMessage("You must download the newest version of this to play multiplayer. Would you like to now?");
alert.SetCancelable(false);
alert.SetPositiveButton("Yes", new EventHandler<DialogClickEventArgs>((object sender, DialogClickEventArgs e) => GetUpdate()));
alert.SetNegativeButton("No", delegate{});
alert.Show();
}
else
{
doIfUpToDate.Invoke();
}
}
private bool NeedUpdate()
{
try
{
var curVersion = PackageManager.GetPackageInfo(PackageName, 0).VersionName;
var newVersion = curVersion;
string htmlCode;
//probably better to do in a background thread
using (WebClient client = new WebClient())
{
htmlCode = client.DownloadString("https://play.google.com/store/apps/details?id=" + PackageName + "&hl=en");
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlCode);
newVersion = doc.DocumentNode.SelectNodes("//div[#itemprop='softwareVersion']")
.Select(p => p.InnerText)
.ToList()
.First()
.Trim();
return String.Compare(curVersion, newVersion) < 0;
}
catch (Exception e)
{
Log.Error(TAG, e.Message);
Toast.MakeText(this, "Trouble validating app version for multiplayer gameplay.. Check your internet connection", ToastLength.Long).Show();
return true;
}
}
private void GetUpdate()
{
try
{
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + PackageName)));
}
catch (ActivityNotFoundException e)
{
//Default to the the actual web page in case google play store app is not installed
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("https://play.google.com/store/apps/details?id=" + PackageName)));
}
}
And then from a given button that could start a multiplayer game:
var quickMatchButton = FindViewById<Button>(Resource.Id.button_quick_game);
quickMatchButton.Click += new EventHandler((object sender, EventArgs e) => CheckUpdate(() => startQuickMatch()));

Integrating and working with .pkpass passes in Xamarin Android app

I'm developing a Xamarin Android app and I need the ability to be able to work with Passes (PassKit passes for example (JSON)). I need to be able to list all the passes in a ListVew and be able to open and display the pass. Also be able to save them to a wallet such as PassWallet or Pass2u. I don't need the ability to create them, just view them, and save them to a wallet or discard them.
There seems to be an example Xamarin iOS app which does exactly what i need here but of course I need to be able to do this in Xamarin Android.
I've been researching this for hours but don't know how to achieve what i need. JSON.net seems the way to go to read the passes, but that's as far as I've managed to get. Some examples would be great. Can anybody help?
To add the pass into PassWallet you can use the following:
private static boolean launchPassWallet(Context applicationContext, Uri uri, boolean launchGooglePlay) {
if (null != applicationContext) {
PackageManager packageManager = applicationContext.getPackageManager();
if (null != packageManager) {
final String strPackageName = "com.attidomobile.passwallet";
Intent startIntent = new Intent();
startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startIntent.setAction(Intent.ACTION_VIEW);
Intent passWalletLaunchIntent = packageManager
.getLaunchIntentForPackage(strPackageName);
if (null == passWalletLaunchIntent) {
// PassWallet isn't installed, open Google Play:
if (launchGooglePlay) {
String strReferrer = "";
try {
strReferrer = "&referrer=" + URLEncoder.encode(uri.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
strReferrer = "";
}
try {
startIntent.setData(Uri.parse("market://details?id=" + strPackageName + strReferrer));
applicationContext.startActivity(startIntent);
} catch (android.content.ActivityNotFoundException anfe) {
// Google Play not installed, open via website
startIntent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + strPackageName + strReferrer));
applicationContext.startActivity(startIntent);
}
}
} else {
final String strClassName = "com.attidomobile.passwallet.activity.TicketDetailActivity";
startIntent.setClassName(strPackageName, strClassName);
startIntent.addCategory(Intent.CATEGORY_BROWSABLE);
startIntent.setDataAndType(uri, "application/vnd.apple.pkpass");
applicationContext.startActivity(startIntent);
return true;
}
}
}
return false;
}
And an example call is:
launchPassWallet(getApplicationContext(),Uri.parse("http://test.attidomobile.com/PassWallet/Passes/AttidoMobile.pkpass"), true);
You can also use a file:// URL if you have the file locally.
To display them in the list, you'd need to unzip the .pkpass file and then parse the JSON for the relevant fields.

Sending a String result to a website

I'm rather new to Android Dev and I'm stuck at the very last part of my app. I've made a barcode scanning app (thanks Zxing) and would like to search the result on a website.
So for example if I wanted to search my result on www.trademe.co.nz how would I go about doing this?
So far I've gotten the String and opened the browser I just don't know how to import the text into the right textbox and search it.
The web part of my code.
private void openBrowser(String contents, String format) {
Intent i = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.trademe.co.nz"));
startActivity(i);
}
Sorry if I've done something wrong, this is my first post!
Thanks is advanced for any help :)
Try this (and mark this as an answer if my answer solve your problem)
private void openBrowser(String contents, String format) {
String url = "http://www.trademe.co.nz/Browse/SearchResults.aspx?searchType=all&searchString=%s&rptpath=all&type=Search&generalSearch_keypresses=5&generalSearch_suggested=0";
try
{
your_keyword = URLEncoder.encode(your_keyword, "UTF-8")); //encode keyword
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
url = String.format(url, your_keyword);
Intent i = new Intent(Intent.ACTION_VIEW,
Uri.parse(url));
startActivity(i);
}
Use httpPost method to post your string to the url.
Check
here
Also see a simple example here

Intent extras only work on some devices

In my app I send some intent extras from one activity to another. But some users report back that these data are always zero - even though I can see the values are alright in the sending activity.
Here's the code of the sending activity:
Intent intent = new Intent();
intent.setClass(waypointListView.this, addWaypointActivity.class);
intent.putExtra("latitude", String.format("%9.6f", globLatitude));
intent.putExtra("longitude", String.format("%9.6f", globLongitude));
startActivityForResult(intent, ACTIVITY_ADD_WAYPOINT);
And this is how it's read in the new activity:
Intent myIntent = getIntent();
String latitudeStr = myIntent.getExtras().getString("latitude");
try{
globLatitude = Float.parseFloat(latitudeStr);
} catch(NumberFormatException nfe) {
globLatitude=0f;
}
String longitudeStr = myIntent.getExtras().getString("longitude");
try{
globLongitude = Float.parseFloat(longitudeStr);
} catch(NumberFormatException nfe) {
globLongitude=0f;
}
On both my devices it works fine, but I have 3 cases of customers complaining that it doesn't work (documented in video recordings).
Any suggestions?
I tried to change the code to use getFloatExtra() instead of getString and parse it to a float, and it solved the problem. I see this is a lot more efficient, but I still don't understand why the original solution worked on some devices but not on others.
Case closed!

How to use Intent.ACTION_APP_ERROR as a means for a "feedback" framework in Android?

I would like to reuse the Intent.ACTION_BUG_REPORT in my app, as a simple means of getting user feedback.
Google Maps uses it as their "Feedback" option. But I've not been successful in firing the event.
I'm using the following in a onOptionsItemSelected(MenuItem item):
Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
startActivity(intent);
And in my AndroidManifest.xml I've declared the following under my Activity:
<intent-filter>
<action android:name="android.intent.action.BUG_REPORT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
However, nothing seems to happen besides the screen "blink" when I select the option. The App or intent doesn't crash, it doesn't log anything. Tried it both in the Emulator and on an ICS 4.0.4 device.
I'm clealy missing something, but what?
Edit
Intent.ACTION_APP_ERROR (constant android.intent.action.BUG_REPORT) was added in API level 14, http://developer.android.com/reference/android/content/Intent.html#ACTION_APP_ERROR
This was solved with the help from the link in #TomTasche comment above. Use built-in feedback mechanism on Android.
In my AndroidManifest.xml I added the following to the <Activity> where I want to call the Feedback agent from.
<intent-filter>
<action android:name="android.intent.action.APP_ERROR" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
And I made a simple method called sendFeedback() (code from TomTasche blogpost)
#SuppressWarnings("unused")
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void sendFeedback() {
try {
int i = 3 / 0;
} catch (Exception e) {
ApplicationErrorReport report = new ApplicationErrorReport();
report.packageName = report.processName = getApplication().getPackageName();
report.time = System.currentTimeMillis();
report.type = ApplicationErrorReport.TYPE_CRASH;
report.systemApp = false;
ApplicationErrorReport.CrashInfo crash = new ApplicationErrorReport.CrashInfo();
crash.exceptionClassName = e.getClass().getSimpleName();
crash.exceptionMessage = e.getMessage();
StringWriter writer = new StringWriter();
PrintWriter printer = new PrintWriter(writer);
e.printStackTrace(printer);
crash.stackTrace = writer.toString();
StackTraceElement stack = e.getStackTrace()[0];
crash.throwClassName = stack.getClassName();
crash.throwFileName = stack.getFileName();
crash.throwLineNumber = stack.getLineNumber();
crash.throwMethodName = stack.getMethodName();
report.crashInfo = crash;
Intent intent = new Intent(Intent.ACTION_APP_ERROR);
intent.putExtra(Intent.EXTRA_BUG_REPORT, report);
startActivity(intent);
}
}
And from my SettingsActivity I call it like:
findPreference(sFeedbackKey).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public final boolean onPreferenceClick(Preference paramAnonymousPreference) {
sendFeedback();
finish();
return true;
}
});
Verified working with Android 2.3.7 and 4.2.2.
When the sendFeedback() method is called, a "Complete action using"-dialog is opened where the user can select from three actions/icons.
The calling app, which returns to the app, and Google Play and the Feedback agent. Selecting either Google Play Storeor Send feedback will open the built-in Android feedback agent as intended.
I haven't investigated further if it's possible to skip the "Complete action using"-step, it's probably possible with the correct parameters passed to the Intent. So far, this does exactly what I wanted for now.
Please don't mix two different intents Intent.ACTION_BUG_REPORT and Intent.ACTION_APP_ERROR. The first one is designed for old error reporting and feedback and it's supported from API v1. The second one is for sending advanced error reports (supports ApplicationErrorReport object where you can store a lot of useful informations) and was added in API v14.
For sending feedback, I am testing bellow code in my new version of APP (it also create a screenshot of the activity). This starts com.google.android.gms.feedback.FeedbackActivity, which is part of Google Play services. But question is where then I'll find the feedbacks?!
protected void sendFeedback(Activity activity) {
activity.bindService(new Intent(Intent.ACTION_BUG_REPORT), new FeedbackServiceConnection(activity.getWindow()), BIND_AUTO_CREATE);
}
protected static class FeedbackServiceConnection implements ServiceConnection {
private static int MAX_WIDTH = 600;
private static int MAX_HEIGHT = 600;
protected final Window mWindow;
public FeedbackServiceConnection(Window window) {
this.mWindow = window;
}
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Parcel parcel = Parcel.obtain();
Bitmap bitmap = getScreenshot();
if (bitmap != null) {
bitmap.writeToParcel(parcel, 0);
}
service.transact(IBinder.FIRST_CALL_TRANSACTION, parcel, null, 0);
parcel.recycle();
} catch (RemoteException e) {
Log.e("ServiceConn", e.getMessage(), e);
}
}
public void onServiceDisconnected(ComponentName name) { }
private Bitmap getScreenshot() {
try {
View rootView = mWindow.getDecorView().getRootView();
rootView.setDrawingCacheEnabled(true);
Bitmap bitmap = rootView.getDrawingCache();
if (bitmap != null)
{
double height = bitmap.getHeight();
double width = bitmap.getWidth();
double ratio = Math.min(MAX_WIDTH / width, MAX_HEIGHT / height);
return Bitmap.createScaledBitmap(bitmap, (int)Math.round(width * ratio), (int)Math.round(height * ratio), true);
}
} catch (Exception e) {
Log.e("Screenshoter", "Error getting current screenshot: ", e);
}
return null;
}
}
Do note that the crash report solution (as in here) is not available on pre-ICS versions of Android.
A shorter, simpler version of the solution of "kaderud" (here) :
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void sendFeedback()
{
final Intent intent=new Intent(Intent.ACTION_APP_ERROR);
final ApplicationErrorReport report=new ApplicationErrorReport();
report.packageName=report.processName=getApplication().getPackageName();
report.time=System.currentTimeMillis();
report.type=ApplicationErrorReport.TYPE_NONE;
intent.putExtra(Intent.EXTRA_BUG_REPORT,report);
final PackageManager pm=getPackageManager();
final List<ResolveInfo> resolveInfos=pm.queryIntentActivities(intent,0);
if(resolveInfos!=null&&!resolveInfos.isEmpty())
{
for(final ResolveInfo resolveInfo : resolveInfos)
{
final String packageName=resolveInfo.activityInfo.packageName;
// prefer google play app for sending the feedback:
if("com.android.vending".equals(packageName))
{
// intent.setPackage(packageName);
intent.setClassName(packageName,resolveInfo.activityInfo.name);
break;
}
}
startActivity(intent);
}
else
{
// handle the case of not being able to send feedback
}
}
Starting with API level 14 you can try to use the ACTION_APP_ERROR intent but the app needs to be available on Google Play store for this to work.
Intent intent = new Intent(Intent.ACTION_APP_ERROR);
startActivity(intent);
//must be available on play store

Categories

Resources