How to make an Android app that depends on another app? - android

If I create an app that depends on another app or apps (eg: the Facebook and Twitter apps), yet they are not installed, is there a method of checking for those dependencies and installing them at the same time as my own app?

I did this in my application which requires the zxing scanner app to be installed.
You will want this inside your onclick or ontouch:
try{
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.setPackage("com.google.zxing.client.android");
startActivityForResult(intent, 0);
} catch (Exception e) {
createAlert("Barcode Scanner not installed!", "This application uses " +
"the open source barcode scanner by ZXing Team, you need to install " +
"this before you can use this software!", true);
}
which calls
public void createAlert(String title, String message, Boolean button) {
// http://androidideasblog.blogspot.com/2010/02/how-to-add-messagebox-in-android.html
AlertDialog alertDialog;
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle(title);
alertDialog.setMessage(message);
if ((button == true)) {
alertDialog.setButton("Download Now",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
Intent browserIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:com.google.zxing.client.android"));
startActivity(browserIntent);
}
});
}
alertDialog.show();
}
Then after sorting out all that code out I realise you asked for it to be installed at the same time as your app. Not sure if i should post this code, but it may be helpful

Short answer: No, you cannot automatically install other applications as dependencies.
Longer answer:
Android Market does not let you declare other applications to install as a dependency. As a system, Market appears to be designed for single application installs -- not Linux distro style mega dependency graphs.
At runtime, you can test for installed apps and punt your user over to the Market if so. See the techniques suggested by #QuickNick (testing if an app is installed) and #TerryProbert (punting to market) if that's what you want.
Your best bet is probably to design your app to gracefully degrade if dependencies are not available, and suggest (or insist) that they head over to market to install them.

Start from this:
Intent mediaIntent = new Intent("com.example.intent.action.NAME");
// add needed categories
List<ResolveInfo> listResolveInfo = getPackageManager().queryIntentServices(mediaIntent, 0);
if (listResolveInfo.size() != 0) {
//normal behavior
} else {
//install what you need
}
I give you example of querying services. If you want to check activities, then you will call queryIntentActivities().

I think following the pattern outlined in this post on the Android Developer Blog will help you.
http://android-developers.blogspot.com/2009/01/can-i-use-this-intent.html
As TerryProbert points out if you know that the Intent is not available prompt the user to install the missing app.

Here's what I use to return the first mission activity that exists:
try {
Class<?> missionClass = Class.forName(mPackageName+".Mission"+mission);
Method missionDescription;
missionDescription = missionClass.getMethod("missionDescription");
mMissionDescription = (String) missionDescription.invoke(null);
if (mMissionDescription.length() > 0) {
nextMission = mission;
break;
}
} catch (Exception e) {
//DEBUG*/Log.v(this.getClass().getName(), "onResume: Mission no "+mission+" not found: "+e.getMessage());
}
Each mission is held in a separate class, derived from a Mission base class. Derived classes are called Mission1, Mission24 etc.
Not all missions are defined.
The base class has an abstract class missionDescription which returns a string describing the mission.
This code is inside a loop so tests mission=1 to 99, trying to call missionDescription. It returns when the Description for the first mission found is returned.

Related

Send data from unity app to android app on button press

I have two apps one is android java app and other is unity app
Unity app recognize the object and shows some details. What i want to do is if user clicks the button which is shown when the object is identified, i want to send that information to the java android app so that the app can use that data to perform certain functions. How can i send the data and switch from unity to java android app after user clicks the button?
EDIT: For any one looking for the answer. I manage to do it by the code below
IN UNITY APP:
public void LaunchAppMessage()
{
string bundleId = "com.example.sidenavtest";
bool fail = false;
string message = "message";
AndroidJavaClass up = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject ca = up.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject packageManager = ca.Call<AndroidJavaObject>("getPackageManager");
AndroidJavaObject launchIntent = null;
try
{
launchIntent = packageManager.Call<AndroidJavaObject>("getLaunchIntentForPackage", bundleId);
launchIntent.Call<AndroidJavaObject>("putExtra", "arguments", message);
}
catch (System.Exception e)
{
fail = true;
}
if (fail)
{
Application.OpenURL("https://google.com");
}
else
{
ca.Call("startActivity", launchIntent);
}
up.Dispose();
ca.Dispose();
packageManager.Dispose();
launchIntent.Dispose();
}
IN ANDROID APP
#Override
protected void onStart() {
super.onStart();
Bundle extras = getIntent().getExtras();
String userName;
if (extras != null) {
userName = extras.getString("arguments");
}
}
If i understand you correctly you want to have both applications on the same device.
Simplest way would be to save the data ino a file in the unity application and read from that file in the android application. But i think you can even attach data on application calls so that you dont even need to save it temporarily.
Opening the Android app from Unity is possible aswell. Here someone asked the same question and got some working answer.
Edit: From what i can gather you can transfer your data via intents, it seem's like most people work with JAR-Plugin from where you can make a intent call.

