如何編程實現開啟或者關閉GPS

來源:互聯網
上載者:User
文章目錄
  • 山重水複疑無路
  • 柳暗花明又一村
  • 總結

轉自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

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

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的代碼中用到如下方法:

  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中的表徵圖按鈕的序號。所有的序號在類的首部都有定義:

 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中添加如下方法:

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,代碼片斷如下:

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

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

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。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.