show code block

2017年5月30日 星期二

Android權限 ─ 調整螢幕亮度、特殊權限 android.permission.WRITE_SETTINGS

 前言:

之前調整權限的方式請看這裡
這次調用權限的方式比較不一樣。看圖吧!




權限使用:

請參考這篇:
https://yanlu.me/android-m6-0-permission-chasm/
以下全部複製。
這是WRITE_SETTINGS權限的使用方式。
記得先在manifest內增加權限

<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
 


/**
 * An app can use this method to check if it is currently allowed to write or modify system
 * settings. In order to gain write access to the system settings, an app must declare the
 * {@link android.Manifest.permission#WRITE_SETTINGS} permission in its manifest. If it is
 * currently disallowed, it can prompt the user to grant it this capability through a
 * management UI by sending an Intent with action
 * {@link android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}.
 *
 * @param context A context
 * @return true if the calling app can write to system settings, false otherwise
 */
 if(!Settings.System.canWrite(this)){
      Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
                Uri.parse("package:" + getPackageName()));
      startActivityForResult(intent, REQUEST_CODE);
 } 
 
 
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_CODE) {
        if (Settings.System.canWrite(this)) {
            //检查返回结果
            Toast.makeText(MainActivity.this, "WRITE_SETTINGS permission granted", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(MainActivity.this, "WRITE_SETTINGS permission not granted", Toast.LENGTH_SHORT).show();
        }
    }
}
 
其中比較需要注意的地方是Settings.System.canWrite這方法在太低版本的Android上面不適用。
調用會Crash。
所以我們稍加做了一些判斷。

 
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {//android6.0以上使用需要權限
                    if (!Settings.System.canWrite(context)) {//沒有給予權限的話Do Something
                        //跳轉畫面到權限頁面給使用者勾選
                        Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
                                Uri.parse("package:" + getPackageName()));
                        startActivityForResult(intent, 9487);
                    } else {//已有權限 Do Something
                        start_bRight();//開始調整螢幕
                    }

                } else {//android6.0以下可直接調用
                    start_bRight();//開始調整螢幕
                }

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case 9487:
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                    if (Settings.System.canWrite(this)) {
                        start_bRight();//開始調整螢幕
                    } else {
                        Toast.makeText(MainActivity.this, "請給予權限。", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    start_bRight();//開始調整螢幕
                }
                break;
        }
    }

使用
Build.VERSION.SDK_INT > Build.VERSION_CODES.M
來判斷是否Android的版本為SDK 23以上,如果是23以下就沒有權限問題,也可以順利調用Settings.System.canWrite方法。




調整亮度Code:

裡面帶有SeekBar參數。

    //調整螢幕亮度
    private void start_bRight() {

        //設定最大值
        SeekBar m_SeekBar = (SeekBar) findViewById(R.id.see_bar);
        m_SeekBar.setMax(255);

        //取得目前系統的亮度值
        int brightness = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, 255);
        Log.w(TAG, "亮度 素質" + brightness);

        //將亮度值 射定道系統中
        m_SeekBar.setProgress(brightness);

        //關閉自動調整亮度功能
        Settings.System.putInt(this.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
        /*
         * @param cr要訪問的ContentResolver。
         * @param name要修改的設置的名稱。
         * @param value設置的新值。
         */


        //設定SeeBar的監聽事件
        m_SeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                //觀察目前系統的亮度值
                int brightness = android.provider.Settings.System.getInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, 255);
                Log.w(TAG, "觀察亮度 素質" + brightness);

                //針對App端的UI作為 螢幕亮度調整
                // (假設App端調整最暗,)
                Window localWindow = getWindow();
                WindowManager.LayoutParams localLayoutParams = localWindow.getAttributes();
                localLayoutParams.screenBrightness = progress / 255.0f;
                localWindow.setAttributes(localLayoutParams);

                //如果想改變整個系統的亮度
                //方法1:
//                Uri uri = android.provider.Settings.System.getUriFor("screen_brightness");
//                android.provider.Settings.System.putInt(context.getContentResolver(), getContentResolver(), progress);
//                context.getContentResolver().notifyChange(uri, null);

                //方法2:
                android.provider.Settings.System.putInt(getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, progress);

                /*補充:android.provider.Settings.System.putInt(參數1,參數2,參數3);
                *
                *參數1:需要一個ContentResolver ,所以getContentResolver()
                *參數2:其實就是一個字串,"screen_brightness",但是這個類別中已經有final String 位置在→ android.provider.Settings.System.SCREEN_BRIGHTNESS
                *參數3:設定的值
                *
                * */
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    }
 
這裡還有另外一些調整亮度的方式。
如果你要進入畫面直接最亮可以嘗試以下方法
【Android開發經驗】與屏幕亮度調節相關的各種方法整理
public class SystemManager {  
  
    private Context mContext;  
    private static SystemManager sInstance;  
  
    private SystemManager(final Context context) {  
        mContext = context;  
    }  
  
    public static SystemManager init(final Context context) {  
        if (null == sInstance) {  
            sInstance = new SystemManager(context);  
        }  
        return sInstance;  
    }  
  
