Android 11 - how to detect programmatically when a SIM is inserted? - android-11

I am trying to catch an event in Android 11 that would get triggered when a SIM card is inserted in a phone. The following question mentions how to fetch the unique subscription ID, to know if the SIM is changed but it does not address how to catch that event of SIM insertion.
Detect SIM card change on Android Q 10
var subscriptionManager = getSystemService(SubscriptionManager::class.java)
subscriptionManager.getActiveSubscriptionInfoList()
SubscriptionInfo.getSubscriptionId()
Please let me know the right approach to handle SIM insertion event. Appreciate your help.

If you want an event/callback for SIM insertion, the best way you can do this is with broadcast receivers.
class SimChangeReceivers: BroadcastReceiver() {
private val TAG = "SimChangeReceivers"
// This is where you'll be receiving the SIM_STATE_CHANGE intent.
override fun onReceive(p0: Context?, p1: Intent?) {
var state = ""
if (p1 != null) {
state = p1.extras?.getString("ss").toString()
if (state == "LOADED")
Log.i(TAG, "SIM Insertion Detected")
}
Log.i(TAG, "SIM State Change Detected $state")
}
}
Make sure, that you add this receiver in your manifest, along with the READ_PHONE_STATE permission.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
....
<receiver android:name=".SimChangeReceivers"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SIM_STATE_CHANGED"/>
</intent-filter>
</receiver>
You can consider when state to be either READY or LOADED as SIM insertion.
Check out this article on Faanghut, which talks about getting an intent for SIM_STATE_CHANGED. Hope this helps, if you any concerns regarding this, do let me know.

Related

onActivityResult not being called when Preference Fragment calls it as a parent

My app records GNSS positions as a tool to produce Orienteering's map using a cell phone. The main activity does all the job and when the mapper needs to export the field job done, app calls a child activity (Save_File) responsible to save on Documents/Oribooklet directory a file, using gpx format. Because of getExternalStoragePublicDirectory obsolescence, SAF is the way to choose to go. I am not an IT guy, I did this for fun, that is why I am so late with this matter: users drop me messages saying they couldn't save the field job anymore.
Main: Oribooklet
public class Oribooklet extends AppCompatActivity {
...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Mapper clicked on a menu option in the app bar overflow menu
Intent intent;
switch (item.getItemId()) {
// Respond to a click on the "Save" menu option
case R.id.action_saveFile:
// Call the Save_File Class
// Prepare to show Save UI
// Save to Shared Preference
SharedPreferences sharedPref = getSharedPreferences("user_preferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean("bShowSaveUI", true);
editor.apply();
intent = new Intent(Oribooklet.this, Save_File.class);
startActivity(intent);
return true;
// Respond to a click on the "Preference" menu option
case R.id.action_settings:
// Call the Class Activity_Preference for options menu
intent = new Intent(Oribooklet.this,Activity_Preference.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
Inside Save_File activity I implemented and it worked fine: when the mapper push Save, startActivityForResult is triggered, then an Android file picker starts, mapper choose where to save.
void createExternalStoragePublicDocument(String fileName) {
try {
// Call SAF
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(INTENT_TYPE);
intent.putExtra(Intent.EXTRA_TITLE, fileName);
// https://stackoverflow.com/questions/6147884/onactivityresult-is-not-being-called-in-fragment
startActivityForResult(intent, CREATE_REQUEST_CODE);
} catch (Exception excep) {
excep.printStackTrace();
}
}
Then onActivityResult gets the returned Uri to complete the job by filling the file with the data collected on the field. Couldn't be any better!
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
super.onActivityResult(requestCode, resultCode, resultData);
Uri currentUri = null;
if (resultCode == Activity.RESULT_OK) {
if (requestCode == CREATE_REQUEST_CODE) {
if (resultData != null) {
currentUri = resultData.getData();
// Write contents
writeFileContent(currentUri, fileData);
}
} else if (requestCode == OPEN_REQUEST_CODE) {
if (resultData != null) {
currentUri = resultData.getData();
sendByMail(stringEMailAddress, stringSubject, currentUri);
// Back to Oribooklet
finish();
}
}
}
}
The app has a Preference fragment to set up some parameters. One of them is the standard to be used. Two standards must not be mixed doing a map. When the mapper changes the map's type, Preference used to call Save_File to do the job so no mix of data happens. It used to work fine.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
final String key) {
// Find the one that changed and address it
Preference connectionPref = findPreference(key);
switch (key){
case "list_iof":
// IOF´s element set
SharedPreferences preferences = getActivity().getSharedPreferences("user_preferences", MODE_PRIVATE);
// Update preference Summary
ListPreference listIOFPreference = (ListPreference) findPreference("list_iof");
CharSequence iof = listIOFPreference.getEntry();
connectionPref.setSummary(getResources().getString(R.string.pref_iof_summary_1) +
iof + "\" " +
getResources().getString(R.string.pref_iof_summary_2));
// Save the field job to avoid IOF set mixing
Intent intent = new Intent(getActivity(), Save_File.class);
startActivity(intent);
break;
After SAF, the onActivityResult of Save_File is never triggered, startActivityForResult triggers the file provider but when the mapper chooses the place to save, instead of onActivityResult of Save_File it returns to Preference so the file is created empty.
I did many tests, debugging with many breaking points, setting and removing super in quite a few places, checked all S.O. posts about the matter without success.
Any idea?
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_oribooklet_v0"
android:name=".MyAppContext"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<!--android:requestLegacyExternalStore="true" -->
<!-- android:roundIcon="#mipmap/ic_oribooklet_v2"-->
<activity android:name="com.hbcavalcanti.oribooklet.Oribooklet"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- A child of the main activity -->
<activity
android:name=".Save_File"
android:label="#string/action_saveFile"
android:parentActivityName=".Oribooklet" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".Oribooklet" />
</activity>
<activity
android:name=".Activity_Preference"
android:label="#string/action_settings"
android:parentActivityName=".Oribooklet" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".Oribooklet" />
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.hbcavalcanti.oribooklet.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
</application>
When called from Preference, the Save File method used not to make any UI call, then its onActivityResult was never called.
Just for test purpose, I introduced one onActivityResult on Preference fragment and it received a trigger. I removed after the test.
I fixed the issue by also calling an UI inside Save File when Preference invoque it. This trigger its onActivityResult making everything works fine like being called from its parent.

How to detect a change in Hardware(sim Change) using Xamarin

How to access event when sim card is changed in mobile(Xamarin)?
I have searched and got References in android(Java) I even tried this example
But its not triggering . Can I get any link related to Xamarin ?.
You can use this simple code to detect SIM changes.
Add new class file to your Android project SimStateChangedReceiver.cs
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "android.intent.action.SIM_STATE_CHANGED"}, Priority = (int)IntentFilterPriority.HighPriority)]
public class SimStateChangedReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent0)
{
Toast.MakeText(Application.Context, "Sim state has been changed", ToastLength.Long).Show();
}
}
Also provide READ_PHONE_STATE permission in your manifest
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
When you change SIM in your phone OnReceive method will fire.

