Get available space fails - android

Up to now, I have been querying for available space in the following manner :
StatFs stats;
long lBlockSize, lBlockCount;
long lTotal = 1;
stats = new StatFs(Environment.getExternalStoragePublicDirectory("Documents").getAbsolutePath());
lBlockCount = (long)stats.getAvailableBlocksLong();
lBlockSize = (long)stats.getBlockSizeLong();
lTotal = lBlockCount * lBlockSize;
return lTotal;
However, with Android 9 this would appear to be failing (reported to me by a user).
Has something major changed ?

With Android 9 I don't think there was any major change BUT with Android 10 there was a major change to start the introduction of Scoped Storage, where you might not have direct access to the file system any more. (With Android 11 Google have said that this type of file access won't work any more).
See https://developer.android.com/training/data-storage/files/external-scoped

Related

Determine Android app's last update time during development?

I am trying to get a timestamp of when the currently running Android app was updated during development (e.g. a new APK installed by Android Studio or ADB.). I have tried the following, but both timestamps do not update even though the app has been updated:
val pm: PackageManager = this.getPackageManager()
val appInfo = pm.getApplicationInfo(this.packageName, 0)
val appFile: String = appInfo.sourceDir
val lastWriteTime = File(appFile).lastModified()
val lastUpdateTime = this.getPackageManager()
.getPackageInfo(this.packageName, 0).lastUpdateTime
As you can see in the screenshot below, the lastUpdateTime is 1653240000762 which in my time zone is 2022-05-22 13:20:00 -0400. That is about 12 days in the past as of this writing. The lastWriteTime is 1653239999000 which is 2022-05-22 13:19:59 -0400.
I just re-ran this code from AndroidStudio about one hour ago on 2022-06-03 14:00:00 -0400. Why did the timestamp not change? I know for sure the app was updated because before this change, the code lines shown were not there to show up in the debugger!
There must be a way to do this. Clearly, the code has changed on the Android device. How can I get a measurement of when that happened?
The reason I want this is because I am a developer of an Android library, and I want to make the library clear out some cache information when it detects a new app install during development to make things easier on the app developer.
If I clearly understood your problem, following approach may help you (actually, it may be not the best solution):
Via gradle add constant for timestamp or date:
static def timestamp() {
return System.currentTimeMillis()
}
android {
...
defaultConfig {
...
buildConfigField "Long", "BUILD_TIMESTAMP", timestamp()
}
}
On your main activity at onCreate send BuildConfig.BUILD_TIMESTAMP and current system timestamp wherever you want. For example, write simple web service that accepts such requests and saves it at remote database.
If you want to track only unique installations, you can use instead of build timestamp hash sum for installation apk somehow or use self written code generation lib that would calc hash sum for sources (for example).
Edit: Or you can calc sources hash at build.gradle directly.

How to detect programmatically if "Android App" is running in chrome book or in Android phone