Auto download offline speech recognition language on Android

Is there any way in Java to detect if an Android device has an offline speech recognition language installed, and if it does not prompt the user to download it?
I know you can ask to speech to text to prefer offline speech to text, but how do you know if the device has the language installed?
This question is not on how to use offline speech, this works.
The question is "how to detect and download/install offline speech languages" from Java app code. i.e. have the app detect if they have offline German language installed, and if not prompt the user to download/install it.
This is not the answer you are hoping for, as at the time of writing, I don't believe there is a straight forward solution to this. I very much hope to be proved wrong.
I requested an enhancement to provide this information programmatically a long time ago - here
The enhancement suggested an additional parameter RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES:
It would surely be trivial for this to be added and used in the following way:
final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final ArrayList<String> vrStringLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
// This would be nice
final ArrayList<String> vrStringOfflineLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES);
}
}, null, 1234, null, null);
Alas, it has never happened.
You do have two other options to attempt to handle this gracefully.
In the unlikely event you application runs with root permissions, you can check the location of /data/data/com.google.android.googlequicksearchbox/app_g3_models/ which contains the offline files, labelled quite handily by their locale.
The second involves knowing when the user needs a prompt to install the missing offline files.
From my experience, the recognition error of SpeechRecognizer.ERROR_SERVER most often denotes this, but it is not foolproof.
#Override
public void onError(final int error) {
switch (error) {
case SpeechRecognizer.ERROR_SERVER:
// TODO - prompt to install offline files
break;
}
}
When detected, you can guide the user to the correct installation screen.
public static final String PACKAGE_NAME_GOOGLE_NOW = "com.google.android.googlequicksearchbox";
public static final String ACTIVITY_INSTALL_OFFLINE_FILES = "com.google.android.voicesearch.greco3.languagepack.InstallActivity";
public static boolean showInstallOfflineVoiceFiles(#NonNull final Context ctx) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(PACKAGE_NAME_GOOGLE_NOW, ACTIVITY_INSTALL_OFFLINE_FILES));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
ctx.startActivity(intent);
return true;
} catch (final ActivityNotFoundException e) {
} catch (final Exception e) {
}
return false;
}
Using hard-coded values such as this, is of course not ideal, but neither is this situation!
Once you've messed around with all of the above and think you have a good interim solution - think again! Regardless of whether the user has correctly installed the missing offline files, it is highly likely it still won't work.....
My answer here describes the process I still have to guide my user's with. It's very frustrating.
Finally one more bug to throw into the mix - RecognitionListener.onError(int) can be thrown when there isn't an error. Check my gist from the answer here to use a BugRecognitionListener so you can check the callbacks are being sent in the correct order and ignore those that aren't. This remains a problem, despite my answer suggesting a fix in a previous release.
The above should keep you busy! Good luck....
To detect whether needed Language(German) is available, please follow below :
Iterate the Locale list and check whether Locale available for German language.
If you didn't get any Locale object in return, you can conclude that German language is not available offline. Then you can write code to download and do other stuff.
I did below implementation for my project. Hope below code helps you !!!
private TextToSpeech t1;
private void setForOtherLangAudio() {
Locale[] locales = Locale.getAvailableLocales();
Locale loc = null;
for (Locale locale : locales) {
// Replace XXX with your German codes
if (locale.getDisplayCountry().equals("XXX") && locale.getDisplayLanguage().equals("XXX")) {
loc = locale ;
break;
}
}
final Locale germanLocale = loc;
t1 = new TextToSpeech(getContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
t1.setLanguage(germanLocale);
}
}
});
}

