How does shareit discovers nearby devices android programmatically [duplicate] - java

This question already has answers here:
How the "SHAREit" android application works technically?
(2 answers)
Closed 1 year ago.
I'm want to create a file sharing app like shareit but I'm really confused about how shareit discovers the nearby devices.
When you click receive button shareit creates a hotspot at the receiver side and the sender without connecting to the hotspot shows the receiver name. How is that possible?
If shareit uses Wi-Fi direct then what's the point of creating hotspot?
And to use Network Service Discovery (NSD) both server and client should be on same network so I think shareit is using something else
If anyone can explain this concept of shareit it will be very helpful.

I finally found the answer! SHAREit uses WiFi SSID to identify the nearby app users.
The SSID Consist of two partslike this. BAHD-bXViYQ WHERE 'B' Stands for ANDROID DEVICE and the AHD for the user icon. the second part is the user name encoded in Base64. In this example my name muba.
I hope this answer helps save some time.

Well I have found how to enable the hotspot from one sharing app and find the list of available wifi enabled by that sharing app into another one. just like shareIt receiver enables the wifi hotspot and sender discovers the list of available receivers.
First of all You have to scan all available wifi network using WifiManager
public void startScan(){
mWifiManager.startScan();
mScanResultList = mWifiManager.getScanResults();
mWifiConfigurations = mWifiManager.getConfiguredNetworks();
}
now pass this mScanResultList to a method which finds the network according to your requirement.
public static List<ScanResult> filterWithNoPassword(List<ScanResult> scanResultList){
if(scanResultList == null || scanResultList.size() == 0){
return scanResultList;
}
List<ScanResult> resultList = new ArrayList<>();
for(ScanResult scanResult : scanResultList){
if(scanResult.capabilities != null && scanResult.capabilities.equals(NO_PASSWORD) || scanResult.capabilities != null && scanResult.capabilities.equals(NO_PASSWORD_WPS)){
resultList.add(scanResult);
}
}
return resultList;
}
Now pass the resultList to arraylist adapter to show the network in list. Inside adapter's convertView method just pass that dataList to scanner to get ssid and mac address of the network
#Override
public View convertView(int position, View convertView) {
ScanResultHolder viewHolder = null;
if(convertView == null){
convertView = View.inflate(getContext(), R.layout.item_wifi_scan_result, null);
viewHolder = new ScanResultHolder();
viewHolder.iv_device = (ImageView) convertView.findViewById(R.id.iv_device);
viewHolder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
viewHolder.tv_mac = (TextView) convertView.findViewById(R.id.tv_mac);
convertView.setTag(viewHolder);
}else{
viewHolder = (ScanResultHolder) convertView.getTag();
}
ScanResult scanResult = getDataList().get(position);
if(scanResult != null){
viewHolder.tv_name.setText(scanResult.SSID);
viewHolder.tv_mac.setText(scanResult.BSSID);
}
return convertView;
}
This is the code to enable the hotspot
public static boolean configApState(Context context, String apName) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
WifiConfiguration wificonfiguration = null;
try {
wificonfiguration = new WifiConfiguration();
wificonfiguration.SSID = apName;
// if WiFi is on, turn it off
if(isApOn(context)) {
wifimanager.setWifiEnabled(false);
// if ap is on and then disable ap
disableAp(context);
}
Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method.invoke(wifimanager, wificonfiguration, !isApOn(context));
return true;
}
catch (Exception e) {
e.printStackTrace();
}
return false;
}

Related

I want to know the existing of the device by bluetooth getRemoteDevice function or other function