    public static SystemManager getInstance() {  
        return sInstance;  
    }  
  
    // 判斷是否是自動調光模式  
    public boolean isAutoBrightness() {  
        boolean automicBrightness = false;  
        try {  
            ContentResolver resolver = mContext.getContentResolver();  
            automicBrightness = Settings.System.getInt(resolver,  
                    Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;  
        } catch (SettingNotFoundException e) {  
            e.printStackTrace();  
        }  
        return automicBrightness;  
    }  
  
    // 設置屏幕亮度  
    public void setBrightness(Activity activity, int brightness) {  
        WindowManager.LayoutParams lp = activity.getWindow().getAttributes();  
        lp.screenBrightness = Float.valueOf(brightness) * (1f / 255f);  
        activity.getWindow().setAttributes(lp);  
    }  
  
    // 保存屏幕亮度  
    public void saveBrightness(int brightness) {  
        ContentResolver resolver = mContext.getContentResolver();  
        Uri uri = android.provider.Settings.System  
                .getUriFor("screen_brightness");  
        android.provider.Settings.System.putInt(resolver, "screen_brightness",  
                brightness);  
        resolver.notifyChange(uri, null);  
    }  
  
    // 開啟自動調光模式  
    public void startAutoBrightness() {  
        ContentResolver resolver = mContext.getContentResolver();  
        Settings.System.putInt(resolver,  
                Settings.System.SCREEN_BRIGHTNESS_MODE,  
                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);  
        Uri uri = android.provider.Settings.System  
                .getUriFor("screen_brightness");  
        resolver.notifyChange(uri, null);  
    }  
  
    // 關閉自動調光模式  
    public void stopAutoBrightness() {  
        ContentResolver resolver = mContext.getContentResolver();  
        Settings.System.putInt(resolver,  
                Settings.System.SCREEN_BRIGHTNESS_MODE,  
                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);  
        Uri uri = android.provider.Settings.System  
                .getUriFor("screen_brightness");  
        resolver.notifyChange(uri, null);  
    }  
  
    // 獲得當前屏幕亮度  
    public int getScreenBrightness() {  
        int nowBrightnessValue = 0;  
        try {  
            ContentResolver resolver = mContext.getContentResolver();  
            nowBrightnessValue = android.provider.Settings.System.getInt(  
                    resolver, Settings.System.SCREEN_BRIGHTNESS);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return nowBrightnessValue;  
    }  
  
    // 設置光亮模式  
    public void setBrightnessMode(int mode) {  
        Settings.System.putInt(mContext.getContentResolver(),  
                Settings.System.SCREEN_BRIGHTNESS_MODE, mode);  
    }  
  
    // 獲得亮度模式  
    public int getBrightnessMode() {  
        try {  
            return Settings.System.getInt(mContext.getContentResolver(),  
                    Settings.System.SCREEN_BRIGHTNESS_MODE);  
        } catch (SettingNotFoundException e) {  
            return Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;  
        }  
    }  
    //調到最亮 0~255 最暗~最亮
    Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 255);
  
}  
 




Demo:
https://dl.dropboxusercontent.com/s/hcv9hqoaudd8wuk/ScreenBright.7z

2017年5月26日 星期五

Android元件(DownloadManager) ─ downloadManager下載元件

完全參考這三篇:

DownloadManager
Android DownloadManager 的使用
[Android] DownloadManager 下載APK並自動開啟安裝畫面(Android6.0 7.0 皆可運作)

progressBar的部分可以參考我這篇 ProgressBar





重點程式碼:

    private DownloadManager mDownloadManager;//驅動
    private DownloadManager.Request request;//回傳下載網址使用
    private DownloadManager.Query query;//監測下載狀態使用
    private long downloadID;//下載後給下載的東西一個ID方便後續處理


可以一開始就幫 mDownloadManager初始化。
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);

DownloadManager.Request
Request顧名思義就是請求,作用就是你塞給他一個Uri 在吐給DownloadManager。就開始下載。

 request = new DownloadManager.Request(uri);
        request.setTitle("HelloWorld");//設置你在下載時,上面的title名稱
        request.setDescription("DownLoad Waiting.....");//設置你在下載時,Title旁邊的文字顯示
        LatestDownloadID = mDownloadManager.enqueue(request);//裝入DownloadManager並開始下載(同時裝入LatestDownloadID,供query使用抓取你下載的ID)


DownloadManager.Query
query顧名思義就是詢問,作用是給你拿來監控下載的狀態用的。
他只有兩個方法可以使用
 query.setFilterById(LatestDownloadID);//用於你要監控的下載ID元件
 query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);//你想要監控的下載狀態




基本使用方式:


完全複製Android DownloadManager 的使用這篇的使用方式。

使用Download來下載
// uri 是你的下載地址,可以使用Uri.parse("http://")包裝成Uri對象
DownloadManager.Request req = new DownloadManager.Request(uri);

// 通過setAllowedNetworkTypes方法可以設置允許在何種網絡下下載,
// 也可以使用setAllowedOverRoaming方法,它更加靈活
req.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);

