I'm trying to download a website source code and display it in a textbox but I seem to get an error and can't figure it out :s
public void getHtml() throws ClientProtocolException, IOException
{
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet("http://www.spartanjava.com");
HttpResponse response = httpClient.execute(httpGet, localContext);
String result = "";
BufferedReader reader = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent()
)
);
String line = null;
while ((line = reader.readLine()) != null){
result += line + "\n";
Toast.makeText(activity.this, line.toString(), Toast.LENGTH_LONG).show();
}
}
how come this doesn't work and throw an IOException?
I think you're probably missing INTERNET permission in your manifest.xml
Pay attention to <uses-permission> tag provided in the code below. I tested your code in eclipse, and it works.
BTW I think using String result in this way wont work. Didn't test that far though. But I think you cannot just add string to a string. You need to use stringBuilder and append new strings.
EDIT: tested this String result metod, and it works. Maybe the problem is that you are trying to throw so many toast all at once. Your code throws a toast for every line of retrived html code. I set your getHtml() method to type String, and to return result, and it returned it properly... I can't think of any other reason for exception, except missing INTERNET permission in your AndroidManifest.xml....
Cheers!
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.test.test"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name" android:debuggable="true">
<activity android:name=".test"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Related
I am trying to download a file from the internet with DownloadManager on Android 9, but I only get unsuccessful download. This is what I am testing:
My Manifest permission:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
My code to download it:
private final String FILE_NAME = "SampleDownloadApp.apk";
String apkUrl = "https://androidwave.com/source/apk/app-pagination-recyclerview.apk";
public void download(Context context) {
DownloadManager dm = (DownloadManager)context.getSystemService(DOWNLOAD_SERVICE);
Uri mUri = Uri.parse(apkUrl);
DownloadManager.Request r = new DownloadManager.Request(mUri);
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
Uri uri = Uri.parse("file://" + context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + FILE_NAME_2);
r.setDestinationUri(uri);
dm.enqueue(r);
}
I have tried android: usesCleartextTraffic = "true" in the manifest but then nothing happens. I never get any errors neither in logcat nor in run.
I followed this tutorial: https://androidwave.com/download-and-install-apk-programmatically/
I have no idea what the problem may be, any solution?
Help with this!
there is something wrong with you URL tried following and its working
private final String FILE_NAME = "SampleDownloadApp.apk";
String apkUrl = "https://d-10.winudf.com/b/APK/Y29tLm5lbW8udmlkbWF0ZV80MzUxMV9iOTJjMTFkZA?_fn=VmlkTWF0ZSBIRCBWaWRlbyBEb3dubG9hZGVyIExpdmUgVFZfdjQuMzUxMV9hcGtwdXJlLmNvbS5hcGs&_p=Y29tLm5lbW8udmlkbWF0ZQ&am=cCsiKSeBEin6IVuzn-Q2PA&at=1590661203&k=3c1a8eca32edf42751cb3f5fa102d0205ed0e1d3";
public void download(Context context) {
DownloadManager dm = (DownloadManager)context.getSystemService(DOWNLOAD_SERVICE);
Uri mUri = Uri.parse(apkUrl);
DownloadManager.Request r = new DownloadManager.Request(mUri);
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, FILE_NAME);
dm.enqueue(r);
}
Hey so I save my pdf in external data storage. Eg:
Environment.getExternalStorageDirectory().getPath() + "/file.pdf"
Then, I try to attach it to intent to send:
File attachment = this.getFileStreamPath(fileDirectory + "/" + fileName);
Uri uri = Uri.fromFile(attachment);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setDataAndType(Uri.parse("mailto:"), "text/plain"); // I have also tried "application/pdf"
emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Calc PDF Report");
emailIntent.putExtra(Intent.EXTRA_TEXT, " PDF Report");
emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(emailIntent, "Send mail..."));
finish();
and im getting the error:
Caused by: java.lang.IllegalArgumentException: File /storage/emulated/0/file.pdf contains a path separator
I am thinking it is something wrong with were I am saving my file, but can't find any examples that are up-to-date.
To share a file as an email attachment using intent, you need to use a FileProvider.
/**
* Generate file content and returns uri file
*/
public static Uri generateFile(Context context) {
File pdfDirPath = new File(context.getFilesDir(), "pdfs");
pdfDirPath.mkdirs();
File file = new File(pdfDirPath, "attachment.pdf");
file.deleteOnExit();
Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".file.provider", file);
FileOutputStream os = null;
try {
Logger.info("Generate file " + file.getAbsolutePath());
os = new FileOutputStream(file);
document.writeTo(os);
document.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
return uri;
}
private void share(Context context) {
Uri uri = generateFile(context);
final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
emailIntent.putExtra(EXTRA_SUBJECT, "Send something");
emailIntent.putExtra(Intent.EXTRA_TEXT, "You receive attachment");
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(emailIntent);
}
In your app add the file provider definition:
AndroidManifest.xml
<application
android:name=".DemaApplication"
android:allowBackup="false"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.file.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
...
</application>
provider_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="internal_files"
path="/"/>
<!--<external-path name="external_files" path="./files"/>-->
</paths>
At last but not least, you need to specify the file provider path (where are your files). I hope this helps. Here, the official documentation about how to send email and attachment with intent.
Problem #1: getFileStreamPath() does not support subdirectories and is not related to external storage, where your file resides.
Problem #2: Uri.fromFile() will not work on Android 7.0, as your app will crash with a FileUriExposedException. To fix this and Problem #1, use FileProvider to set up a content Uri that you can use for EXTRA_STREAM.
Problem #3: ACTION_SEND does not use a "data" Uri (i.e., your "mailto:" should not be there).
Problem #4: The MIME type of a PDF is not text/plain — as your comment notes, use application/pdf.
Problem #5: getExternalStorageDirectory() is deprecated on Android 10 and higher, and you will not be able to write files there. Consider using getExternaFilesDir(null) (called on a Context) for a better location that works without permissions and on more Android OS versions.
can't find any examples that are up-to-date
The documentation covers the use of ACTION_SEND.
I'm developing an android application which needs to consume rest apis deployed, for now, on an heroku instance...since i got crashes anytime i try to integrate retrofit as http client I've done the following:
Added retrofit2 as dependendcy (didn't choose the latest version in order to avoid potential maturity problems)
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.google.code.gson:gson:2.6.2'
I coded an example android app, just to check if something has been done wrong in my original app, using http://httpbin.org/ip
public interface HttpBinService
{
public static class Response
{
private String origin;
public Response(String origin) {
this.origin = origin;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
}
#GET("ip")
public Call<Response> getIp ();
}
And the main activity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Retrofit setup
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://httpbin.org")
.addConverterFactory(GsonConverterFactory.create())
.build();
// Service setup
HttpBinService service = retrofit.create(HttpBinService.class);
try {
Call<HttpBinService.Response> call = service.getIp();
Response<HttpBinService.Response> res = call.execute();
if (res.isSuccessful()){
Log.i("PROVARETROFIT", "OK");
((TextView)findViewById(R.id.testo)).setText(res.body().getOrigin());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I did not forget to ask for internet permissions in my manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.spich.provaretrofit">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
But all i got is that application closes unexpectedly. If t execute it in debug, it executes correctly all steps until call execution. LogCat appears to not say anything useful
04-15 09:48:08.281 6491-6491/? I/art: Late-enabling -Xcheck:jni
04-15 09:48:08.367 6491-6491/? W/System: ClassLoader referenced unknown path: /data/app/it.spich.provaretrofit-1/lib/arm64
04-15 09:48:08.387 6491-6491/it.spich.provaretrofit I/HwCust: Constructor found for class android.app.HwCustHwWallpaperManagerImpl
04-15 09:48:08.577 6491-6491/? I/Process: Sending signal. PID: 6491 SIG: 9
Has someone idea of what is happening there?
Not sure why logcat doesn't show anything useful. But when executing it, it is giving an android.os.NetworkOnMainThreadException, which can explain the problem. So as they say in the comments: try using the enque method with a callback, this also allows you to get rid of the try/catch statement. Try to replace the code after // Service setup in your MainActivity with:
HttpBinService service = retrofit.create(HttpBinService.class);
Call<HttpBinService.Response> call = service.getIp();
call.enqueue(new Callback<HttpBinService.Response>() {
#Override
public void onResponse(Call<HttpBinService.Response> call, Response<HttpBinService.Response> response) {
if (response.isSuccessful()){
Log.i("PROVARETROFIT", "OK");
//((TextView)findViewById(R.id.testo)).setText(res.body().getOrigin());
System.out.println(response.body().getOrigin());
} else {
System.out.println("Unsuccesfull");
}
}
#Override
public void onFailure(Call<HttpBinService.Response> call, Throwable t) {
System.out.println("Call failed");
}
});
I built a SyncAdapter for my app so that I could use Google Cloud Messaging to trigger a sync of database to the server. I am using Volley to actually make the network calls and sync the data, but from what I read when wanting to sync your app you should have a SyncAdapter
My issue is that the onPerformSync() doesn't always run. I will fire the GCM and I always get a log stating that it got through the GCM properly, but my log for the onPerformSync() doesn't always fire. Because it does sometimes I would imagine it is set up properly. But I cannot figure out what is happening when it doesn't
onPerformSync()
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d("onPerformSync", "got to the sync");
}
onMessageReceived() in GCM message handler
#Override
public void onMessageReceived(String from, Bundle data) {
if (from.equals("/topics/global")) {
Log.d("gcm topics", data.getString("message"));
try {
if (data.getString("message").equals("update")) {
Log.d("is update", "is message update");
Account newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
ContentResolver.requestSync(newAccount, AUTHORITY, data);
}
} catch (NullPointerException e) {
Log.e("GCM", e.toString());
}
} else {
String message = data.getString("message");
createNotification(from, message);
}
}
Creating the account in MainActivity
public static Account createSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
ACCOUNT, ACCOUNT_TYPE);
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(
ACCOUNT_SERVICE);
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (accountManager.addAccountExplicitly(newAccount, null, null)) {
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call context.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
ContentResolver.setIsSyncable(newAccount, ArmyContract.CONTENT_AUTHORITY, 1);
ContentResolver.setSyncAutomatically(newAccount, ArmyContract.CONTENT_AUTHORITY, true);
return newAccount;
} else {
/*
* The account exists or some other error occurred. Log this, report it,
* or handle it internally.
*/
Log.e("Account Creation", "Error withou dummy accocunt");
return null;
}
}
syncadapter.xml
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.clashtoolkit.clashtoolkit"
android:accountType="clashtoolkit.com"
android:userVisible="false"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"/>
authenticator.xml
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="clashtoolkit.com"
android:icon="#mipmap/ic_launcher"
android:smallIcon="#mipmap/ic_launcher"
android:label="#string/app_name"/>
AndroidManifext.xml
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.clashtoolkit.clashtoolkit.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.clashtoolkit.clashtoolkit.permission.C2D_MESSAGE" />
<service
android:name="com.clashtoolkit.clashtoolkit.network.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="#xml/authenticator" />
</service>
<service
android:name="com.clashtoolkit.clashtoolkit.network.SyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/syncadapter" />
</service>
The problem might be in adding these keys to Bundle data :
// Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
data.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
data.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(newAccount, AUTHORITY, data);
I am attempting to access metadata for an activity from the manifest file.
The manifest looks like this :
<activity
android:name="co.uk.benbun.nvrrclubapp.MainActivity"
android:label="#string/app_name" >
<meta-data android:value="newstag" android:name="NEWS"></meta-data>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The code to access it, looks like this :
try {
ApplicationInfo ai = getPackageManager().getApplicationInfo(this.getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
String myApiKey = bundle.getString("NEWS");
} catch (NameNotFoundException e) {
Log.e("metadata", "Failed to load meta-data, NameNotFound: " + e.getMessage());
feedTag = "NEWS";
} catch (NullPointerException e) {
Log.e("metadata", "Failed to load meta-data, NullPointer: " + e.getMessage());
feedTag = "NEWS";
}
When I execute the code I always get the nullPointerException.
What am I doing wrong?
The documentation for PackageManager.GET_META_DATA says:
ComponentInfo flag: return the metaData data Bundles that are
associated with a component. This applies for any API returning a
ComponentInfo subclass.
You are calling getApplicationInfo() which returns an ApplicationInfo object. ApplicationInfo does not inherit from ComponentInfo, so this object will not have any meta-data. You need to get the ActivityInfo for your MainActivity in order to get the meta-data (ActivityInfo is a subclass of ComponentInfo).