Force app to update when new version of app is available in android play store

I had an app on the playstore. Know what I want is when new update is available on playstore the user should get a popup to update the app when he try to use the app. And if he does not update the app it should close the app. Ex: I want to force the user to update the app to continue using.
As far as I know Google Play doesn't provide with any kind of API for this, so you would have to manually check.
But I can tell you a method to force user to update with the latest release.
One way is by sending a push notification to the user, and when you receive the notification you redirect user to the playstore.
Second Method is longer but this is a proper sure method.
You make a webservice on a server, which stores the latest version of the app.
whenever your apps runs,
on MainActivity you make a post a request to the webservice and check if the version in the app is latest or not
If it is not the latest version, on the response of the webservice you can redirect user to the playstore
You shouldn't need to force an update directly, the Play store will actually automatically update your application for users when you push updates out. Users don't have to take any action unless you've made changes to your permissions.
I would definitely recommend letting the Play store do its thing on its own... but I did do similar in one app.
Something like this should tell you the play store update dates and version:
SimpleDateFormat formatter = Dates.getSimpleDateFormat(ctx, "dd MMMM yyyy");
String playUrl = "https://play.google.com/store/apps/details?id=" + appPackageName;
RestClient restClient = /* Some kind of rest client */
try {
String playData = restClient.getAsString(playUrl);
String versionRaw = findPattern(playData, "<([^>]?)*softwareVersion([^>]?)*>([^<]?)*<([^>]?)*>");
String updateRaw = findPattern(playData, "<([^>]?)*datePublished([^>]?)*>([^<]?)*<([^>]?)*>");
Date updated = formatter.parse(updateRaw.replaceAll("<[^>]*>", "").trim());
String version = versionRaw.replaceAll("<[^>]*>", "").trim();
_currentStatus = new PlayStatus(version, updated, new Date());
} catch (Exception e) {
_currentStatus = new PlayStatus(PlayStatus.UNKNOWN_VERSION, new Date(0), new Date(0));
}
My PlayStatus class had a method like the following:
public boolean hasUpdate() {
int localVersion = 0;
int playVersion = 0;
if (! versionString.equals(UNKNOWN_VERSION)) {
localVersion = Integer.parseInt(BuildConfig.VERSION_NAME.replace(".",""));
playVersion = Integer.parseInt(versionString.replace(".",""));
}
return (playVersion > localVersion);
}
You can't update the app directly obviously, but if you determine the version is out of date you can present an Intent to the user that will take them to the Play Store:
public static void updateApp(final Activity act) {
final String appPackageName = BuildConfig.APPLICATION_ID;
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder
.setTitle(act.getString(R.string.dialog_title_update_app))
.setMessage(act.getString(R.string.dialog_google_credentials_message))
.setNegativeButton(act.getString(R.string.dialog_default_cancel), null)
.setPositiveButton(act.getString(R.string.dialog_got_it), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
try {
act.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (ActivityNotFoundException anfe) {
act.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName;)));
}
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
I believe this was compiled against API 21, so there might be a couple small tweaks for 22.
I just wrote a class that helps you to know when there is a new version of your app published on Google Play Store.
With the class, you will be able to implement something really simple like this:
new CheckNewAppVersion(yourContext).setOnTaskCompleteListener(new CheckNewAppVersion.ITaskComplete() {
#Override
public void onTaskComplete(CheckNewAppVersion.Result result) {
//Checks if there is a new version available on Google PlayStore.
result.hasNewVersion();
//Get the new published version code of the app.
result.getNewVersionCode();
//Get the app current version code.
result.getOldVersionCode();
//Opens the Google Play Store on your app page to do the update.
result.openUpdateLink();
}
}).execute();
You can download the class here and use in your project.
Basically, you use Jsoup lib to get o actual version published by making a request to Google Play Store page.
Get the versionnumber and versioncode from manifest programatically like:
String versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
or
int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
Strore them in your app by shared preference.Now whenever the user open the app check the current versionCode with the previous one.If they match,then let the user to use the app.But if they dont match then show a pop up to ask the user to update your app.

Message Dialog "No connectivity" etc. in Glass Activity