Is there a way to distinguish between Shutdown and Restart in Windows 7 and later? [duplicate]

I know that when Windows is shutting down, it sends a WM_QUERYENDSESSION message to each application. This makes it easy to detect when Windows is shutting down. However, is it possible to know if the computer going to power-off or is it going to restart after Windows has shutdown.
I am not particularly hopeful, considering the documentation at MSDN has this to say about WM_QUERYENDSESSION: "...it is not possible to determine which event is occurring," but the cumulative cleverness of stackoverflow never ceases to amaze me.
In Windows 7 (and probably also in Vista / 8 / Server) you could use the system events to track whether Windows is shutting down (and powering off the computer) or just restarting. Every time a shutdown/reboot is initiated (by any means - clicking the button in Start menu, or programmatically), Windows 7 writes one or two events in the System log, source USER32, event ID 1074. You can see these events recorded if you open the Event Viewer from Administrative Tools (filter the System log to see only ID 1074). The description (message) of these events contains the shutdown type. So you could parse the description of the most recent event of this type (after the shutdown was initiated), looking for the necessary word (shutdown, reboot/restart).
I didn't try to see the shutdown type written in the event when using the power button to gracefully shutdown Windows (I usually disable this function), but some site suggests that it states a "power off" type instead of "shutdown" - so check it out, if you need to be sure. Or simply look for a "reboot" type - if it's not found, then a "shutdown" type is assumed.
In Windows XP, from my experience, an event 1074 is recorded only if the shutdown/reboot is done programmatically (e.g. during a program install or using the shutdown.exe utility). So it does not register the shutdowns initiated from the shell (Explorer), but perhaps you could combine this method with reading the value from registry as proposed in another answer. Also, keep in mind that in WinXP the message of event 1074 contains the word "restart" no matter what the real type of shutdown is, so you should look at the "Shutdown Type:" field, which will state either "shutdown" or "reboot".
Related to this, an event ID 1073 is recorded whenever Windows fails to shutdown/reboot for some reason (e.g. if an application doesn't allow to shutdown as a response to WM_QUERYENDSESSION). In that case the message will also contain words as "shutdown", "reboot" or "power off" - in WinXP. For Win7 this type of event is less useful in our case, since it won't make any difference between shutdown and reboot. But for WinXP - if you only need to intercept the shutdown/reboot, perform some actions, then continue the corresponding shutdown or reboot process - it should work as expected.
From here:
You can read the DWORD value from
"HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shutdown
Setting" to determine what the user
last selected from the Shut Down
dialog.
A bit of a roundabout solution, but it should do the trick.
A trick that usually works is to trap WM_ENDSESSION and log it. Now keep track of the time. If the system comes back up within a reasonable peroid (say 5 minutes). Then that was a reboot, not a shutdown.
Idea: If the system comes back up within 5 minutes, does it really matter if the user clicked 'shutdown' or 'reboot'?
If you really need to detect a shutdown (and the only reason I think you'd need to do this is if you're depending upon an obscure behavioral software difference between a shutdown vs a reboot) you could investigate API hooking of ExitWindowsEx and related functions but I don't recommend this approach. Rethink if you really need to detect this directly.
Possible experimental solution for Windows7 could be the following. (I'm not sure if this works well with other localizations, therefore I would call it a workaround)
using System.Diagnostics.Eventing.Reader;
namespace MyApp
{
public class RestartDetector : IDisposable
{
public delegate void OnShutdownRequsted(bool restart);
public OnShutdownRequsted onShutdownRequsted;
private EventLogWatcher watcher = null;
public RestartDetector()
{
try
{
EventLogQuery subscriptionQuery = new EventLogQuery(
"System", PathType.LogName, "*[System[Provider[#Name='USER32'] and (EventID=1074)]]");
watcher = new EventLogWatcher(subscriptionQuery);
// Make the watcher listen to the EventRecordWritten
// events. When this event happens, the callback method
// (EventLogEventRead) is called.
watcher.EventRecordWritten +=
new EventHandler<EventRecordWrittenEventArgs>(
EventLogEventRead);
// Activate the subscription
watcher.Enabled = true;
}
catch (EventLogReadingException e)
{
}
}
public void EventLogEventRead(object obj, EventRecordWrittenEventArgs arg)
{
bool restart = false;
try
{
// Make sure there was no error reading the event.
if (arg.EventRecord != null)
{
String[] xPathRefs = new String[1];
xPathRefs[0] = "Event/EventData/Data";
IEnumerable<String> xPathEnum = xPathRefs;
EventLogPropertySelector logPropertyContext = new EventLogPropertySelector(xPathEnum);
IList<object> logEventProps = ((EventLogRecord)arg.EventRecord).GetPropertyValues(logPropertyContext);
string[] eventData = (string[])logEventProps[0];
foreach (string attribute in eventData)
{
if (attribute.Contains("restart")) { restart = true; break; }
}
}
}
catch (Exception e)
{
}
finally
{
if (onShutdownRequsted != null) { onShutdownRequsted(restart); }
}
}
public void Dispose()
{
// Stop listening to events
if (watcher != null)
{
watcher.Enabled = false;
watcher.Dispose();
}
}
}
}
The following is an example of XML which is written to the event log when a PC is restarted:
- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
<Provider Name="USER32" />
<EventID Qualifiers="32768">1074</EventID>
<Level>4</Level>
<Task>0</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2015-12-15T11:10:43.000000000Z" />
<EventRecordID>90416</EventRecordID>
<Channel>System</Channel>
<Computer>WIN7PC</Computer>
<Security UserID="S-1-5-21-1257383181-1549154685-2724014583-1000" />
</System>
- <EventData>
<Data>C:\Windows\system32\winlogon.exe (WIN7PC)</Data>
<Data>WIN7PC</Data>
<Data>No title for this reason could be found</Data>
<Data>0x500ff</Data>
<Data>restart</Data>
<Data />
<Data>WIN7PC\WIN7PCUser</Data>
<Binary>FF00050000000000000000000000000000000000000000000000000000000000</Binary>
</EventData>
</Event>

Ibeacon regions closed sets?

We are trying to use Altbeacon library to satisfy the next study case:
We want to put several IBeacons in a room or corridor with a distance of no more than 3 meters between each of them, and we want to get the current closest Ibeacon based on the user phone which scans for the beacons.
We first tried to build regions with only one beacon each, wondering that a region were a closed set, meaning that when you enter in a region, you couldn’t be in other region at the same time, and when you leave a region, you enter in the next closest one and so. But that’s not the approach that the library implements.
We want to know if there’s any way in Altbeacon library to apply our approach or if some kind of patch has to be made to satisfy the study case that I present to you.
The easiest way to accomplish this goal is to range for all beacons using a single region, and start ranging:
#Override
public void onBeaconServiceConnect() {
try {
// Set up a region that matches all of your beacons. You may want to replace the first
// null with a UUID that all your beacons share.
Region allBeaconsRegion = new Region("all beacons", null, null, null);
beaconManager.startRangingBeaconsInRegion(mAllBeaconsRegion);
beaconManager.setRangeNotifier(this);
} catch (RemoteException e) {
Log.e(TAG, "Cannot connect to beacon service");
}
}
Note, if you are using a custom Application class with the RegionBootstrap, you can put the above code above inside the didEnterRegion method instead of inside the onBeaconServiceConnect method.
Once you start ranging, you will get a callback once per second with a list of all visible beacons. You can add code to determine which one is closest:
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region arg1) {
Beacon closestBeacon = null;
for (Beacon beacon : beacons) {
if (closestBeacon == null) {
closestBeacon = beacon;
}
else {
if (closestBeacon.getDistance() > beacon.getDistance()) {
closestBeacon = beacon;
}
}
}
// Do Something with closestBeacon here
}
Keep in mind that the closest beacon may change back and forth due to radio noise, so you probably need to add extra logic to protect against the closest beacon flipping back and forth too often.

How to know when a HID USB/Bluetooth device is connected in Cocoa?

How can I get a simple call back when a HID device, or at last, any USB/Bluetooth device gets connected/disconnected?
I made a simple app that shows the connected joysticks and the pressed buttons/axis for mac in a pretty way. Since I am not very familiar with cocoa yet, I made the UI using a webview, and used the SDL Joystick library.
Everything is working nice, the only problem is that the user needs to scan for new joysticks manually if he/she connects/disconnects something while the program is running.
With a callback, I I can just call the Scan function. I don't want to handle the device or do something fancy, just know when there is something new happening...
Thanks.
Take a look at IOServiceAddMatchingNotification() and related functions. I've only worked with it in the context of serial ports (which are in fact USB to serial adapters, though that doesn't matter), but it should be applicable to any IOKit accessible device. I'm not sure about Bluetooth, but it should at least work for USB devices. Here's a snippet of code I use:
IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notificationPort),
kCFRunLoopDefaultMode);
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOSerialBSDServiceValue);
CFRetain(matchingDict); // Need to use it twice and IOServiceAddMatchingNotification() consumes a reference
CFDictionaryAddValue(matchingDict, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDRS232Type));
io_iterator_t portIterator = 0;
// Register for notifications when a serial port is added to the system
kern_return_t result = IOServiceAddMatchingNotification(notificationPort,
kIOPublishNotification,
matchingDictort,
SerialDeviceWasAddedFunction,
self,
&portIterator);
io_object_t d;
// Run out the iterator or notifications won't start (you can also use it to iterate the available devices).
while ((d = IOIteratorNext(iterator))) { IOObjectRelease(d); }
// Also register for removal notifications
IONotificationPortRef terminationNotificationPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(terminationNotificationPort),
kCFRunLoopDefaultMode);
result = IOServiceAddMatchingNotification(terminationNotificationPort,
kIOTerminatedNotification,
matchingDict,
SerialPortWasRemovedFunction,
self, // refCon/contextInfo
&portIterator);
io_object_t d;
// Run out the iterator or notifications won't start (you can also use it to iterate the available devices).
while ((d = IOIteratorNext(iterator))) { IOObjectRelease(d); }
My SerialPortDeviceWasAddedFunction() and SerialPortWasRemovedFunction() are called when a serial port becomes available on the system or is removed, respectively.
Relevant documentation is here, particularly under the heading Getting Notifications of Device Arrival and Departure.
Use IOHIDManager to get the notifications.
Based on the earlier answers from Andrew and Arjuna, I ended up with the following snippet using IOHIDManager that should work with an Apple HID device (e.g. a bluetooth trackpad was tested). This appears to also send notifications more than once without needing to clear/decrement anything.
- (void) startHIDNotification
{
ioHIDManager = IOHIDManagerCreate ( kCFAllocatorDefault, kIOHIDManagerOptionNone );
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOHIDDeviceKey);
CFDictionaryAddValue(matchingDict, CFSTR(kIOHIDManufacturerKey), CFSTR("Apple"));
IOHIDManagerSetDeviceMatching (ioHIDManager, matchingDict);
IOHIDManagerRegisterDeviceMatchingCallback( ioHIDManager, AppleHIDDeviceWasAddedFunction, (__bridge void *)(self) );
IOHIDManagerRegisterDeviceRemovalCallback( ioHIDManager, AppleHIDDeviceWasRemovedFunction, (__bridge void *)(self) );
hidNotificationRunLoop = CFRunLoopGetCurrent();
IOHIDManagerScheduleWithRunLoop(ioHIDManager,
hidNotificationRunLoop,
kCFRunLoopDefaultMode);
}
and the callback methods
void AppleHIDDeviceWasAddedFunction( void * context,
IOReturn result,
void * sender,
IOHIDDeviceRef device)
{
NSLog(#"added");
}
void AppleHIDDeviceWasRemovedFunction( void * context,
IOReturn result,
void * sender,
IOHIDDeviceRef device)
{
NSLog(#"removed");
}

Resources