Reset Raspberry Pi 3 Model B through code [duplicate] - raspberry-pi3

I want to use this code in order to reboot my RPI3 running Android Things:
public static void Reboot()
{
try {
Process proc = Runtime.getRuntime().exec(new String[]{"su", "-c", "reboot"});
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
}
I get the following error:
java.io.IOException: Cannot run program "su": error=13, Permission denied
I add to the manifest all the permission
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.SET_TIME_ZONE"/>
<uses-permission android:name="android.permission.SHUTDOWN"/>
Am I missing something?

/system/bin/reboot binary in DP 4, so as in all the previous dev previews, has world-executable permission, i.e. the following yields
adb shell ls -l /system/bin | grep reboot
-rwxr-xr-x 1 root shell ... reboot
That said, it is yet possible to execute the binary for any user (a.k.a app process in Android) without a need to grab su. Just execute in Java for
rebooting
Runtime.getRuntime().exec("reboot");
or for powering off
Runtime.getRuntime().exec("reboot -p");
No permission's needed in AndroidManifest.xml to run the binary successfully.
Caution: in case of security model changes in newer OS versions this approach may not work.

You can now do a reboot using:
https://developer.android.com/things/reference/com/google/android/things/devicemanagement/DeviceManager.html
Example
public class SomeActivity extends Activity {
void doReboot() {
DeviceManager.getInstance().reboot();
}
void doFactoryReset() {
boolean wipeExternalCard = true;
DeviceManager.getInstance().factoryReset(wipeExternalCard);
}
}
You need the com.google.android.things.permission.REBOOT permission

Access to system-protected features (such as those provided by the PowerManager.reboot() API) will be available to apps running on Android Things in a future developer preview release. You cannot (and should not) attempt to run your app process as the root user via su.
As a side note, the developer images for Android Things are built as userdebug, which means you can access root from the shell by simply rebooting the ADB daemon with the adb root command before you attempt to access the shell. This gives you any root access you may need during development without compromising the device security and allowing app processes to run as root.

You need a root access.
public static void runCmd(String cmd) {
DataOutputStream os;
try {
Process process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(cmd + "\n");
os.writeBytes("exit\n");
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Then you can run any commands that require root access like this: runCmd("reboot");

Related

Get reminders based on data in a database

I want to get reminders for some Appointments that I have saved in database and they have a notificationTime property witch is the time when a notification needs to be displayed.
My approach so far is to write some kind of job that runs 1 or 2 times a day to pull the notifications that need to be registered in the next 24h and ofc register them (if you guys have a better ideea lmk :D )
This works BUT:
Only if the app is in foreground / background; then I get notification every 15min or so;
If I KILL the app I don't receive notification on my physical device (Xiaomi Redmi Note 9 Pro with Android version 12 SKQ),
only on the virtual one (Pixel 5 Android 13)
Right now I have a class that extends JobService and I use JobScheduler to schedule the Job to run every 15 min (for testing so I don't need to w8 12h xD )
Here is the JobScheduler witch I call in MainActivity file in OnCreate method
Console.WriteLine("Schedualing job");
TimeSpan interval = TimeSpan.FromMinutes(15);
var javaClass = Java.Lang.Class.FromType(typeof(NotificationService));
var componentName = new ComponentName(Application.Context, javaClass);
var jobInfo = new JobInfo.Builder(1, componentName)
.SetPeriodic(15 * 60 * 1000, 30 * 60 * 1000)
.SetRequiredNetworkType(NetworkType.Any)
.SetPersisted(true)
.Build();
var jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
var resultCode = jobScheduler.Schedule(jobInfo);
and here is the NotificationService.cs
[Service(Name = "com.companyname.deratizare_mobile.NotificationService",
Permission = "android.permission.BIND_JOB_SERVICE")]
public class NotificationService : JobService
{
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
return StartCommandResult.StickyCompatibility;
}
public override bool OnStartJob(JobParameters #params)
{
Console.WriteLine("Job started");
Task.Run(async () =>
{
//var hasSuccessful = await ProccessNotificationToRegister();
var notification = new NotificationRequest
{
Title = "Job",
Description = $"Description",
Schedule = new NotificationRequestSchedule
{
NotifyTime = DateTime.Now,
}
};
LocalNotificationCenter.Current.Show(notification);
JobFinished(#params, false);
Console.WriteLine("Job finished");
});
return true;
}
public override bool OnStopJob(JobParameters #params)
{
Console.WriteLine("Job stopped");
return true;
}
}
AndroidManifest
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.BIND_JOB_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
UPDATE
I have given permission to auto start to my app from the device and it works
SOLUTION
I ended up using FCM and a hosted service on the server that checks the cache every 5 minutes where I have stored the next notification that needs to be displaied
You can try to use Firebase push notifications.
With push notifications, you can update your users without requiring the app to run at all times or having it poll a server, potentially running down the battery.
For more information, you can check Implementing Push Notifications in Your Android Apps and Firebase Cloud Messaging.

How to know the wifi SSID my device is connected to in Xamarin?

I have an app that needs to be connected to a specific network. I already have a code to force the device to connect to that network, but every time I open a different screen it repeats the process and it takes like 2 or 3 seconds. So, instead of forcing to connect every time I want to ask in what network it is in that moment, so, if it's the incorrect network it has to connect to the correct one, and if it's in the correct one it doesn't have to do anything. How can I get the network's name?
Below is the code I am using, but when I debug it it says the SSID name is "<unknown ssid>", so every time I check if the name is correct it says that is false and it connects again to the network.
public static string GetSSID() {
WifiManager wifiManager = (WifiManager)(Android.App.Application.Context.GetSystemService(Context.WifiService));
if (wifiManager != null && !string.IsNullOrEmpty(wifiManager.ConnectionInfo.SSID))
{
return wifiManager.ConnectionInfo.SSID;
}
else
{
return "WiFiManager is NULL";
}
}
At first, you need to grant the app the permission about the location.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
And then you need to grant the permisson by the ActivityCompat.RequestPermissions before you get the information of the wifi.
The official document about run-time permission:
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/permissions?tabs=windows
In addition, you can also try the following code to get the SSID after the permission granting.
ConnectivityManager connectivityManager = (ConnectivityManager)Android.App.Application.Context.GetSystemService(Context.ConnectivityService);
NetworkInfo networkInfo = connectivityManager.ActiveNetworkInfo;
var ssid = networkInfo.ExtraInfo;

Error opening camera with Xamarin.Forms and Prism

Code Behind
async Task BtnCameraEvento()
{
try
{
await CrossMedia.Current.Initialize();
//Verifica se a camera está disponivel
if (!CrossMedia.Current.IsTakePhotoSupported || !CrossMedia.Current.IsCameraAvailable)
{
await App.Current.MainPage.DisplayAlert("Aviso", "Nenhuma camera detectada", "OK");
return;
}
//tira a foto
var file = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions
{
SaveToAlbum = false,
Directory = "Demo",
Name = "foto"
});
//Verifica se foi tirado alguma foto
if (file == null)
return;
//Adiciona a foto a lista de imagens
_imageList.Add(file.Path);
}
catch (Exception ex)
{
int x = 1;
}
}
The following error appears in the line "CrossMedia.Current.TakePhotoAsync":
"Unable to get file location. This most likely means that the file provider information is not set in your Android Manifest file. Please check documentation on how to set this up in your project."
See particularly this section of the docs linked by sushihangover:
https://github.com/jamesmontemagno/MediaPlugin#android
Copied here in case link ever breaks:
Android
The WRITE_EXTERNAL_STORAGE & READ_EXTERNAL_STORAGE permissions are required, but the library will automatically add this for you. Additionally, if your users are running Marshmallow the Plugin will automatically prompt them for runtime permissions. You must add the Permission Plugin code into your Main or Base Activities:
Add to Activity:
public override void OnRequestPermissionsResult(int requestCode, string[]
permissions, Android.Content.PM.Permission[] grantResults)
{
Plugin.Permissions.PermissionsImplementation.
Current.OnRequestPermissionsResult
(requestCode, permissions, grantResults);
}
Android Current Activity Setup
This plugin uses the Current Activity Plugin to get access to the current Android Activity. Be sure to complete the full setup if a MainApplication.cs file was not automatically added to your application. Please fully read through the Current Activity Plugin Documentation. At an absolute minimum you must set the following in your Activity's OnCreate method:
CrossCurrentActivity.Current.Init(this, bundle);
It is highly recommended that you use a custom Application that are outlined in the Current Activity Plugin Documentation](https://github.com/jamesmontemagno/CurrentActivityPlugin/blob/master/README.md)
Android Misc Setup
By adding these permissions Google Play will automatically filter out devices without specific hardware. You can get around this by adding the following to your AssemblyInfo.cs file in your Android project:
[assembly: UsesFeature("android.hardware.camera", Required = false)]
[assembly: UsesFeature("android.hardware.camera.autofocus", Required = false)]
Android File Provider Setup
You must also add a few additional configuration files to adhere to the new strict mode:
1.) Add the following to your AndroidManifest.xml inside the <application> tags:
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
2.) Add a new folder called xml into your Resources folder and add a new XML file called file_paths.xml. Make sure that this XML file has a Build Action of: AndroidResource.
Add the following code:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="my_images" path="Pictures" />
<external-files-path name="my_movies" path="Movies" />
</paths>
You can read more at: https://developer.android.com/training/camera/photobasics.html

Xamarin Android Facebook AppInviteDialog not showing

I'm using the Xamarin.FacebookSdk to display the App Invite Dialog. For iOS everything works great but for Android, nothing displays.
Update
It turns out iOS isn't always working. I actually get the following error sometimes:
[0:] Invite Failed Error Domain=com.facebook.sdk.core Code=9 "(null)"
I can step through the following code until it gets to the AppInv.Show. However, Show never shows anything. I tried having the Facebook app installed and without it installed.
public class FacebookService : IFacebookService
{
public void InviteFriends(string appLinkUrl, string previewImageUrl)
{
if (AppInviteDialog.CanShow())
{
var activity = Xamarin.Forms.Forms.Context as Activity;
var content = new AppInviteContent.Builder().SetApplinkUrl(appLinkUrl).SetPreviewImageUrl(previewImageUrl).Build() as AppInviteContent;
//AppInviteDialog.Show(activity, content);
AppInviteDialog AppInv = new AppInviteDialog(activity);
var callbackManager = CallbackManagerFactory.Create();
var invitecallback = new CCallback();
AppInv.RegisterCallback(callbackManager, invitecallback);
AppInv.Show(content);
}
}
}
public class CCallback : Java.Lang.Object, IFacebookCallback
{
public void OnCancel()
{
System.Diagnostics.Debug.WriteLine($"Invite was cancelled");
}
public void OnError(FacebookException error)
{
System.Diagnostics.Debug.WriteLine($"Invite failed {error.Message}");
}
public void OnSuccess(Java.Lang.Object result)
{
System.Diagnostics.Debug.WriteLine($"Invite was a success: {result}");
}
}
I added the following to the AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
........
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/app_id" />
<activity android:name="com.facebook.FacebookActivity" android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:theme="#android:style/Theme.Translucent.NoTitleBar" android:label="#string/app_name" />
<provider android:authorities="com.facebook.app.FacebookContentProviderXXXXXMy App IdXXXX" android:name="com.facebook.FacebookContentProvider" android:exported="true" />
It turns out that AppInviteDialog was deprecated by Facebook.
It sure would have been nice for a more informative error to be displayed.

Geo location is not working in xamarin android

I am try to get the current geo location of the phone using 'plugin.geolocator' but it works fine in ios in android getting task cancellation exception. Here is the code I have tried. Please suggest any idea why I am getting this exception.
sample code:
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = -1;
if (locator.IsGeolocationEnabled)
{
var position = await locator.GetPositionAsync(TimeSpan.FromMilliseconds(5000));
}
These are the permissions I have gave in android manifest file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
I am getting task cancellation exception while I am testing in emulator. I have tried with changing time span but no luck getting task cancellation exception only.
Set a different value for Desired accuracy (big values -> more chance to have a result):
locator.DesiredAccuracy = 100;
Well, you also have to override OnRequestPermissionResult on your MainActivity class:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
And ensure your Android Target version is API 25+. See https://jamesmontemagno.github.io/GeolocatorPlugin/GettingStarted.html

Resources