I have an item in my navigation drawer called "share app" which users can use to share application link to other users.
My question is, can i get the link without first uploading to google play. I don't intend to re-upload my app in other to apply this functionality.
I have tried searching for this answer without any meaningful solution.
try {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_SUBJECT, "My application name");
String sAux = "\nLet me recommend you this application\n\n";
sAux = sAux + "https://play.google.com/store/apps/details?id=com.app.ben.example \n\n";
i.putExtra(Intent.EXTRA_TEXT, sAux);
startActivity(Intent.createChooser(i, "choose one"));
} catch(Exception e) {
e.toString();
}
Play store links are deterministic. Your link should look like this :
https://play.google.com/store/apps/details?id=packagename
Edit
To know your package name, search for package in manifest tag : https://developer.android.com/guide/topics/manifest/manifest-element.html
Related
I am very noob in Android studio Java apps. so please bear with me on this.
So I would like to save some text data to a .txt file and then share this Text file on a click of a button as attachment for an Email.
I think there are two ways of doing this:
1- Send the .txt file as attachment per email in the background of the activity/App or whatever it is called.
for that way I have already found the SendGmail and I don't know the available stuff in Internet and so on and made Gmail account less secure and stuff but as a noob it just did not work for me so if you can provide me with step-by-step salutation it will be great (it would really really help me if you don't miss out any step even if small and understandable,... thanks in advance)
2- Promote the user to send the Email by using the Intent stuff in android studio java language.
for that according also to the search I have done we need to use the FileProvider service (if I am allowed to call it like that) from the Android Studion Java language.
for that I did the following:
I Added the Stuff need to be added in the AndroidManifest.xml as following:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.XXXX.YYYY"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
and then I created the file_paths.xml file here please support me as I don't exactly know what and how to do it correctly:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="/storage/emulated/0" path="."/>
</paths>
And now I think I am ready to Save The Text data to a .txt file using this function:
filepath = "AppData";
// in side the on create method i added this permission stuff
ActivityCompat.requestPermissions(MainActivity.this, new String[]{READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE},PackageManager.PERMISSION_GRANTED);
// of course in the Manifest i also added the user request for Eternal Storage saving stuff
private String SaveToExternal(String fileContent) {
if (!fileContent.equals("")) {
File myExternalFile = new File(getExternalFilesDir(filepath), "DataToSend.txt");
String Out = getExternalFilesDir(filepath) + File.separator + "DataToSeve.txt";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(myExternalFile);
fos.write(fileContent.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
return "Unable to save";
} catch (IOException e) {
e.printStackTrace();
return "Unable to save";
}
Toast.makeText(MainActivity.this,"Data to send is prepared and ready",Toast.LENGTH_SHORT).show();
//return Out;
return myExternalFile.getPath();
} else {
Toast.makeText(MainActivity.this,"Data to send is not available",Toast.LENGTH_SHORT).show();
return "Unable to save";
}
}
here if you can provide me with more information on how really to select where to save what it will be great (sorry for asking too much)
now the .txt file is there I just need to attach it and send it per Email of the App user: I used the following Code for that:
private void sendEmail(String Body, String FilePath) {
// Toast.makeText(MainActivity.this, "Your Email Body is: " + Body,Toast.LENGTH_LONG).show();
try {
// First copy the File from internal to External storage:
// File dst = new File(StringPath);
// exportFile(new File(FilePath), dst);
// Then Share it now
// This one was working:
Uri Pathtosend = FileProvider.getUriForFile(MainActivity.this,"com.example.XXXX.YYYY",new File(FilePath));
Toast.makeText(MainActivity.this,"Your Uri is: " + Pathtosend,Toast.LENGTH_LONG).show();
TTba.setText(Pathtosend.toString());
Intent intent = new Intent(Intent.ACTION_SENDTO)
//.setType("message/rfc822")
//.setType("text/plain")
.setType("*/*")
.setData(new Uri.Builder().scheme("mailto").build())
.putExtra(Intent.EXTRA_EMAIL, new String[]{"XXXX YYYY <XYZ#gmail.com>"})
.putExtra(Intent.EXTRA_SUBJECT, "Email subject")
.putExtra(Intent.EXTRA_TEXT, "Dear Sir/Madem" + System.getProperty("line.separator") + System.getProperty("line.separator") + "I would like to ......")
.putExtra(Intent.EXTRA_STREAM, Pathtosend)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
Intent chooser = Intent.createChooser(intent, "Send email with");
List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
grantUriPermission(packageName, Pathtosend, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
try {
// Toast.makeText(MainActivity.this,"I am at the try of send Email",Toast.LENGTH_LONG).show();
startActivity(chooser);
} catch(android.content.ActivityNotFoundException ex) {
Toast.makeText(MainActivity.this, "I am at the Catch of send Email", Toast.LENGTH_LONG).show();
ComponentName emailApp = intent.resolveActivity(getPackageManager());
ComponentName unsupportedAction = ComponentName.unflattenFromString("com.android.fallback/.Fallback");
Toast.makeText(MainActivity.this, "Results of ComponentName: " + emailApp, Toast.LENGTH_LONG).show();
if (emailApp != null && !emailApp.equals(unsupportedAction))
try {
// Needed to customise the chooser dialog title since it might default to "Share with"
// Note that the chooser will still be skipped if only one app is matched
Intent chooser1 = Intent.createChooser(intent, "Send email with");
startActivity(chooser1);
return;
} catch (ActivityNotFoundException ignored) {
}
Toast
.makeText(this, "Couldn't find an email app and account", Toast.LENGTH_LONG)
.show();
}
}catch(android.content.ActivityNotFoundException ex){
Toast.makeText(MainActivity.this,"Unable to create Pathtosend",Toast.LENGTH_LONG).show();
}
}
So after I have those two I can call it when the button is clicked and so on like this:
rv = "Testing stuff that need to be saved to Text file and then attached";
DataPathFile = SaveToExternal(rv);
sendEmail(rv,DataPathFile);
so guy now comes the problem with this method I am using. it is working on the Emulator and SAMUSNG with Android version 8.0.0 but not working on my SAMSUNG with Android version 11.
in my build.gradle i have:
defaultConfig {
applicationId "com.example.XXXX"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
I think the problem is with where the file is saved and how to know the exact path of the file and how to dynamically update the file path in xml or java or wherever it should be updated.
Thanks a lot for your help and support :)
I'm going nuts with this error. As far as I can see I've followed the instructions correctly. My scopes are YOUTUBE_FORCE_SSL. In desperation I've tried to add all Google Plus Scopes without luck. Still get the same error, both in the device, emulator and Google Api Explorer. The video I try to comment on are public. I have a Google+ profile and are signed in with it when I try to make a comment.
This is the full error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "youtube.commentThread",
"location" : "Authorization",
"locationType" : "header",
"message" : "The callers YouTube account is not connected to Google+.",
"reason" : "ineligibleAccount"
} ],
"message" : "The callers YouTube account is not connected to Google+."
}
This is my code:
try {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("part", "snippet");
CommentThread commentThread = new CommentThread();
CommentThreadSnippet snippet = new CommentThreadSnippet();
Comment topLevelComment = new Comment();
CommentSnippet commentSnippet = new CommentSnippet();
commentSnippet.set("textOriginal", textComment);
commentSnippet.set("channelId", channelId);
commentSnippet.set("videoId", ytId);
topLevelComment.setSnippet(commentSnippet);
snippet.setTopLevelComment(topLevelComment);
commentThread.setSnippet(snippet);
YouTube.CommentThreads.Insert commentThreadsInsertRequest = mService.commentThreads().insert(parameters.get("part"), commentThread);
CommentThread response = commentThreadsInsertRequest.execute();
Log.i("COMMENT:", response.toString());
}
Adding screenshot from Api Explorer:
Can you get CommentThreads: insert to work with the API Explorer? If so, how?
I have seen the answers to a similar question here and they don't solve this problem.
Any help is appreciated.
Edit 1
After further testing. Everything works fine with an old account I have. I've tried to see which settings could be different, so far without luck.
This also works if I switch to a YouTube brand account.
The problem remains, it don't work for all Google Accounts, not even when they're also Google+ accounts. The error seems to imply that the request is not made from a Google+ Account. Would be great if Google could clarify the exact reason.
Also, is it possible to programmatically make an account eligible to make a comment, after asking the permission from the account owner? How?
Edit 2
According to this page the reason for the error is this:
The YouTube account used to authorize the API request must be merged
with the user's Google account to insert a comment or comment thread.
How can this be done within the app?
Edit 3
I guess the answer can be found here. You're not able to comment without a YouTube Channel.
The problem is that you're not able to comment unless you have a private YouTube Channel or are logged in with your Brand Account. Using the model to login that Google gave in the instructions don't allow login with Brand Accounts, they're not visible in the account picker.
The result is that you're able to login with an account that have YouTube Brand Accounts, but you will not be able to comment using that accountand since you're not able to pick a Brand Account there is no way to solve this unless you ask users to also create a private Channel. The error message should say something like this:
The callers YouTube account is not a YouTube Channel Account.
If you have created a new account and if you haven't commented on any of the youtube videos, then it throws the error: "The callers YouTube account is not connected to Google+."
Solution: Atleast manually comment in any of the youtube videos using the new account and then try the API. It works smoothly.
Since you can't post comments without a private YouTube Channel(see edits above) the solution would look something like this. If you can find a better one, please submit!
1) Catch the Error. Give Alert with instructions.
2) Launch a Webview with this URL: https://m.youtube.com/create_channel?chromeless=1&next=/channel_creation_done
3) Monitor the Webview and determine when the URL change to the following: https://m.youtube.com/channel_creation_done. The URL indicates that a channel has been created.
4) Close the Webview and resend the authorized API request.
The URLs above were found here but the error code to catch is not the same as on that page. You should catch a 403 with "reason" : "ineligibleAccount".
Update June 29th, 2018
I got back to this issue today and got it working in an acceptable way. See my implementation below:
1. Catch the error 403 after user posted comment without YouTube Channel
if(mLastError.getMessage().contains("403") && mLastError.getMessage().contains("ineligibleAccount")) {
// Show Alert with instruction
showAlertCreate("Please Create a YouTube Channel!", "You need a personal YouTube Channel linked to your Google Account before you can comment. Don't worry, it's easy to create one!\n\n1) Tap on CREATE below and wait for page to load.\n\n2) Login if needed.\n\n3) Tap CREATE CHANNEL and wait until comment is posted.");
}
Code for Alert:
public void showAlertCreate(String title, String description) {
AlertDialog.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
} else {
builder = new AlertDialog.Builder(this);
}
builder.setTitle(title)
.setMessage(description)
.setPositiveButton(R.string.yes_create, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Start Youtube WebView to create Channel
Intent intent = new Intent(mContext, WebViewActivity.class);
startActivityForResult(intent, 777);
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
2. When user tap CREATE in Alert, open this WebView
Notice this code to start Intent in alert above:
// Start Youtube WebView to create Channel
Intent intent = new Intent(mContext, WebViewActivity.class);
startActivityForResult(intent, 777);
XML for WebView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WebViewActivity">
<WebView
android:id="#+id/create_channel"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
Code for WebView:
public class WebViewActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
WebView createChannel = findViewById(R.id.create_channel);
createChannel.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
if (url!=null && url.contains("https://m.youtube.com/channel_creation_done")) {
view.setVisibility(View.INVISIBLE);
//Log.i("URLWEB", url);
Intent intent = new Intent();
intent.putExtra("created", "yes");
setResult(RESULT_OK, intent);
finish();
}
}
});
createChannel.loadUrl("https://m.youtube.com/create_channel?chromeless=1&next=/channel_creation_done");
}
}
3. Catch when user completed Create Channel step in your activity
In onActivityResult() include something like this:
if (requestCode == 777) {
if(resultCode == RESULT_OK) {
// Receive intent from WebView, if new Channel, repost comment/reply
String created = data.getStringExtra("created");
if(created.equals("yes")) {
// Posting the comment again
getResultsFromApi();
}
}
}
Not the cleanest solution but it works.
I have this code working well on Android 4.0.4.
// Create the new Intent using the 'Send' action.
Intent share = new Intent(Intent.ACTION_SEND);
// Set the MIME type
share.setType(type);
// Create the URI from the media
java.io.File media = new java.io.File(mediaPath);
Uri uri = Uri.fromFile(media);
// Add the URI and the caption to the Intent.
share.putExtra(Intent.EXTRA_STREAM, uri);
share.putExtra(Intent.EXTRA_TEXT, caption);
// Broadcast the Intent.
mActivity.startActivity(Intent.createChooser(share, "Share to"));
But on Android 4.4.2 it crashes the Facebook app. Facebook app opens, the image is not shown and the FB app is dead.
In log dump I've noticed this message:
E/JHEAD ( 5850): can't open '/data/data/cz.volten.brili.android.free/files/product_preview_shared.jpg'
V/ContextImpl( 5850): ----- packageName = com.facebook.katana is NOT LOCKED -----
Could the reason be some security restrictions, e.g. The FB app does not have rights to access the image in the application folder even though it is invoked from an intent?
If so, what would be a proper location for an image shared between the apps?
Shall I use something like this: how to share image to facebook via intent
Could the reason be some security restrictions, e.g. The FB app does not have rights to access the image in the application folder even though it is invoked from an intent?
Correct. That image is on internal storage for your app, which is private to your app.
If so, what would be a proper location for an image shared between the apps?
You can stick with internal storage, though you will need to use a FileProvider, perhaps with my LegacyCompatCursorWrapper, to serve the file. This sample app demonstrates this, albeit with a PDF rather than an image.
Or, put the file on external storage.
Shall I use something like this: how to share image to facebook via intent
You could, though that would seem to be overkill, compared to using FileProvider.
This is what I usually use
private void initShareIntent(String type) {
boolean found = false;
Intent share = new Intent(android.content.Intent.ACTION_SEND);
share.setType("image/jpeg");
// gets the list of intents that can be loaded.
List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(share, 0);
if (!resInfo.isEmpty()) {
for (ResolveInfo info : resInfo) {
if (info.activityInfo.packageName.toLowerCase().contains(type) ||
info.activityInfo.name.toLowerCase().contains(type)) {
share.putExtra(Intent.EXTRA_TEXT, "Elevator Express");
share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(imagePath))); // Optional, just if you wanna share an image.
share.setPackage(info.activityInfo.packageName);
found = true;
break;
}
}
if (!found) {
Toast.makeText(getApplicationContext(), "Facebook does not exist", Toast.LENGTH_SHORT).show();
return;
}
startActivity(Intent.createChooser(share, "Select"));
}
}
and call it like this :
iniShareIntent("face");
This code works for me.....here "updateImage" is my image location.
if (isFacebookExist()) {
if (hashClick.isChecked()) {
SharePhoto sharePhoto = new SharePhoto.Builder()
.setBitmap(updateImage)
.build();
if (ShareDialog.canShow(SharePhotoContent.class)) {
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(sharePhoto)
.setShareHashtag(new ShareHashtag.Builder()
.setHashtag("#HashTag")
.build())
.build();
shareDialog.show(content);
}
} else {
SharePhoto sharePhoto = new SharePhoto.Builder()
.setBitmap(updateImage)
.build();
if (ShareDialog.canShow(SharePhotoContent.class)) {
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(sharePhoto)
.build();
shareDialog.show(content);
}
}
} else {
showToast(" Facebook is not install.");
}
private boolean isFacebookExist() {
PackageManager pm = getPackageManager();
try {
PackageInfo info = pm.getPackageInfo("com.facebook.katana", PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return true;
}
I am developing an Android App which requires speech to text conversion. Currently I have used Google voice search for this purpose but using google requires internet connection and moreover it gives highly inaccurate results for eg. when I say '1' it prints "when"..
Therefore, I want to define my own grammar such that when I give a voice command it searches the grammar defined by me to find the best possible match instead of searching the internet. Using grammar for speech recognition can be done easily for windows 8 phone but I want to know how I can make this work for Android phones.
Kindly take a look at below codes!..
**Using Intent:::**
Intent intent = new Intent(
RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");
try {
startActivityForResult(intent, RESULT_SPEECH);
txtText.setText("");
} catch (ActivityNotFoundException a) {
Toast t = Toast.makeText(getApplicationContext(),
"Opps! Your device doesn't support Speech to Text",
Toast.LENGTH_SHORT);
t.show();
}
Without Using Intent::
Step 1: Implement RecognitionListener in your class.
Step 2. Add the Below codes:
private SpeechRecognizer speech = null;
private Intent speechIntent=null;
/**
* Speech Result is used to Store the Voice Commands
*/
private ArrayList<String> speechResult;
inside onCreate() --- >
speech = SpeechRecognizer.createSpeechRecognizer(this);
speech.setRecognitionListener(this);
Trigger this after your button Click:
if (SpeechRecognizer.isRecognitionAvailable(this)) {
if(speechIntent==null ){
speechIntent=new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en");
speechIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName());
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS,12);
speech.startListening(speechIntent);
}else{
if(speech!=null){
speech.startListening(speechIntent);
}
}
}
Replace the onResults link this:
public void onResults(Bundle results) {
speechResult = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if(speechResult!=null){
if(speechResult.size()>0 ){
String command=speechResult.get(0).toString();
}
}
}
I'm developing a lite version for an app on the Android. How can I start an Intent to open the Android Market, preferably with the full version of my app displayed? This is difficult to test on an emulator (which is the closest thing to a device I have), as there seems to be no legal way of installing the Market on it.
That query above works, but when I tried it, it looked like it was bringing up search results based on the name.
If you use something like
intent.setData(Uri.parse("market://details?id=com.wolinlabs.SuperScorepad"));
instead, it will go right to the Android Market page for your app.
I think that's more what you wanted (?)
Found answer in the end:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://search?q=pname:MyApp"));
startActivity(intent);
No way of testing on emulator, though.
Hi I was trying the achieve the same but with one small difference
I DIDN'T WANT TO OPEN IT EMBEDDED ON MY APP
public void start(JSONArray args, CallbackContext callback) {
Intent launchIntent;
String packageName;
String activity;
String uri;
ComponentName comp;
try {
packageName = args.getString(0); //com.android.vending
activity = args.getString(1); //com.google.android.finsky.activities.LaunchUrlHandlerActivity
uri = args.getString(2); //'market://details?id=com.triplingo.enterprise'
launchIntent = this.cordova.getActivity().getPackageManager().getLaunchIntentForPackage(packageName);
comp = new ComponentName(packageName, activity);
launchIntent.setComponent(comp);
launchIntent.setData(Uri.parse(uri));
this.cordova.getActivity().startActivity(launchIntent);
callback.success();
} catch (Exception e) {
callback.error(e.toString());
}
}
THE BIG DIFFERENCE HERE IS THAT YOU START A NEW APP NOT JUST SHOW GOOGLE PLAY IN YOUR
APP
This code is part of a Cordova plugin but is pretty obvious what you need to do to use it natively.
THE IMPORTANT LINES
launchIntent = this.cordova.getActivity().getPackageManager().getLaunchIntentForPackage(packageName);
comp = new ComponentName(packageName, activity);
launchIntent.setComponent(comp);
launchIntent.setData(Uri.parse(uri));
Regards