android GPS开启方法 代码

对于android上GPS的控制,官方提供了相关的API 


Settings.Secure.setLocationProviderEnabled(getContentResolver(), LocationManager.GPS_PROVIDER, true); 

 

但是当我们调用setLocationProviderEnabled方法后,系统会抛出异常提示需要android.permission.WRITE_SECURE_SETTINGS的权限,即便在mainfest中添加该权限的请求也是一样。setLocationProviderEnabled这个方法需要root的权限,要使这个代码能执行,程序就必须是系统的app,即安装在/system/app下;或者是请求root权限,这样除了厂商能将自己的app安装在/system/app 之下外,只能是需要请求root权限了。

 

 百度了一下,有解决办法,但是说的不太清除,而且直接copy他们的代码,运行后gps状态也没有改变。而且也没有说明其原理。

 其实除了使用  Settings.Secure.setLocationProviderEnabled 这个方法之外,还有一个方法就是使用系统自带的电量控制Widget来更改GPS的状态。

 具体代码如下: 

 

Intent intent =  new Intent();
intent.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
intent.addCategory("android.intent.category.ALTERNATIVE");
intent.setData(Uri.parse("custom:3"));
context.sendBroadcast(intent);

 

 

 这段代码是什么意思呢?其实就是通过intent将消息发给com.android.settings.widget.SettingsAppWidgetProvider去处理,因为这个是系统自带的程序,所以他拥有root权限。

 那 Uri.parse("custom:3") 又是什么意思呢,其实custom:3就是电量控制插件上对应的各个按钮,通过查看改代码可以知道各个id的情况

 

private  static  final  int BUTTON_BLUETOOTH = 4;
private  static  final  int BUTTON_BRIGHTNESS = 1;
private  static  final  int BUTTON_GPS = 3;
private  static  final  int BUTTON_SYNC = 2;
private  static  final  int BUTTON_WIFI = 0; 

 

这样就可以通过给 com.android.settings.widget.SettingsAppWidgetProvider 发送消息实现更改GPS状态了。同时,更改其他系统设设置的状态也可以通过这个方法实现。

 

 

接下来控制WIFI的开关就很容易了,只要简单调用一下代码就可以实现了

 

WifiManager manager = null;
manager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
manager.setWifiEnabled( false);
manager.setWifiEnabled( true); 

 

 

 控制蓝牙的开关

BluetoothAdapter bluetoothadapter = BluetoothAdapter.getDefaultAdapter();
bluetoothadapter.disable();
bluetoothadapter.enable(); 

 

控制飞行模式,谷歌没有提供相关的api,但是我们可以通过intent广播来实现

 

Intent intent;
Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, enabled ? 1 : 0);
intent =  new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", enabled);
context.sendBroadcast(intent);

 

这样,我们就完成了情景模式中控制GPS/WIFI/蓝牙/飞行模式 的功能。



转自:http://www.learningandroid.net/blog/advance/programmable-toggle-gps/

手机应用中最酷的可能就是位置服务相关的了,如何读取GPS信息,在官方文档上有相当详细的说明,后面如果有机会,我也会专门写例子来介绍(教程已完成,请参见:教程:实现Android的不同精度的定位(基于网络和GPS))。但今天,我们先来看下如何以编程的方式来开启关闭GPS
官方的API中,android.provider.Settings.Secure类有2个静态方法:
public static final void setLocationProviderEnabled (ContentResolver cr, String provider, boolean enabled)

public static final boolean isLocationProviderEnabled (ContentResolver cr, String provider)
不过遗憾的是,这2个方法都注明了从API Level 8(即Android 2.2)才开始提供,那么在2.2之前又该如何编程实现GPS的开关呢?

山重水复疑无路

首先,我们要知道,Android系统的设置画面中就可以进行GPS的开关,那么它是如何实现的呢?
由于我的机器上的android source是2.3版本的,所以直接启动了一个2.1的模拟器,用adb pull将Settings.apk抓下来,反编译之后,在SecuritySettings类中找到如下代码:
package,com.android.settings.SecuritySettings.java

1
2
3
4
5
6
7
8
      CheckBoxPreference localCheckBoxPreference3 = this.mGps;
      if (paramPreference == localCheckBoxPreference3)
      {
        ContentResolver localContentResolver3 = getContentResolver();
        boolean bool6 = this.mGps.isChecked();
        Settings.Secure.setLocationProviderEnabled(localContentResolver3, "gps", bool6);
        continue;
      }

可以看到2.1系统中已经存在有Settings.Secure.setLocationProviderEnabled方法了,只是该方法没有开放而已,事实上读过Android源码的人都对/*hide*/很反感吧,看得到,摸不到!

既然Setting画面中的用法,我们不能使用,那么再换1种方法,我们去看一下Settings.Secure.setLocationProviderEnabled的写法,然后直接套用。
这次,我们直接去看Android 2.3的源码,找到Setting.java之后,找到相关的方法,代码如下:
core, android.provider.Setting.java

1
2
3
4
5
6
7
8
9
10
11
12
        public static final void setLocationProviderEnabled(ContentResolver cr,
                String provider, boolean enabled) {
            // to ensure thread safety, we write the provider name with a '+' or '-'
            // and let the SettingsProvider handle it rather than reading and modifying
            // the list of enabled providers.
            if (enabled) {
                provider = "+" + provider;
            } else {
                provider = "-" + provider;
            }
            putString(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider);
        }