Since Google has announced that chromebook also support "Android Application" so I also wanted to support my app on chromebook although it is running fine with few exception which I need to fix.
I want to write code in such a way that that is will execute only for chromebook and will not execute for android phones and tablet.
I have check with Chromebook documentation in android developer site, I didn't get any such API which tell that your app is running in chrome book environment.
Suggestion from ARC Beta documentation did not work:
If you need to check if your app is running on Chrome OS, look for chromium as the android.os.Build.BRAND and android.os.Build.MANUFACTURER.
Both return google on an ASUS Chromebook.
Finally I figure out a way to know if app in running in ARC:
context.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
Jan 15, 2023 Note-- Jump to the bottom of this answer to read how Google has changed their own method for checking YET AGAIN.
(Or keep reading for the history of the ARC check.)
Another method Google uses in their own code (updated several times now from link) is to check if Build.DEVICE ends with "_cheets". I don't know if ending device names like this is some kind of long-term strategy or a fast workaround, but it's also worth a look in addition to dex's proposed solution.
FWIW, since ARCWelder's method is deprecated and there's no official documentation on this (yet), I've also started a discussion in the XDA forums here for people to discuss what works/doesn't work on various devices.
Update 5/18: Looks like the code above was moved and updated, so Google's new ARC check as of May 2018 is here, particularly in this bit:
... } else if (Build.DEVICE != null && Build.DEVICE.matches(ARC_DEVICE_PATTERN)) {
mFormFactor = FORM_FACTOR_ARC;
} else { ...
where ARC_DEVICE_PATTERN is defined as
private static final String ARC_DEVICE_PATTERN = ".+_cheets|cheets_.+";
So it's not just a device ending with _cheets. It can start with cheets_ as well.
Update 8/26/20 -- As of 7 months ago, the source has been moved around from FormFactors.java to FeatureSupport.java. If you were looking for where it went- here it the code as of today.
public static boolean isArc() {
return (Build.DEVICE != null && Build.DEVICE.matches(".+_cheets|cheets_.+"));
}
The test remains the same.
Jan 15, 2023 -- The code has changed again! isArc() is now built into the FeatureUtil class (see commit here) The current version of isArc() :
/** Returns {#code true} if device is an ARC++ device. */
public static boolean isArc() {
return hasAnySystemFeature(ARC_FEATURE, ARC_DEVICE_MANAGEMENT_FEATURE);
}
Where ARC_FEATURE and ARC_DEVICE_MANAGEMENT_FEATURE are defined like this:
public static final String ARC_FEATURE = "org.chromium.arc";
public static final String ARC_DEVICE_MANAGEMENT_FEATURE = "org.chromium.arc.device_management";
the function hasAnySystemFeature() simply checks individual features and returns true if any is true.
Therefore the following might work as a simple standalone check in kotlin (where context is the activity context):
fun isArc(): Boolean {
return ((context.packageManager.hasSystemFeature("org.chromium.arc")) || (context.packageManager.hasSystemFeature("org.chromium.arc.device_management")))
Note this is similar to #dex's answer below, but includes both tests used by the Android source.
Incidentally, from looking at the code linked above you can also check other device characteristics like like isWatch(), isTV(), isAutomotive(), isPC(), isVrHeadset(), isLowRam(), etc. using similar feature checks.
PackageManager pm = context.getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_PC))
// it's a chromebook
I found the solution in Android CTS code.
public static boolean isArc(#NonNull Context context) {
PackageManager pm = context.getPackageManager();
return pm.hasSystemFeature( "org.chromium.arc" ) || pm.hasSystemFeature( "org.chromium.arc.device_management" );
}

Can we programatically enable/disable USB debugging on Android devices? [duplicate]

This question already has answers here:
Enable USB debugging (under settings/applications/development) programmatically from within an app
(6 answers)
Closed 5 years ago.
Is there any way to turn USB debugging on/off programmatically on Android devices?
Hi this is my first post on here, and normally I wouldn't bother but I see no one wanted to give you the answer despite there being multiple ways to do so.
This is all from my app, I'm "idone" on xda-dev btw. Also some of this code maybe Samsung MSMxxxx specific
If you have root you can indeed. And here are 3 ways to do so despite other people saying otherwise
Method 1(broadcast secret code)
Method 2(set sys.usb.config)
Method 3(set settings global adb_enabled 1)
public String[] SET_DM_PORT_STATUS_LIST = new String[9];{
SET_DM_PORT_STATUS_LIST[0] = "setMTP";
SET_DM_PORT_STATUS_LIST[1] = "setMTPADB";
SET_DM_PORT_STATUS_LIST[2] = "setPTP";
SET_DM_PORT_STATUS_LIST[3] = "setPTPADB";
SET_DM_PORT_STATUS_LIST[4] = "setRNDISDMMODEM";
SET_DM_PORT_STATUS_LIST[5] = "setRMNETDMMODEM";
SET_DM_PORT_STATUS_LIST[6] = "setDMMODEMADB";
SET_DM_PORT_STATUS_LIST[7] = "setMASSSTORAGE";
SET_DM_PORT_STATUS_LIST[8] = "setMASSSTORAGEADB";}
public String[] SET_DM_PORT_CONFIG_LIST = new String[9];{
SET_DM_PORT_CONFIG_LIST[0] = "mtp";
SET_DM_PORT_CONFIG_LIST[1] = "mtp,adb";
SET_DM_PORT_CONFIG_LIST[2] = "ptp";
SET_DM_PORT_CONFIG_LIST[3] = "ptp,adb";
SET_DM_PORT_CONFIG_LIST[4] = "rndis,acm,diag";
SET_DM_PORT_CONFIG_LIST[5] = "rmnet,acm,diag";
SET_DM_PORT_CONFIG_LIST[6] = "diag,acm,adb";
SET_DM_PORT_CONFIG_LIST[7] = "mass_storage";
SET_DM_PORT_CONFIG_LIST[8] = "mass_storage,adb";}
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
outputStream.writeBytes("am broadcast -a android.provider.Telephony.SECRET_CODE -d android_secret_code://" + SET_DM_PORT_STATUS_LIST[paramInt]+"\n");
outputStream.writeBytes("setprop sys.usb.config " + SET_DM_PORT_CONFIG_LIST[paramInt]+"\n");
if(SET_DM_PORT_STATUS_LIST[paramInt].contains("adb")){
outputStream.writeBytes("settings put global adb_enabled 1\n");
}
I am in the process of reversing IOTHIDDENMENU.apk and recreating it's methods but without the internal and hidden api it uses.
On a regular device, with a regular app, you can't.
You need a rooted device, with an app in /system/app, then you can.
Anyway, you shouldn't configure such a thing by yourself, the user should be in full control in such a case.
This is not possible in android because for that you have to access Setting.System. For more info take a look here : How can I disable Android USB debugging programmatically
It's not possible without using your own custom firmware that grants access to the security settings. See thread here: http://groups.google.com/group/android-developers/browse_frm/thread/953c6f0eb0fa9bed#
usb debugging is another name for the Android Debug Bridge (ADB). The item you're looking for is here
http://developer.android.com/reference/android/provider/Settings.Secure.html#ADB_ENABLED
great answer :
https://stackoverflow.com/a/17029123/1136074
basicly its:
android.os.Debug.waitForDebugger(); also you can use the following to determine if the debugger is connected:
android.os.Debug.isDebuggerConnected(); //Determine if a debugger is currently att