// 此方法表示在下載過程中通知欄會一直顯示該下載,在下載完成後仍然會顯示,
// 直到用戶點擊該通知或者消除該通知。還有其他參數可供選擇
req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

// 設置下載文件存放的路徑,同樣你可以選擇以下方法存放在你想要的位置。
// setDestinationUri
// setDestinationInExternalPublicDir
req.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, title);

// 設置一些基本顯示信息
req.setTitle("Android.apk");
req.setDescription("下載完後請點擊打開");
req.setMimeType("application/vnd.android.package-archive");

// Ok go!
DownloadManager dm = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
long downloadId = dm.enqueue(req);

獲取下載的文件
DownloadManager dm = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Query query = new DownloadManager.Query().setFilterById(downloadId);
Cursor c = dm.query(query);
if (c != null) {
    if (c.moveToFirst()) {
        String fileUri = c.getString(c.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI));
        // TODO 處理文件
    }
    c.close();
}




實作:

給權限
 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />



main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.update.a015865.downloaddemo.MainActivity">

    <Button
        android:id="@+id/tv_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="download"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/tv_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        tools:layout_editor_absoluteX="8dp"
        tools:layout_editor_absoluteY="8dp" />

    <LinearLayout
        android:layout_alignParentBottom="true"
        android:id="@+id/tv_layout_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="gone">

        <TextView
            android:id="@+id/tv_txtprogress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="0%" />

        <ProgressBar
            android:max="100"
            android:id="@+id/tv_progress"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_image" />

    </LinearLayout>

</RelativeLayout>


MainActivity.java
public class MainActivity extends AppCompatActivity {

    private Button mButton;
    private ImageView mImageView;
    private ProgressBar mProgressBar;
    private LinearLayout mLayoutProgress;
    private TextView mTxtProgress;

    private long downloadID;
    private DownloadManager DM;
    private DownloadManager.Request request;
    private DownloadManager.Query query;
    static final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initSet();
        initListener();
    }

    private void initView() {
        mTxtProgress = (TextView) findViewById(R.id.tv_txtprogress);
        mLayoutProgress = (LinearLayout) findViewById(R.id.tv_layout_progress);
        mProgressBar = (ProgressBar) findViewById(R.id.tv_progress);
        mButton = (Button) findViewById(R.id.tv_button);
        mImageView = (ImageView) findViewById(R.id.tv_image);
    }

    private void initSet() {
        DM = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);//init 初始化

    }

    private void initListener() {
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                    checkPermission();
                } else {
                    downloadStuff();
                }
            }
        });
    }

    //開始下載東西
    private void downloadStuff() {
        mLayoutProgress.setVisibility(View.VISIBLE);

        String URL = "https://dl.dropboxusercontent.com/s/kkvs6zw8k50uc8m/android-nougat.png";
        request = new DownloadManager.Request(Uri.parse(URL));//把網址給request處理
        request.setTitle("ImageAndroid");//設置title
        request.setDescription("download please wait...");//設置內容
        downloadID = DM.enqueue(request);//GO 開始下載、並記錄下載的id

        //註冊DOWNLOAD_COMPLETE-BroadcastReceiver (裡面有使用query,當下載完成,追蹤塞進去的downloadID開啟圖檔)
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                    query = new DownloadManager.Query();
                    query.setFilterById(downloadID);
                    query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
                    Cursor cur = DM.query(query);
                    if (cur != null) {
                        if (cur.moveToFirst()) {
                            String urlString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                            if (!TextUtils.isEmpty(urlString)) {
                                mImageView.setImageURI(Uri.parse(urlString));
                                Toast.makeText(context, "download Success", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                }
            }
        };
        registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

        //註冊觀察者 (CONTENT_URI為固定參數,不能做改變)
        DownloadObserver downloadObserver = new DownloadObserver(null);
        getContentResolver().registerContentObserver(CONTENT_URI, true, downloadObserver);
    }

    
    //檢查是否有權限
    private void checkPermission() {
        int readPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
        int writePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (readPermission != PackageManager.PERMISSION_GRANTED && writePermission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1999);
        } else {
            downloadStuff();
        }
    }

    
    //權限讀取結果回應
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 1999:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    downloadStuff();
                } else {
                    Toast.makeText(this, "給予權限才能拿來做事情啊!", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    
    //監控ProgessBar
     
    class DownloadObserver extends ContentObserver {
        public DownloadObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downloadID);

            Cursor cursor = DM.query(query);
            if (cursor != null && cursor.moveToFirst()) {
                final int totalColumn = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
                final int currentColumn = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
                int totalSize = cursor.getInt(totalColumn);
                int currentSize = cursor.getInt(currentColumn);
                float percent = (float) currentSize / (float) totalSize;
                final int progress = Math.round(percent * 100);
                runOnUiThread(new Runnable() {//確保在UI Thread執行
                    @Override
                    public void run() {
                        mTxtProgress.setText("" + progress + "%");
                        mProgressBar.setProgress(progress);
                    }
                });
            }
        }
    }

}

DEMO:
https://github.com/nikeru8/download

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...