原来这个方法只是1个包装,事实上调用的还是Settings.Secure中的putString方法,我们直接借用过来:
在自己的onClick事件中写上
Settings.Secure.putString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, “network,gps”);
然后执行,WOW,发生了什么,需要android.permission.WRITE_SETTINGS权限?在Manifest文件中加上,再运行,还是出错,不过这次需要的是android.permission.WRITE_SECURE_SETTINGS,再次加上。
满怀希望的再次运行,结果还是一样的问题:
java.lang.SecurityException: Permission denial: writing to secure settings requires android.permission.WRITE_SECURE_SETTINGS
看来,Google封死了直接调用Settings的路了,事实上我又试着使用反射来直接调用setLocationProviderEnabled方法,结果也是一样的告诉我需要权限

柳暗花明又一村

难道没有别的办法了吗?那些2.1中可以运行的App Widget是如何做到的呢?
再次检视2.1的Settings.apk中的代码,发现有1个widget包,里面有1个类叫SettingsAppWidgetProvider,这就是用来提供App Widget的类,继续研究这里的代码,发现构造RemoteView的代码中用到如下方法:

1
2
3
4
5
6
7
8
9
  private static PendingIntent getLaunchPendingIntent(Context paramContext, int paramInt1, int paramInt2)
  {
    Intent localIntent1 = new Intent();
    Intent localIntent2 = localIntent1.setClass(paramContext, SettingsAppWidgetProvider.class);
    Intent localIntent3 = localIntent1.addCategory("android.intent.category.ALTERNATIVE");
    Uri localUri = Uri.parse("custom:" + paramInt2);
    Intent localIntent4 = localIntent1.setData(localUri);
    return PendingIntent.getBroadcast(paramContext, 0, localIntent1, 0);
  }

由于这是反编译的结果,略微有点混乱,但还是可以看出思路,目的是通过PendingIntent来扔出1个Intent,接受者是SettingsAppWidgetProvider.class,接受的参数有2个,1个是Category:SettingsAppWidgetProvider.class(正是这个类自身),另1个是Data:Uri.parse(“custom:” + paramInt2),这个paramInt2是Widget中的图标按钮的序号。所有的序号在类的首部都有定义:

1
2
3
4
5
  private static final int BUTTON_BLUETOOTH = 4;
  private static final int BUTTON_BRIGHTNESS = 1;
  private static final int BUTTON_GPS = 3;
  private static final int BUTTON_SYNC = 2;
  private static final int BUTTON_WIFI = 0;

那么我们只要送出custom:3的Uri给SettingsAppWidgetProvider.class,就应该可以由SettingsAppWidgetProvider类来帮我们调用Settings.Secure.setLocationProviderEnabled方法了。
说到做到,在Activity中添加如下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
	private void toggleGPS() {
		Intent gpsIntent = new Intent();
		gpsIntent.setClassName("com.android.settings",
				"com.android.settings.widget.SettingsAppWidgetProvider");
		gpsIntent.addCategory("android.intent.category.ALTERNATIVE");
		gpsIntent.setData(Uri.parse("custom:3"));
		try {
			PendingIntent.getBroadcast(this, 0, gpsIntent, 0).send();
		}
		catch (CanceledException e) {
			e.printStackTrace();
		}
	}

这个方法是1个纯开关,如果当前是开启的,那么就会关闭它,反之亦然。

检查GPS开关状态

那么,如何查看当前的GPS开关状态呢?可以用上面提到的反射方式调用isLocationProviderEnabled,代码片断如下:

1
2
3
4
5
	secureClass = cl.loadClass("android.provider.Settings$Secure");
	isMethod = secureClass.getMethod("isLocationProviderEnabled",
			ContentResolver.class, String.class);
	Boolean ret = (Boolean) isMethod.invoke(secureClass, this
			.getContentResolver(), "gps");

也可以直接用下面的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	private void isGPSEnable() {
		/* 用Setting.System来读取也可以,只是这是更旧的用法
		String str = Settings.System.getString(getContentResolver(),
				Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
		*/
		String str = Settings.Secure.getString(getContentResolver(),
				Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
		Log.v("GPS", str);
		if (str != null) {
			return str.contains("gps");
		}
		else{
			return false;
		}
	}

这2种方法的原理都是一样的,方法2其实也就是isLocationProviderEnabled实际调用的代码,只是Google未对读取操作进行权限限制。

总结

如果目标手机是运行Android 2.2的话,那么最好还是使用2.2开放的Settings.Secure类中的2个方法来操作。但如果目标手机运行的版本是2.1或以下的话,那么就只能使用变通的方法来实现了。这1方法在Android官方的Wiki上已经有人提出了,详情请见:Issue 7890。但可能是2.1版本已经古旧不再维护的原因,官方并未进行任何的Fix。

 


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Android GPS定位的完整代码实例,包括权限申请和位置监听器的实现: 1. 首先,在AndroidManifest.xml文件中添加以下权限: ```xml <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ``` 2. 接着,在MainActivity.java文件中添加以下代码: ```java public class MainActivity extends AppCompatActivity { private LocationManager locationManager; private LocationListener locationListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { // 处理位置变化事件 double latitude = location.getLatitude(); double longitude = location.getLongitude(); Log.i("Location", "Latitude: " + latitude + ", Longitude: " + longitude); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // 处理位置状态变化事件 } @Override public void onProviderEnabled(String provider) { // 处理位置提供者启用事件 } @Override public void onProviderDisabled(String provider) { // 处理位置提供者禁用事件 } }; if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); } else { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); } } } } } ``` 以上代码实现了位置监听器(locationListener)的初始化并在权限被授予时开始监听位置变化。你可以根据需要在位置变化事件(onLocationChanged)中实现具体的处理逻辑。 注意:为了让上述代码运行正常,你需要在设备上打开GPS定位功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值