I am working on Network based project in android, so, to prevent force close on Android ICS because of Can't do network operation on UI Thread , I must use the part of code such below or try to start my network operation on other thread, but I don't want to change the base code, so I should use the code as below on Android ICS. :
static {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
}
How can I make unique apk file to run in all android version ( >= 1.6 ) ? android.os.StrictMode is accessible for higher version of android, so, i can not try to use the above part of code in my Android Activity. So, which solution is better :
Using Reflections to run this part of code on higher versions of API (As oracle docs, reflective operations have slower performance than their non-reflective counterparts)
Change my android build target to Android 4.1.1 (API 16) and try to change the android:minSdkVersion on AndroidManifest.xml
Or if you know any better ones, please let me know.
Thanks in advance :)
You can use BUILD.VERSION and reflection to get over this compability problem (tested).
if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 9) {
try {
// StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
Class<?> strictModeClass = Class.forName("android.os.StrictMode", true, Thread.currentThread()
.getContextClassLoader());
Class<?> threadPolicyClass = Class.forName("android.os.StrictMode$ThreadPolicy", true, Thread.currentThread()
.getContextClassLoader());
Field laxField = threadPolicyClass.getField("LAX");
Method setThreadPolicyMethod = strictModeClass.getMethod("setThreadPolicy", threadPolicyClass);
setThreadPolicyMethod.invoke(strictModeClass, laxField.get(null));
} catch (Exception e) {
}
}
Related
Has anyone else tried to mark their clipboard copied data as sensitive as per the following recommendation?
https://developer.android.com/about/versions/13/features/copy-paste
clipData.apply {
description.extras = PersistableBundle().apply {
putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
}
}
When I tried to do so, I don't find a clipData.apply method.
How can I set the sensitivity settings in an android app Java code?
apply() is a Kotlin scope function. You appear to be programming in Java, so the Kotlin syntax will not work for you.
By eyeball, the Java equivalent would be:
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
clipData.getDescription().setExtras(extras);
I've been trying to get my app to be able to delete an audio file. However, after trying many possible solutions, I couldn't really find one that works.
Here is my solution so far:
public static void deleteFiles(List<Track> tracks, Context context,
final MutableLiveData<IntentSender> deletionIntentSenderLD){
final Uri AUDIO_URI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
for(Track t : tracks){
try {
context.getContentResolver().delete(ContentUris
.withAppendedId(AUDIO_URI, t.getUriId()), null, null);
}catch (SecurityException securityException) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (securityException instanceof RecoverableSecurityException) {
deletionIntentSenderLD
.postValue(((RecoverableSecurityException) securityException)
.getUserAction().getActionIntent().getIntentSender());
} else
throw securityException;
} else
throw securityException;
}
}
}
When the try block fails a SecurityException is catch then the IntentSender is passed to the live data that is observed in a fragment:
audioViewModel.getDeletionIntentSenderLD().observe(getViewLifecycleOwner(),
intentSender -> {
try {
startIntentSenderForResult(intentSender, DELETE_PERMISSION_REQUEST,
null, 0 ,0, 0,
null);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
});
I've tried implementing the onRequestPermissionResult() method but that doesn't do anything. I've also tried deleting the files using File file = new File(), however, due to the changes made to Android 10, I didn't expect it to work.
So after many Google searches, I've come to the conclusion that the best approach (to my knowledge) is to simply turn off scoped storage for Android Q (10).
Here, I'll provide two solutions. The first is the one where I turn it off and the second is the one where scope storage is still enable. However, a thing you should note is that the second solution is a little buggy, at times it actually does delete both the actual media file and updates the Media Store, but most times it simply deletes from the Media Store only. Obviously, this isn't a very good solution as on reboot your application would then load those files back in because the Media Store would scan for them.
Solution 1 - Turn off Scoped Storage
For this solution you can still target Android 11. All you have to do is go to the build.gradle file at the Module Level and set the compileSdkVersion and targetSdkVersion to 30.
After that, you go into the AndroidManifest.xml and have the uses-permission and application tag set up like this:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage"/>
<application
android:requestLegacyExternalStorage="true"
...
After having done that, you could use the Content Resolver to delete the media file (and update the Media Store) and you do not have to worry about catching a security exception like its said in the Android docs. Your implementation for Android 11s delete operation should not be affected.
Solution-ish 2 - Turn on Scoped Storage
Firstly, in your manifest ensure that the WRITE_EXTERNAL_STORAGE permissions maxSdkVersion is set to 28. Also ensure that requestLegacyExternalStorage is set to false (don't think this is required). Then simply copy the code in my original post. You do not require a Live Data if you are doing the delete operation from your activity/fragment. But you should note that startIntentSenderForResult() requires an activity.
But as I mentioned before, I did experience some bugs with this. The most frustrating thing about this solution though is that it does not delete the actual file but instead deletes the entry from the Media Store. Maybe this has something to do with the fact that #blackapps mentioned, which is that you cannot bulk delete and I might have implemented it slightly wrong. Nevertheless, this is horrible for user experience if bulk deletion is impossible in Android 10.
The tutorials I followed for this are:
https://developer.android.com/training/data-storage/shared/media#remove-item
https://www.raywenderlich.com/9577211-scoped-storage-in-android-10-getting-started#toc-anchor-007
https://www.solutionanalysts.com/blog/scoped-storage-in-android-10/
Side Note - Delete on Android 11
To delete on Android 11 you just need to call createDeleteRequest() which should return a PendingIntent. From this PendingIntent you could get the IntentSender by using getIntentSender. Pass this intent sender to the activity/fragment then call startIntentSenderForResult() in your activity/fragment. This pops up a dialog to the user asking them if the application can delete a file. If the user gives permission the system goes ahead and deletes the file and updates the Media Store.
Side Side Note - Scoped Storage, Android 10 and Future
From everything I've seen, it seems to suggest that scoped storage is only enforced in Android 11 but I'm not entirely sure if the legacy option would still be available in Android 10 indefinitely. But I would have to do more research on this...
I'm trying to develop a simple camera app with face detection and i'm using android-vision sample from here
https://github.com/googlesamples/android-vision/tree/master/visionSamples/FaceTracker
Everything is working fine and i need to add zoom in/out feature in it. I searched SO but found nothing related to vision. Every answer is related to Camera2.
You might try startSmoothZoom:
https://developer.android.com/reference/android/hardware/Camera.html#startSmoothZoom(int)
You'd need to modify the open source version of CameraSource to make this change, since you'd need access to its underlying android.hardware.Camera instance:
https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java#L121
Try this code, it works (Yes, it's reflection)
try {
cameraSource.apply {
start(holder)
javaClass.getDeclaredField("zzg").apply {
isAccessible = true
(get(cameraSource) as Camera).apply {
startSmoothZoom(min(5, parameters.maxZoom))
}
}
}
} catch (e: Throwable) {
Timber.e(e)
}
Notice, that zzg is an obfuscated var of Camera instance and it's name may be different per library releases
I have a loader that uses the Support Library v4, it is being used to carry the loading of a ListView in an Activity that contains two fragments, one containing the ListView (being it an extension of ListFragment) and the other carrying a button (which can be clicked while the loader is doing the work).
The implementation is pretty similar to the one available at the Android documentation of the AsyncTaskLoader, which is also creating a ListView trough the loader, with the exception of the monitoring part, where my implementation does not need the monitoring of changes: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
As the app has support to API level 8, I am using the FragmentActivity::getSupportLoaderManager method to start the loader as advised in the documentation in order to keep the support.
http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html
When using this class as opposed to new platform's built-in fragment and loader support, you must use the getSupportFragmentManager() and getSupportLoaderManager() methods respectively to access those features.
Being the loader started from the Fragment, I had to use the ListFragment::getActivity method to call the method FragmentActivity::getSupportLoaderManager, resulting in the following code being used to start the loader:
getActivity().getSupportLoaderManager().initLoader(0, null, this).forceLoad();
The app is running fine with APIs higher than 8, but on level 8 it is crashing when the loader tries to renders the list on UI after loading (Loader::onLoadFinished method).
Debugging I found that it is crashing at the moment that the ArrayAdapter<>::addAll method is being called on the adapter, which confirms that the problem is on the rendering of the UI. At that moment, the app is thrown to the SamplingProfilerIntegration class where something related to a snapshot is trying to be done at a static part of the class:
/** Whether or not a snapshot is being persisted. */
private static final AtomicBoolean pending = new AtomicBoolean(false);
static {
samplingProfilerMilliseconds = SystemProperties.getInt("persist.sys.profiler_ms", 0);
samplingProfilerDepth = SystemProperties.getInt("persist.sys.profiler_depth", 4);
if (samplingProfilerMilliseconds > 0) {
File dir = new File(SNAPSHOT_DIR);
dir.mkdirs();
// the directory needs to be writable to anybody to allow file writing
dir.setWritable(true, false);
// the directory needs to be executable to anybody to allow file creation
dir.setExecutable(true, false);
if (dir.isDirectory()) {
snapshotWriter = Executors.newSingleThreadExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, TAG);
}
});
enabled = true;
Log.i(TAG, "Profiling enabled. Sampling interval ms: "
+ samplingProfilerMilliseconds);
} else {
snapshotWriter = null;
enabled = true;
Log.w(TAG, "Profiling setup failed. Could not create " + SNAPSHOT_DIR);
}
} else {
snapshotWriter = null;
enabled = false;
Log.i(TAG, "Profiling disabled.");
}
}
It could be related to the specific behavior of the UI rendering on prior to Honeycomb versions as stated in the documentation, but I can not think of what.
http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html
Prior to Honeycomb (3.0), an activity's state was saved before pausing. Fragments are a significant amount of new state, and dynamic enough that one often wants them to change between pausing and stopping. These classes throw an exception if you try to change the fragment state after it has been saved, to avoid accidental loss of UI state. However this is too restrictive prior to Honeycomb, where the state is saved before pausing. To address this, when running on platforms prior to Honeycomb an exception will not be thrown if you change fragments between the state save and the activity being stopped. This means that in some cases if the activity is restored from its last saved state, this may be a snapshot slightly before what the user last saw.
I found that the support libraries v4 and v7, which are the being imported to the project, does not support the method ArrayAdapter<>::addAll() and this was making the app crash.
This question is related to this issue and the solution presented was suitable to address my problem:
ListViews - how to use ArrayAdapter.addAll() function before API 11?
So, the solution was to implement my own version of the ArrayAdapter class, so that the prior to Honeycomb versions of Android could use it.
I would like to ascertain at run-time inside an Android app whether it is running within the BlueStacks Android emulator. This is so I can modify the way the app runs when running inside BlueStacks.
BlueStacks does not support multi-touch so I want to implement an alternative to the standard pinch-to-zoom functionality my current app has.
E.g.
If (appIsRunningInBlueStacks){
mySurfaceView.enableMultiTouchAlternatives();
} else{
mySurfaceView.enableMultiTouchFeatures();
}
What is a reliable way of ascertaining the value of appIsRunningInBlueStacks?
EDIT Summary of answers to comments on question:
Ben, Taras, thanks for the suggestions. The Build.MODEL etc. values for BlueStacks are:
Model: "GT-I9100"
Manufacturer: "samsung"
Device: "GT-I9100"
Product: "GT-I9100"
This is the same model number as the Samsung Galaxy SII so it would not be ideal to use this for fear of treating all users with SIIs the same as those on BlueStacks.
CommonsWare, the app continues to run in BlueStacks even with the < uses-feature> for multitouch in the manifest. In fact (also answering iagreen's question)...
packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
... returns true! This is to be expected I suppose as the emulator is convinced it is a Samsung Galaxy SII!
Therefore we are still without a way of reliably detecting whether an app is running on BlueStacks without also throwing all Samsung Galaxy SII users in the same bucket. Any other ideas?
All the above methods are not working on BlueStacks 5. The correct way to do is checking if the path of /mnt/windows/BstSharedFolder exists. It is working fine on both BlueStacks 4 and 5.
fun checkFilesExist(files: Array<String>): Boolean {
files.forEach {
val file = File(it)
if (file.exists()) {
return true
}
}
return false
}
fun isBlueStacks(): Boolean {
val BLUE_STACKS_FILES = arrayOf(
"/mnt/windows/BstSharedFolder"
)
return checkFilesExist(BLUE_STACKS_FILES)
}
You can check that the Bluestacks shared folder exist
/sdcard/windows/BstSharedFolder
Boolean onBlueStacks()
{
File sharedFolder = new File(Environment
.getExternalStorageDirectory().toString()
+ File.separatorChar
+ "windows"
+ File.separatorChar
+ "BstSharedFolder");
if (sharedFolder.exists())
{
return true;
}
return false;
}
After trying all the suggested solutions available online we found the Google's SafetyNet Attestation API is the only solution for detecting VMs like BlueStack(any version) and NoxPlayer.
Apps that care about content piracy (and other security issues) can filter their availability on the Google Play like Netflix filters devices on the PlayStore.
The new “device catalog” section of the console includes an option
called “SafetyNet exclusion,” which can be used to prevent “devices
that fail integrity tests or those that are uncertified by Google,”
from downloading a specific app: among these would be rooted devices
and those running custom ROMs.
But there is a catch user will still find the APK from cross-sharing or other distribution systems, so the client must implement SafetyNet Attestation API on the app level.
How does it work?
SafetyNet examines software and hardware information on the device
where your app is installed to create a profile of that device. The
service then attempts to find this same profile within a list of
device models that have passed Android compatibility testing. The API
also uses this software and hardware information to help you assess
the basic integrity of the device, as well as the APK information of
the calling app. This attestation helps you to determine whether or
not the particular device has been tampered with or otherwise
modified.
It's an (easy to implement) paid API from the Google which allows 10,000 free hits per day as of now :\
If anyone is interested in detecting VMs by them self, these are the good papers available suggesting heuristic approaches :
Evading Android Runtime Analysis via Sandbox Detection
Rage Against the Virtual Machine:
Hindering Dynamic Analysis of Android Malware
My version of BlueStacks is reporting my Build.Model as GT-N7100.
Using: android.opengl.GLES20.glGetString(android.opengl.GLES20.GL_RENDERER) I get Bluestacks.
It maybe too late but for the sake of others who have the same problem :
public boolean isRunningOnEmulator() {
return Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")
|| Build.MANUFACTURER.contains("Genymotion")
|| (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| "google_sdk".equals(Build.PRODUCT)
|| Build.PRODUCT.contains("vbox86p")
|| Build.DEVICE.contains("vbox86p")
|| Build.HARDWARE.contains("vbox86");
}
Based on Mr. Regis' answer, you can detect it when the shared folder is present. However in Bluestacks 4, using file.exists() will only return false. This is because the shared folder has no permissions (000 or ----------). But listing files in the directory will detect the folder.
String path = Environment.getExternalStorageDirectory().toString();
Log.d("FILES", "Path: " + path);
File directory = new File(path);
File[] files = directory.listFiles();
for (File file : files) {
if (file.getName().contains("windows")) {
Log.d("FILES", "windows file exists, it's a bluestacks emu");
}
}
This Will be unique.
There is no bluetooth device in Bluestack.
So try to get The Bluetooth Address string which is always 'null' on Bluestack or Any emulator.Make sure you are adding Bluetooth permission on your project manifest.
BluetoothAdapter m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_bluetoothAdd = m_BluetoothAdapter.getAddress();