I'm trying to create a system overlay. But I keep getting "permission denied". I'm using SDK version 23.
My manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test" >
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".activity.MainActivity"
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>
</manifest>
The code I use to create the overlay:
//mView = new HUDView(this);
mButton = new Button(this);
mButton.setText("Overlay button");
mButton.setOnTouchListener(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mButton, params);
First, there is no permission named SYSTEM_OVERLAY_WINDOW. It is SYSTEM_ALERT_WINDOW.
Second, if your targetSdkVersion is 23 or higher, and you are running on Android 6.0+ devices, your app will not get this permission at the outset. Call Settings.canDrawOverlays() to see if you have the permission, and use ACTION_MANAGE_OVERLAY_PERMISSION to lead the user over to Settings if you do not.
In AndroidManifest (for version < 23)
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE= 5469;
//Random value
public void testPermission() {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}
}
Result :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
// You have permission
}
}
}
You can also lead the user over to the specific app's overlaying page. The documentation states:
Input: Optionally, the Intent's data URI can specify the application package name to directly invoke the management GUI specific to the package name. For example "package:com.my.app".
So something like:
intent.setData(Uri.fromParts("package", getPackageName(), null));
As an alternative solution, you can try WindowManager.LayoutParams.TYPE_TOAST instead of WindowManager.LayoutParams.TYPE_SYSTEM_ALERT.
This not requires any permission.
I'm using it to show image, maybe button will work to
for users below and above android 8 use
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
I handled all of the overlay permissions for every android version in my library. Please see the gist here.
For Display over the other apps permissions is required to add in the manifest is
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
To check your app has permission
Settings.canDrawOverlays(context)
To check permission checkOverlayPermission
private const val CODE_DRAW_OVER_OTHER_APP_PERMISSION = 2084
private fun checkOverlayPermission(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
//If the draw over permission is not available open the settings screen
//to grant the permission.
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName")
)
startActivityForResult(
intent,
CODE_DRAW_OVER_OTHER_APP_PERMISSION
)
}
}
And in onActivityResult you can check permission is granted or not
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
if (requestCode == CODE_DRAW_OVER_OTHER_APP_PERMISSION) {
if (Settings.canDrawOverlays(this)) {
// Permission Granted
} else {
// Permission not Granted
// If you want then call again checkOverlayPermission until permission granted
}
}
}
Related
I'm trying to use usb camera devices connected to my android device. So initially i have got the details of the usb devices connected through UsbManager.getDeviceList() method. Then i iterated through every device and requested for permission if permission was already not granted.
Prior to requesting the permission i have registered a global BroadCastReceiver to listen to the response of the requested permission.
Here is the MainActivity.java:
public class MainActivity extends AppCompatActivity {
private UsbManager usbManager_;
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
public PendingIntent permissionIntent;
private static String TAG = "testing";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// SurroundView surroundView = new SurroundView(this);
// setContentView(surroundView);
usbManager_ = (UsbManager) getSystemService(USB_SERVICE);
permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
requestUsbPermissions();
}
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "received intent by broadcast " + intent.getAction());
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
Log.i(TAG, "got the permission");
}
} else {
Log.d(TAG, "permission denied for device " + device);
}
}
}
}
};
public void requestUsbPermissions(){
HashMap<String, UsbDevice> deviceList = usbManager_.getDeviceList();
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
this.registerReceiver(usbReceiver, filter);
Log.i(TAG, "registered broadcast receiver!");
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while (deviceIterator.hasNext()) {
UsbDevice device = deviceIterator.next();
Log.i(TAG,
"Camera: device Id " + device.getDeviceId() + " device mName : " + device.getDeviceName());
if (!usbManager_.hasPermission(device)) {
Log.i(TAG, "requesting permission");
usbManager_.requestPermission(device, permissionIntent);
}
}
}
}
So when i run the app it detects one usb device connected and requests permission for the same. But the dialog box which asks for user input never comes. Instead when the intent is received by the BroadCastReceiver the value of intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false) will always be false which means the permission is already denied. Can anyone explain to me why the dialog box is not coming in the first place and why the permission is denied automatically.
Here is my AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.vision_sdk_testing">
<uses-feature android:name="android.hardware.usb.host" android:required="true"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
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>
</manifest>
And below is the output log:
2020-05-01 17:56:05.282 30769-30769/com.example.vision_sdk_testing I/testing: registered broadcast receiver!
2020-05-01 17:56:05.283 30769-30769/com.example.vision_sdk_testing I/testing: Camera: device Id 1003 device mName : /dev/bus/usb/001/003
2020-05-01 17:56:05.283 30769-30769/com.example.vision_sdk_testing I/testing: requesting permission
2020-05-01 17:56:05.301 30769-30769/com.example.vision_sdk_testing I/testing: received intent by broadcast com.android.example.USB_PERMISSION
2020-05-01 17:56:05.302 30769-30769/com.example.vision_sdk_testing D/testing: permission denied for device UsbDevice[mName=/dev/bus/usb/001/003,mVendorId=1443,mProductId=38192,mClass=239,mSubclass=2,mProtocol=1,mManufacturerName=Sonix Technology Co., Ltd.,mProductName=USB 2.0 Camera,mVersion=1.00,mSerialNumberReader=android.hardware.usb.IUsbSerialReader$Stub$Proxy#d41ebfa,mConfigurations=[
UsbConfiguration[mId=1,mName=null,mAttributes=128,mMaxPower=128,mInterfaces=[
UsbInterface[mId=0,mAlternateSetting=0,mName=HD USB Camera,mClass=14,mSubclass=1,mProtocol=0,mEndpoints=[]]
UsbConfiguration[mId=3,mName=null,mAttributes=3,mMaxPower=88,mInterfaces=[]]
Any help is appreciated. Thanks!
For me, I had to go into the app's permissions in the settings menu and give my app the Camera permission. I'm guessing it's because my USB device is a camera? Once I granted this permission, the app worked just as described in the docs https://developer.android.com/guide/topics/connectivity/usb/host
I'm having some trouble with Intent Action_Call. I put the permission in Manifest, but it doesn't work. I press the button to Call and nothing happens. The app that I'm making is an app that does multiple Intents so the code isn't in MainActivity. I don't know if it helps, but I'm using API 28.
Thanks for reading.
MANIFEST:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.intentsimplicitas">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".SmsActivity"></activity>
<activity android:name=".DialActivity" />
<activity android:name=".WaysActivity" />
<activity android:name=".MapActivity" />
<activity android:name=".PageActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
JAVA (DialActivity.java)
public class DialActivity extends Activity {
Button btnDial;
EditText edtPhone;
String phone;
Intent it;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dial);
btnDial = (Button)findViewById(R.id.btnDial);
edtPhone = (EditText)findViewById(R.id.edtPhone);
}
public void dialClick (View v) {
phone = edtPhone.getText().toString();
Uri uri = Uri.parse("tel: " + phone);
it = new Intent(Intent.ACTION_CALL);
it.setData(uri);
startActivity(it);
}
}
From https://developer.android.com/training/permissions/requesting:
Requesting permission:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.CALL_PHONE)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed; request the permission
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.CALL_PHONE},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
// MY_PERMISSIONS_REQUEST_CALL_PHONE is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted
}
Verifying:
#Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CALL_PHONE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
You can do via Intent
public void dialClick (View v) {
phone = edtPhone.getText().toString();
Uri uri = Uri.parse("tel: " + phone);
it = new Intent(Intent.ACTION_DIAL);
it.setData(uri);
startActivity(it);
}
You need to add the permissions at run time to be able to make the call, I recommend the following library, since it is much easier to implement the permissions in time of execution.
https://github.com/Karumi/Dexter
I am trying to make a simple application in Java to install an APK on Android devices connected via USB. Using ABD manually or installing from Android Studio it works fine, but I wanted to give a simple single button click install option within my application, I have tried following code but unfortunately, it is not working
abdsourcesync = apkpath;
progress.setString("sync in progress");
System.out.println("Starting Sync via adb with command " + "adb"
+ " install -r " + apkpath);
Process process = Runtime.getRuntime().exec(
"adb" + " install -r " + apkpath);
InputStreamReader reader = new InputStreamReader(
process.getInputStream());
Scanner scanner = new Scanner(reader);
scanner.close();
int exitCode = process.waitFor();
System.out.println("Process returned: " + exitCode);
I have searched around here but I have only found installing an APK from within an Android application or from the android studio, not from a core Java. or java web module
Your helping hand would be really appreciated ;
Do not forget about runtime permissions
This simple example works for me for API 28.
It opens an apk file to install from "Download folder"
For simplification:
Download the apk file for application you want to install to "Download" folder of your phone. (There are a lot of instructions to do it programmaticaly, ot you can do it manualy)
TO DO
Create new project
Add a button to MainActivity
Create xml folder in res folder and create a file_paths.xml file there
Use the code bellow
Enjoy =)
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.teko.testcleanopenfile">
<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"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
</manifest>
MainActivity
public class MainActivity extends AppCompatActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// textView and button
textView = findViewById(R.id.textView);textView.setText("Hello updatable World\n");
(findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onClick(View view) {RunAPK(getBaseContext());}
});
}
private void RunAPK(Context context){
requestPermissionsToRead();
}
private void requestPermissionsToRead() {
// ASK RUNTIME PERMISSIONS
ActivityCompat.requestPermissions(MainActivity.this, new String[]{READ_EXTERNAL_STORAGE},111);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (grantResults.length > 0) {
if (requestCode == 111 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
textView.append("Permission granted write\n");
// Create Uri
File downloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File file1 = new File (downloads + "//app-debug.apk");//downloads.listFiles()[0];
Uri contentUri1 = getUriForFile(this, BuildConfig.APPLICATION_ID, file1);
// Intent to open apk
Intent intent = new Intent(Intent.ACTION_VIEW, contentUri1);
intent.setDataAndType(contentUri1, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
}
}
}
}
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="download" path="."/>
</paths>
You can Install Application from Java code using below way.
File outputFile = null;
try {
outputFile = new File(<APK Path>);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".provider", outputFile);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(intent);
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N){
Uri apkUri = Uri.fromFile(outputFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}else {
Toast.makeText(mContext, "File not found.", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
}
I am building a voice recognition app that does something when I say a specific word such as "open" and it opens something etc. but the problem is that my app keep crashing when I run it on my phone (real device) and I tap the speak button. I don't know what else to do? I tried giving it internet and voice recognition permission but it still doesn't help
here is the code in java (android studio)
public class MainActivity extends Activity {
private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
private TextView resultText;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button speakButton = (Button) findViewById(R.id.SpeakButton);
speakButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
startVoiceRecognitionActivity();
}
});
}
void startVoiceRecognitionActivity(){
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName());
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
}
#Override
protected void onActivityResult (int requestCode,int resultCode, Intent data){
String wordStr = null;
String[] words = null;
String firstWord = null;
String secondWord = null;
if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK)
{
ArrayList<String> matches = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
wordStr = matches.get(0);
words = wordStr.split(" ");
firstWord = words[0];
secondWord = words[1];
}
if (firstWord.equals("open"))
{
resultText = (TextView)findViewById(R.id.ResultText);
resultText.setText("Results: Open Command Works");
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.starlinginteractivesoftworks.musiccompanion">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I look at the log and it said:
08-07 20:12:57.813 14350-14350/? E/BoostFramework: BoostFramework() :
Exception_1 = java.lang.ClassNotFoundException: Didn't find class
"com.qualcomm.qti.Performance" on path:
DexPathList[[],nativeLibraryDirectories=[/system/lib64,
/vendor/lib64]] 08-07 20:12:58.509
14350-14350/com.starlinginteractivesoftworks.musiccompanion
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.starlinginteractivesoftworks.musiccompanion, PID: 14350
android.content.ActivityNotFoundException: No Activity found to handle
Intent { act=android.speech.action.RECOGNIZE_SPEECH
launchParam=MultiScreenLaunchParams { mDisplayId=0 mFlags=0 } (has
extras) }
at
android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1839)
at
android.app.Instrumentation.execStartActivity(Instrumentation.java:1531)
at android.app.Activity.startActivityForResult(Activity.java:4399)
at android.app.Activity.startActivityForResult(Activity.java:4358)
at
com.starlinginteractivesoftworks.musiccompanion.MainActivity.startVoiceRecognitionActivity(MainActivity.java:55)
at
com.starlinginteractivesoftworks.musiccompanion.MainActivity$1.onClick(MainActivity.java:43)
at android.view.View.performClick(View.java:6205)
at android.widget.TextView.performClick(TextView.java:11103)
at android.view.View$PerformClick.run(View.java:23653)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
The boost framework log is just a warning, no worry about it. The real problem is the
ActivityNotFoundException: No Activity found to handle Intent
It can come from:
a poor connectivity
the voice app is missing on your phone
Possible solutions
Ensure you have a recognition app installed (see ActivityNotFoundException: No Activity found to handle Intent (RECOGNIZE_SPEECH) for more details).
Try to enable offline mode as explained here:
On your device go to Settings -> Language and Input. Click on icon on Google voice input.
Under ALL tab select the language you want to download.
Once the language package downloaded, you can see it under INSTALLED tab.
Workarounds
Catch the exception and open a webview to download a recognition app:
try{
...
}
catch(ActivityNotFoundException e) {
Intent i = new Intent(Intent.ACTION_VIEW,
Uri.parse("https://market.android.com/details?id=APP_PACKAGE_NAME"));
startActivity(i);
}
Check that a recognition app is available before the startActivity (see https://stackoverflow.com/a/35290037/2667536):
PackageManager manager = context.getPackageManager();
List<ResolveInfo> infos = manager.queryIntentActivities(intent, 0);
if (infos.size() > 0) {
//Then there is application can handle your intent
}else{
//No Application can handle your intent
}
Android says, that listOfFiles if null, so what have i done wrong?
I've tried to change getPath to getAboletePath, but it is just the same.
And, i've tried to access /storage/ (whereas SD_PATH is /storage/emulated/0) and i've got a list of 2 folders: emulated and self, both of wich are unaccessible.
public class MainActivity extends AppCompatActivity {
private static final String SD_PATH = Environment.getExternalStorageDirectory().getPath();
...
File home = new File(SD_PATH);
File[] listOfFiles = home.listFiles();
if(listOfFiles != null && listOfFiles.length > 0){
for (File file : home.listFiles()){
songs.add(file.getName());
}
}
Here is my AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unimusic">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<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>
</manifest>
This same thing has burned me in the past.
To quote the docs
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app.
(see here)
Reading from the file system is one of the permissions that must now be requested at run time in order to use. This is only an issue if you target SDK 23 or later. So how to fix:
The docs show an example (see here for the original) that I have modified for your use case (I have not run this code, but it should be a good starting point). You probably want to request permissions in the onCreate() for the Activity that is going to need the permission (in your case the MainActivity).
// Ask for the read external storage permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_EXTERNAL_STORAGE))
{
// Provide an additional rationale to the user if the permission was not granted
// and the user would benefit from additional context for the use of the permission.
// Display a SnackBar with a button to request the missing permission.
Snackbar.make(layout,
"External storage is needed in order to {YOUR EXPLANATION HERE}",
Snackbar.LENGTH_INDEFINITE).setAction("OK", new View.OnClickListener()
{
#Override
public void onClick(View view)
{
// Request the permission
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
}
}).show();
}
else
{
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
}
}