I'm trying to write a continuous stream of data to android wear locally on the wear device. I've a class called DataSaver that works perfectly fine on the phone side, but the same code would not work on the wear device. I've android permission for write, and read on both wear and mobile.
In the constructor for DataSaver, I've the following:
if (!isExternalStorageWritable()) Log.e(TAG, "External storage is not writable"); //This line does not show anything on the log. So, esExternalStorageWritable returns false.
File rootDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);//Environment.getExternalStorageDirectory();
if (!rootDir.canWrite())
{
Log.d(TAG, "cannot write in the root: "+rootDir.toString()+", space: "+rootDir.getUsableSpace()+", can read: "+rootDir.canRead()+", list: "+rootDir.list());
}
Function isExternalStorageWritable() is implemented as follows:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable()
{
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state))
{
return true;
}
return false;
}
This always goes inside the if statement where I'm checking if rootDir can write. The rootDir.canRead also returns false. The free space on the device is returned as 2.2GB.
The mkdirs in later lines after that fails because it cannot write to root. Any ideas, suggestions? I would greatly appreciate it.
The problem was I had to manually give permission in settings on the watch for it to work. Basically go to: Settings -> Permissions -> Your app, and check if storage is disabled (it was in my case). Click once to toggle the value.
Remember to have write permission on manifest.
Related
The device must be in USB Host mode to use the UsbManager class. However, when checking if the app is in USB Host mode using packagemanager.hasSystemFeature(PackageManager.FEATURE_USB_HOST), it always returns false. Apparently, USB Host is an unsupported feature on Chromebooks. Is there another way to detect when a USB is inserted on Android on Chromebooks?
We're transitioning from Chrome App to Android and this documentation says to use a "Temporary* private USB host API" in place of the chrome.usb feature. But the link is broken and I can't find more information on it.
I've also tried the USB Web API with no results (the app is contained within a webview, so thought it might work).
The solution is to use the state property of the StorageVolume. A StorageMediaState value of MOUNTED will indicate a mounted USB drive. You also need to filter out non-USB drives by using the various properties of the attached StorageVolumes.
fun getStorageMediaStateFromVolume(volume: StorageVolume?): StorageMediaState {
val volumeState = volume?.state
return if (volume == null || volumeState == null) StorageMediaState.UNKNOWN
else StorageMediaState.values().find { it.stringValue == volumeState } ?: StorageMediaState.UNKNOWN
}
enum class StorageMediaState(val stringValue: String, val isDriveInserted: Boolean) {
// Unknown storage state, such as when a path isn't backed by known storage media.
// This is the value when no drive is inserted.
UNKNOWN(Environment.MEDIA_UNKNOWN, false),
// Media is present but not mounted. Usually this state occurs after an ejection has completed
// but the user has not yet removed the drive.
UNMOUNTED(Environment.MEDIA_UNMOUNTED, true),
// Media is present and being disk-checked.
CHECKING(Environment.MEDIA_CHECKING, true),
// Media is present but is blank or is using an unsupported filesystem.
NOFS(Environment.MEDIA_NOFS, true),
// Media is present and mounted at its mount point with read/write access.
MOUNTED(Environment.MEDIA_MOUNTED, true),
// Media is present and mounted at its mount point with read-only access.
MOUNTED_READ_ONLY(Environment.MEDIA_MOUNTED_READ_ONLY, true),
// Media is present not mounted, and shared via USB mass storage.
SHARED(Environment.MEDIA_SHARED, true),
// Media is present but cannot be mounted, typically because the media's file system is corrupted.
UNMOUNTABLE(Environment.MEDIA_UNMOUNTABLE, true),
// Media is in the process of being ejected.
EJECTING(Environment.MEDIA_EJECTING, true),
// Media is not present.
REMOVED(Environment.MEDIA_REMOVED, false),
// Media was removed before it was unmounted.
BAD_REMOVAL(Environment.MEDIA_BAD_REMOVAL, false)
}
I have an android app. I have a few users who have a recurring problem: When the app shuts down, every file the app saved is gone. Every folder created is gone. Everything is completely wiped back to square one.
I am carefully saving the game data during every transition and game event, so I am very confident that this is not a case of the user crashing out before the data can be written. Somehow, the data that IS being written but then it's just not persisting after the app is removed from memory.
So-- has anyone had this situation and solved it? The only thing I can imagine is that there's some kind of "filesystem.commit" command I need to call after writing the files, but I can't find that documented anywhere.
Please help!
(Edit) I'm using native code to read and write files. The code I use to write a file is this:
bool WriteFile(char *theFilename, char *theDataPtr, int theLen)
{
FILE* aFile=fopen(theFilename,"w+");
if(!aFile) {Alert("unable to create file %s with error %d", theFilename, errno);return false;}
if(aFile) fclose(aFile);
aFile=fopen(theFilename,"w+b");
if(!aFile) {Alert ("unable to open file %s", theFilename);return false;}
if (aFile)
{
fwrite(theDataPtr, 1, theLen,aFile);
fclose(aFile);
return true;
}
return false;
}
Note:No customers are reporting any alert popups, which are just normal Android message boxes. Also note that this code works on almost every other system-- there's just a few customers that get the wiped data, so I was wondering if it's some weird security or some extra step I need to do to be 100% compatible with all systems.
(Edit) One more piece of information... this is the Java code I use to get the storage path for the app... all files that I try to write are put in this folder.
private void SetFilePath()
{
String storagePath = getFilesDir().getAbsolutePath();
// SDCARD
try {
String storageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(storageState))
storagePath = getExternalFilesDir(null).getAbsolutePath();
} catch (Exception e) {
Log.v(IDS.LOG,
"No permission to access external storage, missing android.permission.WRITE_EXTERNAL_STORAGE");
}
SetFilePathNative(storagePath); // Tells the native code the path
mStorageDir = storagePath;
}
I was using this example with ioctl on android 4.4, 5.1
https://github.com/theicfire/simplewebcam/blob/master/jni/ImageProc.c
I am using this interface to get manual control over parameters like contrast, gain, exposure, white level and etc.
when I tried to move the app to android 7 the fd file fails to open.
fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);
Is there any way to fix this?
I have checked and camera2.api doesn't allow controls over the parameters I need from the camera, and the native code fails because of this error.
edit:
to be more precise, I am using a USB camera connected to the tablet, and android 7 doesn't let met get the device FD even though I am using chmod 666 or 777 to set the permission. is there any way around it or other way to get the controls over exposure, contrast, gain, white lvl?
this is the code I added in the java part, the code fails in the canRead() part
private void InitCameraDevice() throws Exception {
//set permissions to all /dev/video devices before checking them
General.RunAsRoot("chmod 666 /dev/video*");
NativeUtils.setLogName(General.getLogFileName());
File dir = new File("/dev");
File[] videoDevFiles = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("video");
}
});
boolean cameraFound = false;
for (File deviceFile : videoDevFiles) {
// Process file
if(deviceFile.canRead()) {
cameraFound = (NativeUtils.prepareCamera(deviceFile.getAbsolutePath(), frameWidth, frameHeight) != -1);
if (cameraFound)
break;
}
else
General.logd(STREAM_THREAD_TAG, "Insufficient permissions on [" +
deviceFile.getAbsolutePath() +"].");
}
if(!cameraFound)
throw new Exception("UVC Camera not found!");
}
Thanks for the help
You need to use the Android USB manager APIs to get the FD for your USB device; accessing the /dev node directly bypasses Android's permission enforcement (see the USB guide here) for USB device access.
Applications having access to the /dev node is therefore a security vulnerability that's locked down in more recent Android releases.
Once you have the FD for a USB device from the Java USB API, you can manipulate it in native code if you'd like.
A question aimed at Android 4.0.x preferably.
I want to detect immediately, or after a few seconds, any change made to Lock SIM card in Settings > Security > Set up SIM card lock.
I tried 3 methods:
1) access read-only com.android.settings shared preferences.
Context settings = getApplicationContext().createPackageContext("com.android.settings", Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences prefSettings = settings.getSharedPreferences("com.android.settings_preferences", MODE_WORLD_READABLE);
Map<String, ?> allSettings = prefSettings.getAll();
for(String s : allSettings.keySet()){
//do somthing like String value=allSettings.get(s).toString());
}
There is a warning in logcat: "Attempt to read preferences file /data/data/com.android.settings/shared_prefs/com.android.settings_preferences.xml without permission". The map returned by getAll() is empty.
2) ITelephony.isSimPinEnabled() always returns false, even when the SIM PIN is enabled and set. So it appears changing the setting has absolutely nothing to do with this interface. I was thinking of polling the interface but this is no good either.
3) creating a ContentObserver observing Settings.Secure is not working here. Actually, reading the content of settings.db with sqlite shows there isn't any record modified when changing this setting. This was also confirmed by the following code:
try {
int lockPattern = android.provider.Settings.Secure.getInt(getContentResolver(), android.provider.Settings.Secure.LOCK_PATTERN_ENABLED);
// check lock Pattern: 0=disabled, 1=enabled
} catch (SettingNotFoundException e) {
e.printStackTrace(); // on run, we reach this line.
}
The only thing I am sure is that modifying the SIM PIN enabled setting rewrites com.android.settings preferences.xml file as shown below:
$adb shell cat
/data/data/com.android.settings/shared_prefs/com.android.settings_preferences.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<boolean name="sim_toggle" value="true" />
<string name="sim_pin"></string>
</map>
The tag affected by the change is sim_toggle.
Does anyone have an idea? What am I doing wrong here?
Had to implement a way to finde out if the SimPin is Enabled today.
The ITelephony.isSimPinEnabled() always returned false for me, too. Didn't try the other methods you described.
I found a way to get the current setting:
First you need to get hold of a proxyPhone Object, how this can be done can be seen here:
Can a telephony.Phone object be instantiated through the sdk?
Then you can retrieve the IccCard-Object and on this execute the method getIccLockEnabled.
Code:
Object proxyPhone = PhoneUtil.getProxyPhoneInstance(this);
Class<?> phone = Class.forName("com.android.internal.telephony.Phone");
Method getIccCardMethod = phone.getDeclaredMethod("getIccCard");
Object iccCard = getIccCardMethod.invoke(proxyPhone);
Class<?> iccCardClass = Class.forName("com.android.internal.telephony.IccCard");
Method getIccLockEnabled = iccCardClass.getDeclaredMethod("getIccLockEnabled");
Boolean isIccLockEnabled = (Boolean) getIccLockEnabled.invoke(iccCard);
works for me on Android 2.3(+?), but as mentioned in the other thread you have to run this code as phone-user/as phone-process.
Really kinda disappointed that there is no public api / deviceAdmin-Api for this. Could imagine that companys want to ensure that their employes keep the sim pin enabled (case of theft).
Well, I think I have a easy way to detect if a Sim PIN has to be entered. Best of all it's is avaliable via the SDK. You could run this in a PhoneStateListener...
public static boolean isSimPinRequired(){
TelephonyManager m = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (m.getSimState() == TelephonyManager.SIM_STATE_PIN_REQUIRED) return true;
return false;
}//end method
I have an app which is autostarting via BroadcastReceiver and is set as a homescreen on Android 2.3.3. API10 on an HTC Desire HD.
The app should play a video repeatedly right after starting, but as the sdcard is not ready it kills the application with a force close error message which doesn't go away.
At least I think it is because of the sdcard.
In the background, the homescreen restarts but the error message doesn't go away, it would be no problem if it would disappear a few seconds later, but it would be even greater if it wouldn't appear at all..
can you help me?
thanks!
edit #1:
this checks if the sdcard is ready. i only need read access..
static public boolean hasStorage(boolean requireWriteAccess) {
String state = Environment.getExternalStorageState();
Log.v("tomi", "storage state is " + state);
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (requireWriteAccess) {
boolean writable = checkFsWritable();
Log.v("tomi", "storage writable is " + writable);
return writable;
} else {
return true;
}
} else if (!requireWriteAccess && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
do you have a solution for this?
First, you should not need both "autostarting via BroadcastReceiver" and "set as a homescreen". One should suffice, preferably the latter.
Once the activity launches, it can check Environment to see if external storage is ready. If not, it can register a receiver for ACTION_MEDIA_MOUNTED to find out when external storage becomes ready. Once it is ready -- and only at that point -- it can try to play the video.