getUidRxBytes() and getUidTxBytes() always return 0 in Android 4.3

I feel like I am on crazy pills right now. A specific part of my application has been working just fine for several days, and today it just stopped working and I can not figure out why. This part of my code used to output the total data since boot that each specific app has sent and received. Now, the values always show up as 0.
A couple things that may or may not be affecting this:
1.) My Nexus 4 was just updated to Android 4.3 today, but I doubt this is an issue because this worked just fine right after I updated.
2.) With the Android API 18 update, some methods from the Traffic Stats API are now deprecated, but these are methods I am not even using, so this should have no effect.
http://developer.android.com/reference/android/net/TrafficStats.html
All help is greatly appreciated.
PackageManager packageManager=this.getPackageManager();
List<ApplicationInfo> appList=packageManager.getInstalledApplications(0);
for (ApplicationInfo appInfo : appList) {
String appLabel = (String) packageManager.getApplicationLabel(appInfo);
int uid = appInfo.uid;
Log.d("data", String.valueOf(TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid)));
Update[January 23, 2014]: Testing the getUidRxBytes() and getUidTxBytes() on my Nexus 4 running Android 4.4.2 shows that the values are no longer 0, but are reporting the correct statistics.
I have reported the issue to the AOSP issue tracker: here
I have also created an alternate solution to the problem which I have pasted below:
private Long getTotalBytesManual(int localUid){
File dir = new File("/proc/uid_stat/");
String[] children = dir.list();
if(!Arrays.asList(children).contains(String.valueOf(localUid))){
return 0L;
}
File uidFileDir = new File("/proc/uid_stat/"+String.valueOf(localUid));
File uidActualFileReceived = new File(uidFileDir,"tcp_rcv");
File uidActualFileSent = new File(uidFileDir,"tcp_snd");
String textReceived = "0";
String textSent = "0";
try {
BufferedReader brReceived = new BufferedReader(new FileReader(uidActualFileReceived));
BufferedReader brSent = new BufferedReader(new FileReader(uidActualFileSent));
String receivedLine;
String sentLine;
if ((receivedLine = brReceived.readLine()) != null) {
textReceived = receivedLine;
}
if ((sentLine = brSent.readLine()) != null) {
textSent = sentLine;
}
}
catch (IOException e) {
}
return Long.valueOf(textReceived).longValue() + Long.valueOf(textReceived).longValue();
}
The TrafficStats class get the information about network traffic from the /proc/uid_stat/<uid> directory. This contains information about the tcp, udp bytes and packets sent and received. If the files are not present the TrafficStats class can't get the network stats. You can check if the files are present, If not you are out of luck and should look for other way.
If the files are present you can try to read it yourself.
Also the getUidTxBytes() and getUIDRxBytes() report only the TCP traffic and miss UDP traffic. So if your app is doing lots of UDP traffic (like voip) then you'll not get any info.
There is already a bug filed for this : https://code.google.com/p/android/issues/detail?id=32410
I have done some detailed research about this, and to clarify some details, since Android 4.3 the TrafficStats API has changed in the way it extracts details from the device.
Prior to Android 4.3 the UID traffic stats were available for TCP and UDP and included API for bytes and packets & sent and received. That data was extracted from the /proc/uid_stat/[pid]/* files.
In Android 4.3, the developers has decided to switch to a better and more safe API, using the xt_qtaguid UID statistics, which is part of the netfilter kernel module in Linux.
This API (procfs) allows access based on process UID, and this is why when you try to access to TrafficStats API in Android=>4.3 you will get zero information for not-own UID.
btw, the commit that caused the issue is the following:
https://github.com/android/platform_frameworks_base/commit/92be93a94edafb5906e8bc48e6fee9dd07f5049e
*Improve TrafficStats UID APIs.
Deprecate transport layer statistics, leaving only the summarized
network layer statistics.
Improve documentation to be clear about layers where measurements
occur, and their behavior since boot. Under the hood, move to using
xt_qtaguid UID statistics.
Bug: 6818637, 7013662
Change-Id: I9f26992e5fcdebd88c671e5765bd91229e7b0016*

"SQLiteException: no such column: mimetype" when using ContactsContract in Android

I want to delete an entry from Android's internal database table ContactsContract, i.e. an event such as a birthday should be removed from the contact's entry.
The following code works pretty well, but some users (ca. 1%) have this crashing with an SQLException. So is there anything wrong in my code or is it just that their device doesn't support Android's ContactsContract correctly?
try {
ArrayList<Long> rawContactIDs = getRawContactID(o.getID());
int rawContactCount = rawContactIDs.size();
for (int r = 0; r < rawContactCount; r++) {
long rawContactID = rawContactIDs.get(r);
String where = ContactsContract.Data.MIMETYPE+" = ? AND "+ContactsContract.Data.RAW_CONTACT_ID+" = ? AND "+ContactsContract.CommonDataKinds.Event.TYPE+" = ?";
String[] selection = new String[] { ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, String.valueOf(MY_RAW_CONTACT_ID), String.valueOf(ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) };
getContentResolver().delete(ContactsContract.Data.CONTENT_URI, where, selection);
}
}
catch (Exception e) {}
The exception that is thrown is:
android.database.sqlite.SQLiteException: no such column: mimetype: , while
compiling: DELETE FROM data WHERE mimetype = ? AND raw_contact_id = ? AND
data2 = ?
at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:158)
at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:114)
at
android.content.ContentProviderProxy.delete(ContentProviderNative.java:472)
at android.content.ContentResolver.delete(ContentResolver.java:700)
at ... MY_ACTIVITY ...
It is possible for device manufacturers to change the implementation of a ContentProvider that ships with the AOSP. In theory, those changes would be caught by the Compatibility Test Suite (CTS), so that only devices that don't break the API will run your app when shipped through the Play Store.
That being said...
The CTS is far from complete
The CTS does not protect you if you intentionally distribute your app beyond the Play Store, and somebody with an incompatible device runs your app
The CTS does not protect you if you unintentionally distribute your app beyond the Play Store (i.e., your app's been pirated), and somebody with an incompatible device runs your app
Various device manufacturers pirate the Play Store app itself
So, when you see problems that would appear to originate from within an OS-supplied ContentProvider, but those problems are infrequent and/or are on unrecognized devices, don't panic. You still might choose to somehow fail gracefully in this case (by wrapping the failing calls in your own exception handler), but it's unlikely that your code is really the source of the difficulty.
The ContactsContract API has been available since level 5. Is it possible the users reporting this issue are < level 5 (Donut, Cupcake)?

Categories

Resources