I updated the files a bit, now the java file have added support for multiple type of sensors.
HollywoodDelegate.java file: (As always, change your package name in the java file to match your package name in apk compiler settings)
Code: Select all
package com.amy66dev.extended;
// Core Android functionality
import android.content.Intent; // Camera, GPS, Sharing, Permissions
import android.net.Uri; // Camera, Sharing, File operations
import android.os.Build; // Version checks throughout
import android.os.Environment; // File operations, SD card, Storage
import android.util.Log; // Logging throughout
import android.app.Activity; // Base class, context
// Permissions and hardware features
import android.Manifest; // Camera, Location permissions
import android.content.pm.PackageManager; // Permission checking
import android.location.Location; // GPS functionality
import android.location.LocationManager; // GPS functionality
import android.media.MediaScannerConnection; // Camera file scanning
import android.os.Vibrator; // Vibration (currently commented out)
import android.provider.MediaStore; // Camera, MediaStore operations
import android.widget.Toast; // Toast messages (optional)
import android.content.Context; // System services
import android.content.ContentValues; // MediaStore operations
import android.media.MediaScannerConnection; // Camera file scanning (duplicate)
import android.content.ClipboardManager; // Clipboard functions
import android.content.ClipData; // Clipboard functions
import android.view.WindowManager; // Keep Screen On
// AndroidX libraries
import androidx.annotation.Nullable; // Nullable annotations
import androidx.core.app.ActivityCompat; // Permission requests
import androidx.core.content.ContextCompat; // Permission checking
import androidx.core.content.FileProvider; // File sharing
// Java utilities
import java.text.SimpleDateFormat; // Camera timestamp
import java.util.Date; // Camera timestamp
import java.util.Locale; // String formatting
import java.util.List; // GPS location providers
import java.util.ArrayList; // Multiple permissions requests
// File I/O operations
import java.io.File; // All file operations
import java.io.FileInputStream; // File reading, copy operations
import java.io.FileOutputStream; // File writing, copy operations
import java.io.IOException; // Exception handling
import java.io.BufferedReader; // File reading
import java.io.InputStreamReader; // File reading
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import java.util.Map;
import java.util.HashMap;
/**
* HollywoodDelegate - Direct external storage file utilities.
* Must be included as Custom Code in the Hollywood APK Compiler.
*/
public class HollywoodDelegate extends HollywoodActivity {
private static final String TAG = "HollywoodDelegate";
private SensorManager sensorManager;
// --- Add SD card helper HERE (inside the class, not before imports)
private File getExternalSdCard() {
File[] externalDirs = getApplicationContext().getExternalFilesDirs(null);
if (externalDirs != null && externalDirs.length > 1) {
for (File dir : externalDirs) {
if (dir != null && Environment.isExternalStorageRemovable(dir)) {
return dir.getParentFile().getParentFile().getParentFile().getParentFile();
}
}
}
return null;
}
// --- PERMISSION METHODS ---
// Check if MANAGE_EXTERNAL_STORAGE is granted
public boolean hasAllFilesAccess() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
}
return true; // On Android 10 and below, WRITE_EXTERNAL_STORAGE is enough
}
// Open settings page for granting MANAGE_EXTERNAL_STORAGE
public void requestAllFilesAccess() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
} catch (Exception e) {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(intent);
}
}
}
// --- FOLDER METHODS ---
// Check if folder exists
public boolean folderExists(String folderName) {
try {
File dir = new File(Environment.getExternalStorageDirectory(), folderName);
return dir.exists() && dir.isDirectory();
} catch (Exception e) {
Log.e(TAG, "Error checking folder existence: " + e.getMessage());
return false;
}
}
// Create folder
public boolean createFolder(String folderName) {
try {
File dir = new File(Environment.getExternalStorageDirectory(), folderName);
if (!dir.exists()) {
if (!dir.mkdirs()) return false;
}
return true;
} catch (Exception e) {
Log.e(TAG, "createFolder failed: " + e.getMessage());
return false;
}
}
// Delete folder recursively
public boolean deleteFolder(String folderName) {
try {
File dir = new File(Environment.getExternalStorageDirectory(), folderName);
if (!dir.exists() || !dir.isDirectory()) return false;
return deleteRecursive(dir);
} catch (Exception e) {
Log.e(TAG, "deleteFolder failed: " + e.getMessage());
return false;
}
}
private boolean deleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
File[] children = fileOrDirectory.listFiles();
if (children != null) {
for (File child : children) deleteRecursive(child);
}
}
return fileOrDirectory.delete();
}
// --- FILE METHODS ---
// Check if file exists AND is readable
public boolean fileExists(String folderName, String fileName) {
try {
File file = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
boolean exists = file.exists() && file.isFile();
boolean readable = exists && file.canRead();
Log.i(TAG, "fileExists: " + folderName + "/" + fileName + " - exists: " + exists + ", readable: " + readable);
return exists && readable;
} catch (Exception e) {
Log.e(TAG, "fileExists failed: " + e.getMessage());
return false;
}
}
// Create or overwrite file
public boolean createFile(String folderName, String fileName, String content) {
try {
File dir = new File(Environment.getExternalStorageDirectory(), folderName);
if (!dir.exists() && !dir.mkdirs()) return false;
File file = new File(dir, fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
if (content != null) fos.write(content.getBytes("UTF-8"));
fos.flush();
}
return true;
} catch (Exception e) {
Log.e(TAG, "createFile failed: " + e.getMessage());
return false;
}
}
// Read entire file
public String readFile(String folderName, String fileName) {
try {
File file = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!file.exists() || !file.canRead()) return "";
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
}
return sb.toString().trim();
} catch (Exception e) {
Log.e(TAG, "readFile failed: " + e.getMessage());
return "";
}
}
// Append to file
public boolean appendToFile(String folderName, String fileName, String content) {
try {
File file = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!file.exists()) return createFile(folderName, fileName, content);
try (FileOutputStream fos = new FileOutputStream(file, true)) {
if (content != null) fos.write(content.getBytes("UTF-8"));
fos.flush();
}
return true;
} catch (Exception e) {
Log.e(TAG, "appendToFile failed: " + e.getMessage());
return false;
}
}
// Delete file
public boolean deleteFile(String folderName, String fileName) {
try {
File file = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!file.exists()) return false;
return file.delete();
} catch (Exception e) {
Log.e(TAG, "deleteFile failed: " + e.getMessage());
return false;
}
}
// Read a specific line
public String readLineFromFile(String folderName, String fileName, int lineNumber) {
try {
File file = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!file.exists() || !file.canRead()) return "";
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
String line;
int count = 0;
while ((line = reader.readLine()) != null) {
if (count == lineNumber) {
return line;
}
count++;
}
}
} catch (Exception e) {
Log.e(TAG, "readLineFromFile failed: " + e.getMessage());
}
return "";
}
// Count number of lines
public int getNumberOfLines(String folderName, String fileName) {
int count = 0;
try {
File file = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!file.exists() || !file.canRead()) return 0;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
while (reader.readLine() != null) count++;
}
} catch (Exception e) {
Log.e(TAG, "getNumberOfLines failed: " + e.getMessage());
}
return count;
}
// List files in folder (newline-separated)
public String listFilesInFolder(String folderName) {
try {
File dir = new File(Environment.getExternalStorageDirectory(), folderName);
if (!dir.exists() || !dir.isDirectory()) return "";
StringBuilder sb = new StringBuilder();
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
sb.append(f.getName());
if (f.isDirectory()) sb.append(" (dir)");
sb.append("\n");
}
}
return sb.toString().trim();
} catch (Exception e) {
Log.e(TAG, "listFilesInFolder failed: " + e.getMessage());
return "";
}
}
// Copy internal -> external
public boolean copyFileToExternal(String internalRelativePath, String folderName, String fileName) {
try {
File src = new File(getFilesDir(), internalRelativePath);
if (!src.exists()) return false;
File dst = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!dst.getParentFile().exists()) dst.getParentFile().mkdirs();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[4096];
int r;
while ((r = in.read(buf)) > 0) out.write(buf, 0, r);
out.flush();
}
return true;
} catch (Exception e) {
Log.e(TAG, "copyFileToExternal failed: " + e.getMessage());
return false;
}
}
// Copy external -> internal
public boolean copyFileFromExternal(String folderName, String fileName, String internalRelativePath) {
try {
File src = new File(new File(Environment.getExternalStorageDirectory(), folderName), fileName);
if (!src.exists() || !src.canRead()) return false;
File dst = new File(getFilesDir(), internalRelativePath);
if (!dst.getParentFile().exists()) dst.getParentFile().mkdirs();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[4096];
int r;
while ((r = in.read(buf)) > 0) out.write(buf, 0, r);
out.flush();
}
return true;
} catch (Exception e) {
Log.e(TAG, "copyFileFromExternal failed: " + e.getMessage());
return false;
}
}
// --- Create folder on SD card ---
public boolean createFolderOnSDCard(String folderName) {
File sdRoot = getExternalSdCard();
if (sdRoot == null) return false;
File folder = new File(sdRoot, folderName);
return folder.exists() || folder.mkdirs();
}
// --- Create/overwrite file on SD card ---
public boolean createFileOnSDCard(String folderName, String fileName, String content) {
File sdRoot = getExternalSdCard();
if (sdRoot == null) return false;
try {
File folder = new File(sdRoot, folderName);
if (!folder.exists()) folder.mkdirs();
File file = new File(folder, fileName);
try (FileOutputStream fos = new FileOutputStream(file, false)) {
fos.write(content.getBytes("UTF-8"));
fos.flush();
}
return true;
} catch (Exception e) {
Log.e(TAG, "Error writing file to SD card", e);
return false;
}
}
// --- Read file from SD card ---
public String readFileFromSDCard(String folderName, String fileName) {
File sdRoot = getExternalSdCard();
if (sdRoot == null) return "";
try {
File file = new File(new File(sdRoot, folderName), fileName);
if (!file.exists() || !file.canRead()) return "";
StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
}
return sb.toString().trim();
} catch (Exception e) {
Log.e(TAG, "Error reading file from SD card", e);
return "";
}
}
// --- Delete file from SD card ---
public boolean deleteFileFromSDCard(String folderName, String fileName) {
File sdRoot = getExternalSdCard();
if (sdRoot == null) return false;
File file = new File(new File(sdRoot, folderName), fileName);
return file.exists() && file.delete();
}
// --- SD CARD OPERATIONS ---
// Check if folder exists on SD card
public boolean folderExistsOnSDCard(String folderName) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File dir = new File(sdCard, folderName);
return dir.exists() && dir.isDirectory();
}
// Recursive delete helper for SD card
private boolean deleteRecursiveFromSDCard(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
File[] children = fileOrDirectory.listFiles();
if (children != null) {
for (File child : children) {
deleteRecursiveFromSDCard(child);
}
}
}
return fileOrDirectory.delete();
}
// Delete folder from SD card
public boolean deleteFolderFromSDCard(String folderName) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File dir = new File(sdCard, folderName);
if (dir.exists() && dir.isDirectory()) {
return deleteRecursiveFromSDCard(dir);
}
return false;
}
// Check if a file exists on SD card
public boolean fileExistsOnSDCard(String folderName, String fileName) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File file = new File(new File(sdCard, folderName), fileName);
boolean exists = file.exists() && file.isFile();
boolean readable = exists && file.canRead();
Log.i(TAG, "fileExistsOnSDCard: " + folderName + "/" + fileName + " - exists: " + exists + ", readable: " + readable);
return exists && readable;
}
// Append to file on SD card
public boolean appendToFileOnSDCard(String folderName, String fileName, String content) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File dir = new File(sdCard, folderName);
if (!dir.exists()) dir.mkdirs();
File file = new File(dir, fileName);
try (FileOutputStream fos = new FileOutputStream(file, true)) {
fos.write(content.getBytes("UTF-8"));
fos.flush();
return true;
} catch (Exception e) {
Log.e(TAG, "appendToFileOnSDCard failed", e);
return false;
}
}
// Read a specific line from a file on SD card
public String readLineFromFileOnSDCard(String folderName, String fileName, int lineNumber) {
File sdCard = getExternalSdCard();
if (sdCard == null) return "";
File file = new File(new File(sdCard, folderName), fileName);
if (!file.exists() || !file.canRead()) return "";
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
String line;
int count = 0;
while ((line = reader.readLine()) != null) {
if (count == lineNumber) return line;
count++;
}
} catch (Exception e) {
Log.e(TAG, "readLineFromFileOnSDCard failed", e);
}
return "";
}
// Get number of lines in a file on SD card
public int getNumberOfLinesOnSDCard(String folderName, String fileName) {
File sdCard = getExternalSdCard();
if (sdCard == null) return 0;
File file = new File(new File(sdCard, folderName), fileName);
if (!file.exists() || !file.canRead()) return 0;
int count = 0;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
while (reader.readLine() != null) count++;
} catch (Exception e) {
Log.e(TAG, "getNumberOfLinesOnSDCard failed", e);
}
return count;
}
// List files in a folder on SD card
public String listFilesInFolderOnSDCard(String folderName) {
File sdCard = getExternalSdCard();
if (sdCard == null) return "";
File dir = new File(sdCard, folderName);
if (!dir.exists() || !dir.isDirectory()) return "";
StringBuilder sb = new StringBuilder();
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
sb.append(f.getName());
if (f.isDirectory()) sb.append(" (dir)");
sb.append("\n");
}
}
return sb.toString().trim();
}
// Copy file from internal storage -> SD card
public boolean copyFileToSDCard(String internalRelativePath, String folderName, String fileName) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File src = new File(getFilesDir(), internalRelativePath);
if (!src.exists()) return false;
File dst = new File(new File(sdCard, folderName), fileName);
dst.getParentFile().mkdirs();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[4096];
int r;
while ((r = in.read(buf)) > 0) out.write(buf, 0, r);
out.flush();
return true;
} catch (Exception e) {
Log.e(TAG, "copyFileToSDCard failed", e);
return false;
}
}
// Copy file from SD card -> internal storage
public boolean copyFileFromSDCard(String folderName, String fileName, String internalRelativePath) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File src = new File(new File(sdCard, folderName), fileName);
if (!src.exists() || !src.canRead()) return false;
File dst = new File(getFilesDir(), internalRelativePath);
dst.getParentFile().mkdirs();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[4096];
int r;
while ((r = in.read(buf)) > 0) out.write(buf, 0, r);
out.flush();
return true;
} catch (Exception e) {
Log.e(TAG, "copyFileFromSDCard failed", e);
return false;
}
}
// Copy file from External (primary shared storage) -> SD card
public boolean copyFromExternalToSDCard(String externalFolder, String externalFile, String sdFolder, String sdFile) {
File external = Environment.getExternalStorageDirectory();
if (external == null) return false;
File src = new File(new File(external, externalFolder), externalFile);
if (!src.exists() || !src.canRead()) return false;
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File dst = new File(new File(sdCard, sdFolder), sdFile);
dst.getParentFile().mkdirs();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[4096];
int r;
while ((r = in.read(buf)) > 0) out.write(buf, 0, r);
out.flush();
return true;
} catch (Exception e) {
Log.e(TAG, "copyFromExternalToSDCard failed", e);
return false;
}
}
// Copy file from SD card -> External (primary shared storage)
public boolean copyFromSDCardToExternal(String sdFolder, String sdFile, String externalFolder, String externalFile) {
File sdCard = getExternalSdCard();
if (sdCard == null) return false;
File src = new File(new File(sdCard, sdFolder), sdFile);
if (!src.exists() || !src.canRead()) return false;
File external = Environment.getExternalStorageDirectory();
if (external == null) return false;
File dst = new File(new File(external, externalFolder), externalFile);
dst.getParentFile().mkdirs();
try (FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[4096];
int r;
while ((r = in.read(buf)) > 0) out.write(buf, 0, r);
out.flush();
return true;
} catch (Exception e) {
Log.e(TAG, "copyFromSDCardToExternal failed", e);
return false;
}
}
// ================================================================
// πΈ CAMERA CAPTURE (Complete Section)
// ================================================================
private String lastPhotoPath;
// Camera permission methods
public boolean hasCameraPermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}
public void requestCameraPermission() {
if (!hasCameraPermission()) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
2002
);
}
}
// Main camera method
public String openCamera() {
try {
// Check camera permission first
if (!hasCameraPermission()) {
Log.w(TAG, "Camera permission not granted");
return "camera_permission_denied";
}
// Check storage permission for saving photos
if (!hasAllFilesAccess()) {
Log.w(TAG, "Storage permission not granted");
return "storage_permission_denied";
}
// Use Pictures directory that Hollywood can access
File storageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"HollywoodPhotos"
);
if (!storageDir.exists()) storageDir.mkdirs();
// Create unique filename
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
String fileName = "photo_" + timeStamp + ".jpg";
File photoFile = new File(storageDir, fileName);
lastPhotoPath = photoFile.getAbsolutePath();
Log.i(TAG, "Photo will be saved to: " + lastPhotoPath);
// Use MediaStore to create the file entry
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATA, lastPhotoPath);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/HollywoodPhotos");
values.put(MediaStore.Images.Media.IS_PENDING, 1);
}
Uri imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (imageUri != null) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, 2001);
Log.i(TAG, "Camera intent started");
return "camera_opened";
} else {
Log.e(TAG, "No camera app available");
lastPhotoPath = "";
return "no_camera_app";
}
} else {
Log.e(TAG, "Failed to create MediaStore entry");
lastPhotoPath = "";
return "media_store_error";
}
} catch (Exception e) {
Log.e(TAG, "openCamera failed: " + e.toString());
lastPhotoPath = "";
return "error: " + e.getMessage();
}
}
// Handle camera result
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2001) {
if (resultCode == RESULT_OK) {
Log.i(TAG, "Camera returned OK, photo path: " + lastPhotoPath);
// Finalize MediaStore entry for Android Q+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && lastPhotoPath != null) {
try {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
String selection = MediaStore.Images.Media.DATA + "=?";
String[] selectionArgs = new String[]{lastPhotoPath};
getContentResolver().update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values, selection, selectionArgs);
Log.i(TAG, "MediaStore entry finalized for: " + lastPhotoPath);
} catch (Exception e) {
Log.e(TAG, "Failed to finalize MediaStore entry", e);
}
}
// Trigger media scan so file is immediately visible to Hollywood
MediaScannerConnection.scanFile(this, new String[]{lastPhotoPath},
new String[]{"image/jpeg"}, null);
} else {
// Camera was cancelled
Log.i(TAG, "Camera was cancelled");
lastPhotoPath = "";
// Clean up pending file if camera was cancelled
if (lastPhotoPath != null) {
try {
File cancelledFile = new File(lastPhotoPath);
if (cancelledFile.exists()) {
cancelledFile.delete();
}
} catch (Exception e) {
Log.e(TAG, "Failed to delete cancelled photo", e);
}
lastPhotoPath = "";
}
}
}
}
// Get the photo path for Hollywood
public String getLastPhotoPath() {
if (lastPhotoPath != null) {
File photoFile = new File(lastPhotoPath);
if (photoFile.exists()) {
Log.i(TAG, "Returning existing photo path: " + lastPhotoPath);
return lastPhotoPath;
} else {
Log.w(TAG, "Photo file doesn't exist: " + lastPhotoPath);
return "";
}
}
return "";
}
// Check if camera is available on the device
public boolean isCameraAvailable() {
try {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
return intent.resolveActivity(getPackageManager()) != null;
} catch (Exception e) {
Log.e(TAG, "isCameraAvailable failed", e);
return false;
}
}
// ================================================================
// π GPS LOCATION (Complete Section)
// ================================================================
// Location permission methods
public boolean hasLocationPermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
}
public void requestLocationPermission() {
if (!hasLocationPermission()) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
2003
);
}
}
// Check if location services are enabled
public boolean isLocationEnabled() {
try {
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
if (lm == null) return false;
return lm.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception e) {
Log.e(TAG, "isLocationEnabled failed", e);
return false;
}
}
// Get last known location (quick, cached location)
public String getLastKnownLocation() {
try {
// Check location permission
if (!hasLocationPermission()) {
Log.w(TAG, "Location permission not granted");
return "permission_denied";
}
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
if (lm == null) {
Log.e(TAG, "LocationManager is null");
return "service_unavailable";
}
// Check if location services are enabled
if (!isLocationEnabled()) {
Log.w(TAG, "Location services are disabled");
return "location_disabled";
}
// Try multiple location providers in order of preference
Location location = null;
List<String> providers = lm.getProviders(true);
for (String provider : providers) {
try {
Location loc = lm.getLastKnownLocation(provider);
if (loc != null) {
if (location == null || loc.getAccuracy() < location.getAccuracy()) {
location = loc;
}
}
} catch (SecurityException e) {
Log.w(TAG, "No permission for provider: " + provider);
} catch (Exception e) {
Log.w(TAG, "Error getting location from provider: " + provider, e);
}
}
if (location != null) {
double lat = location.getLatitude();
double lon = location.getLongitude();
float accuracy = location.getAccuracy();
long time = location.getTime();
String result = String.format(Locale.US, "%.6f,%.6f", lat, lon);
Log.i(TAG, "Location found: " + result + " (accuracy: " + accuracy + "m, time: " + time + ")");
return result;
} else {
Log.w(TAG, "No last known location available");
return "no_location_available";
}
} catch (SecurityException e) {
Log.e(TAG, "Location permission denied", e);
return "permission_denied";
} catch (Exception e) {
Log.e(TAG, "getLastKnownLocation failed", e);
return "error: " + e.getMessage();
}
}
// Get location with provider preference (GPS first, then network)
public String getCurrentLocation() {
try {
// Check location permission
if (!hasLocationPermission()) {
return "permission_denied";
}
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
if (lm == null) {
return "service_unavailable";
}
// Check if location services are enabled
if (!isLocationEnabled()) {
return "location_disabled";
}
// Try GPS first for highest accuracy
Location location = null;
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
try {
location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
Log.i(TAG, "Using GPS location");
}
} catch (SecurityException e) {
Log.w(TAG, "No permission for GPS provider");
}
}
// Fallback to network if GPS not available
if (location == null && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
try {
location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
Log.i(TAG, "Using network location");
}
} catch (SecurityException e) {
Log.w(TAG, "No permission for network provider");
}
}
if (location != null) {
double lat = location.getLatitude();
double lon = location.getLongitude();
float accuracy = location.getAccuracy();
String result = String.format(Locale.US, "%.6f,%.6f", lat, lon);
Log.i(TAG, "Current location: " + result + " (accuracy: " + accuracy + "m)");
return result;
} else {
Log.w(TAG, "No current location available from any provider");
return "location_unavailable";
}
} catch (SecurityException e) {
Log.e(TAG, "Location permission denied", e);
return "permission_denied";
} catch (Exception e) {
Log.e(TAG, "getCurrentLocation failed", e);
return "error";
}
}
// Get detailed location info (returns comma-separated: lat,lon,accuracy,time,provider)
public String getDetailedLocation() {
try {
if (!hasLocationPermission()) {
return "permission_denied";
}
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
if (lm == null) return "service_unavailable";
if (!isLocationEnabled()) return "location_disabled";
Location bestLocation = null;
List<String> providers = lm.getProviders(true);
for (String provider : providers) {
try {
Location loc = lm.getLastKnownLocation(provider);
if (loc != null) {
if (bestLocation == null || loc.getAccuracy() < bestLocation.getAccuracy()) {
bestLocation = loc;
}
}
} catch (Exception e) {
// Continue with next provider
}
}
if (bestLocation != null) {
return String.format(Locale.US, "%.6f,%.6f,%.1f,%d,%s",
bestLocation.getLatitude(),
bestLocation.getLongitude(),
bestLocation.getAccuracy(),
bestLocation.getTime(),
bestLocation.getProvider()
);
} else {
return "no_location_available";
}
} catch (Exception e) {
Log.e(TAG, "getDetailedLocation failed", e);
return "error";
}
}
// Open location settings so user can enable location services
public void openLocationSettings() {
try {
Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "openLocationSettings failed", e);
// Fallback to general settings
try {
Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
startActivity(intent);
} catch (Exception e2) {
Log.e(TAG, "Fallback settings also failed", e2);
}
}
}
// ================================================================
// π₯ VIBRATION
// ================================================================
// public void vibrateDevice(int durationMs) {
// try {
// Vibrator v = (Vibrator) getSystemService(VIBRATOR_SERVICE);
// if (v != null) v.vibrate(durationMs);
// } catch (Exception e) {
// Log.e(TAG, "vibrateDevice", e);
// }
// }
public void vibrateNow(int durationMs) {
try {
HollywoodActivity.vibrateDevice(durationMs);
} catch (Exception e) {
Log.e(TAG, "vibrateNow failed", e);
}
}
// ================================================================
// π€ SHARE TEXT
// ================================================================
public void shareText(String message) {
try {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, message);
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, "Share via"));
} catch (Exception e) {
Log.e(TAG, "shareText", e);
}
}
// ================================================================
// π€ SHARE IMAGE
// ================================================================
public void shareImage(String imagePath) {
try {
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
Log.e(TAG, "Image file not found: " + imagePath);
return;
}
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/jpeg");
// Use YOUR existing FileProvider authority
Uri imageUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
imageUri = FileProvider.getUriForFile(this,
getPackageName() + ".fileprovider", // β Changed to match your manifest
imageFile);
} else {
imageUri = Uri.fromFile(imageFile);
}
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, "Share Photo"));
Log.i(TAG, "Sharing image: " + imagePath);
} catch (Exception e) {
Log.e(TAG, "shareImage failed", e);
}
}
// ================================================================
// π CLIPBOARD FUNCTIONS
// ================================================================
// Copy text to clipboard
public void copyToClipboard(String text) {
try {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("Hollywood App", text);
clipboard.setPrimaryClip(clip);
Log.i(TAG, "Text copied to clipboard: " + text);
// Optional: Show a quick toast message
// Toast.makeText(this, "Copied to clipboard", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e(TAG, "copyToClipboard failed", e);
}
}
// Get text from clipboard
public String getFromClipboard() {
try {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
if (clipboard.hasPrimaryClip()) {
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
String text = item.getText().toString();
Log.i(TAG, "Retrieved from clipboard: " + text);
return text;
}
} catch (Exception e) {
Log.e(TAG, "getFromClipboard failed", e);
}
return "";
}
// ================================================================
// π KEEP SCREEN ON
// ================================================================
private boolean screenShouldStayOn = false;
// Keep screen on - call this repeatedly if needed
public void keepScreenOn() {
try {
runOnUiThread(new Runnable() {
@Override
public void run() {
getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
screenShouldStayOn = true;
Log.i(TAG, "Screen keep-on flag set");
}
});
} catch (Exception e) {
Log.e(TAG, "keepScreenOn failed", e);
}
}
// Allow screen to turn off normally
public void allowScreenOff() {
try {
runOnUiThread(new Runnable() {
@Override
public void run() {
getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
screenShouldStayOn = false;
Log.i(TAG, "Screen keep-on flag cleared");
}
});
} catch (Exception e) {
Log.e(TAG, "allowScreenOff failed", e);
}
}
// Force screen on and wake up device (requires WAKE_LOCK permission)
public void wakeUpScreen() {
try {
// This is more aggressive - wakes up the screen if it's off
android.view.Window window = getWindow();
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Log.i(TAG, "Screen woken up and kept on");
} catch (Exception e) {
Log.e(TAG, "wakeUpScreen failed", e);
}
}
// Check if screen is currently kept on
public boolean isScreenKeptOn() {
try {
int flags = getWindow().getAttributes().flags;
return (flags & android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0;
} catch (Exception e) {
Log.e(TAG, "isScreenKeptOn failed", e);
return false;
}
}
// ================================================================
// π MULTI-SENSOR FUNCTIONS
// ================================================================
private Map<Integer, float[]> lastSensorValues = new HashMap<>();
private Map<Integer, SensorEventListener> sensorListeners = new HashMap<>();
// Check if specific sensor type is available
public boolean hasSensor(int sensorType) {
try {
if (sensorManager == null) {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
}
if (sensorManager != null) {
Sensor sensor = sensorManager.getDefaultSensor(sensorType);
return sensor != null;
}
return false;
} catch (Exception e) {
Log.e(TAG, "hasSensor failed for type: " + sensorType, e);
return false;
}
}
// Get all available sensors
public String getAvailableSensors() {
try {
if (sensorManager == null) {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
}
StringBuilder sb = new StringBuilder();
sb.append("Available Sensors:\n\n");
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor sensor : sensors) {
sb.append(sensor.getName()).append("\n");
sb.append(" Type: ").append(getSensorTypeName(sensor.getType())).append("\n");
sb.append(" Vendor: ").append(sensor.getVendor()).append("\n");
sb.append(" Power: ").append(sensor.getPower()).append(" mA\n");
sb.append(" Max Range: ").append(sensor.getMaximumRange()).append("\n");
sb.append(" Resolution: ").append(sensor.getResolution()).append("\n\n");
}
return sb.toString();
} catch (Exception e) {
Log.e(TAG, "getAvailableSensors failed", e);
return "Error getting sensor list";
}
}
// Start listening to any sensor
public boolean startSensor(int sensorType) {
try {
if (!hasSensor(sensorType)) {
Log.w(TAG, "Sensor not available: " + getSensorTypeName(sensorType));
return false;
}
Sensor sensor = sensorManager.getDefaultSensor(sensorType);
SensorEventListener listener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
lastSensorValues.put(event.sensor.getType(), event.values.clone());
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Handle accuracy changes
}
};
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
sensorListeners.put(sensorType, listener);
Log.i(TAG, "Started sensor: " + getSensorTypeName(sensorType));
return true;
} catch (Exception e) {
Log.e(TAG, "startSensor failed for type: " + sensorType, e);
return false;
}
}
// Stop specific sensor
public void stopSensor(int sensorType) {
try {
SensorEventListener listener = sensorListeners.get(sensorType);
if (listener != null) {
sensorManager.unregisterListener(listener);
sensorListeners.remove(sensorType);
lastSensorValues.remove(sensorType);
Log.i(TAG, "Stopped sensor: " + getSensorTypeName(sensorType));
}
} catch (Exception e) {
Log.e(TAG, "stopSensor failed for type: " + sensorType, e);
}
}
// Stop all sensors
public void stopAllSensors() {
try {
for (Map.Entry<Integer, SensorEventListener> entry : sensorListeners.entrySet()) {
sensorManager.unregisterListener(entry.getValue());
}
sensorListeners.clear();
lastSensorValues.clear();
Log.i(TAG, "All sensors stopped");
} catch (Exception e) {
Log.e(TAG, "stopAllSensors failed", e);
}
}
// Get current sensor values
public String getSensorValues(int sensorType) {
try {
float[] values = lastSensorValues.get(sensorType);
if (values == null) return "No data";
StringBuilder sb = new StringBuilder();
sb.append(getSensorTypeName(sensorType)).append(": ");
for (int i = 0; i < values.length; i++) {
sb.append(String.format(Locale.US, "%.4f", values[i]));
if (i < values.length - 1) sb.append(", ");
}
return sb.toString();
} catch (Exception e) {
Log.e(TAG, "getSensorValues failed", e);
return "Error";
}
}
// Helper method to get sensor type names
private String getSensorTypeName(int sensorType) {
switch (sensorType) {
case Sensor.TYPE_ACCELEROMETER: return "Accelerometer";
case Sensor.TYPE_GYROSCOPE: return "Gyroscope";
case Sensor.TYPE_MAGNETIC_FIELD: return "Magnetometer";
case Sensor.TYPE_LIGHT: return "Light";
case Sensor.TYPE_PRESSURE: return "Pressure";
case Sensor.TYPE_PROXIMITY: return "Proximity";
case Sensor.TYPE_GRAVITY: return "Gravity";
case Sensor.TYPE_LINEAR_ACCELERATION: return "Linear Acceleration";
case Sensor.TYPE_ROTATION_VECTOR: return "Rotation Vector";
case Sensor.TYPE_RELATIVE_HUMIDITY: return "Humidity";
case Sensor.TYPE_AMBIENT_TEMPERATURE: return "Temperature";
case Sensor.TYPE_STEP_COUNTER: return "Step Counter";
case Sensor.TYPE_STEP_DETECTOR: return "Step Detector";
case Sensor.TYPE_ORIENTATION: return "Orientation";
default: return "Unknown (" + sensorType + ")";
}
}
}
Then I changed the hollywood script accordingly. I also made hollywood save the listing of all available sensors into a file sensors.txt
Code: Select all
; Light sensor example
@DISPLAY {Title = "Light sensor Test", ScaleMode = #SCALEMODE_AUTO, FitScale = True, SmoothScale = True, HideTitleBar = True}
; Define sensor constants (since @ENUM won't work)
Const #SENSOR_LIGHT = 5
ok = CallJavaMethod("hasAllFilesAccess", {ReturnType=#BOOLEAN})
If Not ok
NPrint("App needs ALL FILES ACCESS. Opening settings...")
CallJavaMethod("requestAllFilesAccess")
NPrint("Press to continue after granting permission")
WaitLeftMouse
EndIf
ok = CallJavaMethod("createFolder", {ReturnType=#BOOLEAN}, #STRING, "SensorList"); creates a new folder under /Downloads (Or eg. Documents if specified in java file)
Function p_TestLightSensor()
; Check if device has light sensor
hasSensor = CallJavaMethod("hasSensor", {ReturnType=#BOOLEAN}, #INTEGER, #SENSOR_LIGHT)
If hasSensor
TextOut(10, 30, "Light sensor available!")
; Get all available sensors info
sensorInfo$ = CallJavaMethod("getAvailableSensors", {ReturnType=#STRING})
; Show only light sensors on screen
lightSensorInfo$ = p_GetLightSensorInfo$(sensorInfo$)
TextOut(10, 60, lightSensorInfo$)
; Still save full list to file
ok = CallJavaMethod("createFile", {ReturnType=#BOOLEAN}, #STRING, "SensorList", #STRING, "Sensors.txt", #STRING, sensorInfo$)
; Start monitoring
CallJavaMethod("startSensor", {ReturnType=#BOOLEAN}, #INTEGER, #SENSOR_LIGHT)
TextOut(10, 300, "Light sensor started...")
; Get light values (returns string with lux value)
lightValues$ = CallJavaMethod("getSensorValues", {ReturnType=#STRING}, #INTEGER, #SENSOR_LIGHT)
;getsensorvalue returns a string formatted like "Light: xxx.0000". Removing text before converting to number
Local n = FindStr(lightvalues$, ":")
Local lv$ = LeftStr(lightvalues$, n+1)
Local lightvalues$ = ReplaceStr(lightvalues$, lv$, "")
Local lightValue = ToNumber(lightvalues$)
TextOut(10, 330, "Light: " .. lightValue .. " lux");
; Stop monitoring
CallJavaMethod("stopSensor", {ReturnType=#VOID}, #INTEGER, #SENSOR_LIGHT)
TextOut(10, 360, "Light sensor stopped")
Else
TextOut(10, 30, "No light sensor available on this device")
EndIf
EndFunction
; Get only light sensor info from the full list
Function p_GetLightSensorInfo$(sensorInfo$)
Local lines, c = SplitStr(sensorInfo$, "\n")
Local result$ = "Light Sensors:\n\n"
Local foundLight = False
For i = 1 To c
line$ = lines[i-1]
; Check if this line contains a light sensor (look for " Light" with space)
If FindStr(line$, "Light") > 0 ;<> Nil
foundLight = True
result$ = result$ .. line$ .. "\n"
; Add the next 5 lines (details)
For j = 1 To 5
If (i + j - 1) <= c
result$ = result$ .. lines[i + j - 1] .. "\n"
EndIf
Next
result$ = result$ .. "\n"
Break ; Found our light sensor, no need to continue
EndIf
Next
If Not foundLight
result$ = result$ .. "No light sensors found"
EndIf
Return(result$)
EndFunction
Function p_HandlerFunc(msg)
Switch(msg.Action)
Case "OnMouseDown":
sel = SystemRequest("Quit?", "Quit light measuring?", "Yes|No")
Switch sel
Case 1:
CallJavaMethod("stopSensor", {ReturnType=#VOID}, #INTEGER, #SENSOR_LIGHT)
Wait(10)
quitnow = True
EndSwitch
EndSwitch
EndFunction
InstallEventHandler({OnMouseDown = p_HandlerFunc})
SetFillStyle(#FILLCOLOR)
SetFont(#SANS, 24)
Repeat
CheckEvent
Box(0,0,700,600, #BLACK)
TextOut(10, 0, "=== LIGHT SENSOR TEST ===")
result$ = p_TestLightSensor()
Wait(50) ; Wait 1 second
Until quitnow