I`m sorry about not good English skill.
I want to know that the device exists which has the mac address.
I used the getRemoteDevice method from BluetoothAdapter.
But the document said,
'A BluetoothDevice will always be returned for a valid hardware address, even if this adapter has never seen that device.'
So I couldn`t know the existing of the device.
How can I know the exists of the device?
Below code is my previous code. But I can`t know how to change the null checking.
public void connectSavedDevice() {
String result = pref.getString("first_device", "0");
if(result.equals("0")) {
Log.d(TAG,"not saved device");
return;
}
BluetoothDevice device = ble_adapter_.getRemoteDevice(result);
if(device == null) {
editor.clear();
editor.commit();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
startScan();
}
return;
}
GattClientCallback gatt_client_cb= new GattClientCallback();
ble_gatt_= device.connectGatt( context, false, gatt_client_cb );
}

Check Bluetooth State on specific device on android

I'm trying to know at my application start up if a paired device is connect or not. In practice the main app give me an MAC address and I've got to respond if we're connected or not.
A BroadcastReceiver can't be a full option because if the user start the connection with the device before launching the app I'll be unable to know if I'm connect to the device or not.
I found this on the forum : How to programmatically tell if a Bluetooth device is connected?
There is no way to retrieve the list of connected devices at application startup. The Bluetooth API will only let you listen to connection changes.
but i think this isn't accurate anymore because with this code :
public class cServiceListener implements BluetoothProfile.ServiceListener {
private static final int[] states={ BluetoothProfile.STATE_DISCONNECTING,
BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING};
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onServiceConnected(int profile, BluetoothProfile bluetoothProfile) {
//List<BluetoothDevice> Devices=bluetoothProfile.getDevicesMatchingConnectionStates(states);
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
Log.i("myTag","\n\n<==============profile connexion state =============> : "+ mBluetoothAdapter.getProfileConnectionState(1));
for (BluetoothDevice loop:devices){
Log.i("myTag","Nom du device :" +loop.getName()+" Etat du Device:"+bluetoothProfile.getConnectionState(loop)
+ " Type du device : "+ loop.getType() + " Classe du device : " + loop.getBluetoothClass().toString() );
}
}
#Override
public void onServiceDisconnected(int profile) {
}}
I'm able to tell if SOME devices are connected or not but not with all of them !!
I try the code with portable speakers and with others devices where the calls AND the sounds is take in charge and it work perfectly : if the device is connect it return 2 and if not it return 0.
But when i try it on my real objective (which is a car) it return 0 at anytime. The test car only take in charge calls (you can't play your music with Bluetooth connection, to old). So I think with more modern car it can work..
First i was thinking that car using BLE technology so I try with this code
List<BluetoothDevice> devices = bluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
Log.d("myTag","\n Taille de la liste : " + devices.size());
for(BluetoothDevice device : devices) {
if(device.getType() == BluetoothDevice.DEVICE_TYPE_LE) {
Log.d("myTag","\n BLE <===> Nom du device :" + device.getName());
}
Log.d("myTag","\n<====NONE BLE=====> // \n\n Nom du device :" + device.getName()+"\n\n");
}
But in fact this isn't the point, this don't work.
And it's weird because
mBluetoothAdapter.getProfileConnectionState(1)
returning the correct value when I'm connect to the car only.
I really don't know what to do know and why
bluetoothProfile.getConnectionState() returning the wrong value.
If someone have any idea, I'll be glad to know.
Finally I've achived the work. Bluetooth car are considere like headset so I focus on it :
public static void startListening() {
final BroadcastReceiver mBroadcastReceiver3 = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Bundle info = intent.getExtras();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceAddress = device.getAddress();
if (action.equals( BluetoothDevice.ACTION_ACL_CONNECTED)){
//do some stuff with connected device
}
if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)){
// do things with disconnected
}
}
};}

How to know if a specific app comes to foreground?

Check if an app, for example, Instagram is started by user.
Note: My app is targeting lollipop and above versions in android
Yeah the only way you can do it is through the Accessibility Service. Look at this page to understand how to create it. https://developer.android.com/training/accessibility/service.html They will also need to enable the service via the services -> accessibility screen.
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED you can probably interrogate the package in front to figure out if Instigram is on top.
You definitely don't want to use getRunningTasks since the function was modified in Android 5.0+
I figured out that I can do this by using usage access feature.
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static String getForegroundProcess(Context context) {
String topPackageName = null;
UsageStatsManager usage = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usage.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*1000, time);
if (stats != null) {
SortedMap<Long, UsageStats> runningTask = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
runningTask.put(usageStats.getLastTimeUsed(), usageStats);
}
if (runningTask.isEmpty()) {
return null;
}
topPackageName = runningTask.get(runningTask.lastKey()).getPackageName();
}
if(topPackageName==null) {
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
context.startActivity(intent);
}
return topPackageName;
}
Now continuously check if the desired app is in the foreground.
String fg=getForegroundProcess(getApplicationContext());
if(fg != null && fg.contains("com.instagram.android")){
//Instagram is in foreground
}else {
}
I continuously run the above code with a job service.Which is available for
lollipop and above.

Retrieving MAC Address Programmatically - Android

I'm having an issue with retrieving the MAC address of the device programatically, before anyone mentions anything about other posts I have read them already such as:
How to find MAC address of an Android device programmatically
however I tried using the code with my own application and tested it with a simple log.d, only to find that it is returning nothing. The message of "seeing if this works shows" but nothing else. So i am presuming the mac address is null.
Log.d("seeing if this works", macAddress2);
The code of what I have done is shown here:
//Set onclick listener for the Get Mac Address button
getMac.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wInfo = wifiManager.getConnectionInfo();
String macAddress2 = wInfo.getMacAddress();
macAddress.setText(macAddress2);
}
});
Which Android version are you testing on? The latest(10/2015) Android M preview has blocked the app from getting the hardware identifiers for Wifi and Bluetooth.
To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The WifiInfo.getMacAddress() and the BluetoothAdapter.getAddress() methods now return a constant value of 02:00:00:00:00:00.
There is a workaround by reading the Wifi MAC from /sys/class/net/wlan0/address, which however will also be blocked in the Android N as claimed by Google.
Try this:
public static String getMacAddr() {
try {
List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all) {
if (!nif.getName().equalsIgnoreCase("wlan0")) continue;
byte[] macBytes = nif.getHardwareAddress();
if (macBytes == null) {
return "";
}
StringBuilder res1 = new StringBuilder();
for (byte b : macBytes) {
res1.append(Integer.toHexString(b & 0xFF) + ":");
}
if (res1.length() > 0) {
res1.deleteCharAt(res1.length() - 1);
}
return res1.toString();
}
} catch (Exception ex) {
}
return "02:00:00:00:00:00";
}
From here:
http://robinhenniges.com/en/android6-get-mac-address-programmatically
Works for me.
Do you have this in the manifest?
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

Enabling/Disabling Data issue

I use this code for enabling or disabling Internet 3G Data in my application. I read several questions of it about hidden reflection functions and all that, but it was working very well in thousands of phones with very different android releases (my application is in PlayStore and I had no problems with it). But I am worried because I found a person whose phone is not able to do this. Let me first show the code I use:
try
{ final ConnectivityManager conman = (ConnectivityManager) MyContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if(conman == null) return false;
Class conmanClass = Class.forName(conman.getClass().getName());
if(conmanClass == null) return false;
Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
if(iConnectivityManagerField == null) return false;
iConnectivityManagerField.setAccessible(true);
Object iConnectivityManager = iConnectivityManagerField.get(conman);
if(iConnectivityManager == null) return false;
Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
if(iConnectivityManagerClass == null) return false;
Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
if(setMobileDataEnabledMethod == null) return false;
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConnectivityManager, true/false); //Here is where you choose to enable or to disable
return true; //Everything went OK
}catch(Exception e)
{ return false;
}
The error is in line:
Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
With this result:
java.lang.NoSuchFieldException: mService
That phone is a Samsung Galaxy SII using Jelly Bean 4.1.1
Any ideas? I am afraid of people starting to report same issue.
Apparently, Samsung (or possibly a ROM mod author) rewrote that class and no longer has a data member named mService. This is completely within their rights. So long as their change does not break anything covered by the CTS, they can do what they want with the internal implementations of framework classes. This is why I and other Android experts tell developers not to rely on script-kiddie tricks like what you are using.
If "enabling or disabling Internet 3G Data" is crucial to your app, and you determine that this is affecting stock ROMs on the Samsung Galaxy SII, you will need to block distribution to such devices through the Play Store.
If "enabling or disabling Internet 3G Data" is not crucial to your app, add in a better exception handler to say "sorry, this feature is not available", or some such.

Categories