I have found a similar question, but I want something different.
I noticed that, when you don't have any connectivity, and you try to start Speech Recognition in an app, say through the RecognizerIntent class, you get a "no network connectivity - tap to view connectivity status" (see attached image), and if you click, a new Card with connectivity status appears.
How can I copy this behaviour in my own Activity, using the GDK?
EDIT: here is my code to call the Speech Recognition:
Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
if (speechIntent.resolveActivity(getPackageManager()) != null) {
speechIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Talk to set your title:");
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
Log.d(TAG, "Starting to record speech title");
startActivityForResult(speechIntent, Constants.SPEECH_TITLE_REQUEST_CODE);
}
Ok, I later found an answer to my problem. I'm using the MessageDialog class provided by pif
Here is how I am calling the card:
MessageDialog localDialog = new MessageDialog.Builder(context)
.setMessage("No network connectivity")
.setSecondaryMessage("Tap to view connection settings")
.setIcon(R.drawable.ic_cloud_sad_medium)
.setIsError(true)
.setDismissable(true)
.setAutoHide(false)
.setExpanded(true)
.setShowProgress(false)
.setIsManual(false)
.setListener(new MessageDialog.SimpleListener() {
public boolean onConfirmed() {
Log.d(TAG+"_noConnDialog", "onConfirm");
return true;
}
public void onDismissed() {
Log.d(TAG+"_noConnDialog", "onDismissed");
((Activity)context).finish();
}
public void onDone() {
Log.d(TAG+"_noConnDialog", "onDone");
Intent localIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
localIntent.putExtra("settings_id", 0);
context.startActivity(localIntent);
((Activity)context).finish();
}
}).build();
localDialog.show();
Notice that, as indicated in pif's disclaimer,
This is just for educational purposes and should not be used in any production apps until Google releases something similar officially.
I hope, Google will publish a set of Google Glass Views in the future releases of GDK. We really need them! Especially that awesome progress bar!
AFAIK the Glass Developer Team has not released these functionalities in the GDK yet.

Android starting an activity with Intent.ACTION_INSTALL_PACKAGE and extra return result does not return

I am trying to do programmatic update to the application I am writing, since it is not a Google Play application and I want to provide a way to do updates.
I've been searching around and found out how to start the Android installer after I download the APK for the update, but I need to get a result from the installer, that tells me if the update succeeded or not, or if it was cancelled by the user.
I saw a bunch of questions on StackOverflow about this, and the answers usually involved using a broadcast receiver. The problem with that is that it can only receive intents about the package being installed, not about canceled installs of fails.
I did some more research and it seems the Intent API provides some extras such as Intent.EXTRA_RETURN_RESULT, which if set to true should return a result from the installer activity - I guess via onActivityResult. Unfortunately this doesn't work. Is there anybody that got this working/does it work like this?
Here is the code preparing the installer activity start, that I currently have:
Intent installApp = new Intent(Intent.ACTION_INSTALL_PACKAGE);
installApp.setData(downloadedApk);
installApp.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
installApp.putExtra(Intent.EXTRA_RETURN_RESULT, true);
installApp.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, context.getApplicationInfo().packageName);
context.startActivityForResult(installApp, 1);
Do you use Fragments? The onActivityResult will be called from the Activity or Fragment you have called startActivity(...). Fragment#startActivity(...) does exist. Use it to get the Fragment's onActivityResult(...) called.
If you are not using Fragments, this Workaround will work.
Workaround Pseudocode
// CURRENT_VERSION is a const with the current APK version as int
Activity#onStart() {
super.onStart();
checkForUpdaterResult();
/*...*/
}
Activity#checkForUpdaterResult() {
final int updateVersion = preferences.getInt(UPDATE_VERSION, -1);
switch(updateVersion) {
case -1:break;
default:
// updateVersion = oldVersion is smaller than the new currentVersion
boolean success = updateVersion < CURRENT_VERSION;
onUpdaterPerformed(success, updateVersion , CURRENT_VERSION);
break;
}
}
Activity#startUpdate(File pAPK) {
perferences.putInt(UPDATE_VERSION, CURRENT_VERSION);
/*...*/
}
Activity#onUpdaterPerformed(boolean pSuccess, int pFromVersion, int pToVersion) {
Toast.show("Update success: " + pSuccess);
/* e.g. migrate DB */
/*...*/
}

Categories

Resources