Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 利用懸浮窗進一步降低屏幕亮度保護眼睛(app based on Android),appandroid

利用懸浮窗進一步降低屏幕亮度保護眼睛(app based on Android),appandroid

編輯:關於android開發

利用懸浮窗進一步降低屏幕亮度保護眼睛(app based on Android),appandroid


項目地址:https://github.com/hwding/make-it-darker

歡迎star、fork以及一切建議和意見!

 

在完全黑暗中看手機眼睛會非常容易疲勞,即使將手機亮度調整到最低也會讓自己在完全適應後感到非常刺眼。

利用android的懸浮窗將半透明的黑色layout覆蓋在屏幕上進一步降低亮度。

同時通過改變濾鏡顏色可以過濾藍光等等。

出於自身需求給自己寫了一個小玩意~

 

效果:

    

 

懸浮窗作為服務啟動:

1 package com.amastigote.darker.service; 2 3 import android.app.Service; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.os.IBinder; 7 import android.support.annotation.Nullable; 8 import android.view.LayoutInflater; 9 import android.view.WindowManager; 10 import android.widget.LinearLayout; 11 import com.amastigote.darker.R; 12 import com.amastigote.darker.model.DarkerSettings; 13 14 public class ScreenFilterService extends Service{ 15 static LinearLayout linearLayout; 16 static WindowManager.LayoutParams layoutParams; 17 static WindowManager windowManager; 18 19 @Override 20 public void onCreate() { 21 super.onCreate(); 22 createScreenFilter(); 23 } 24 25 @Override 26 public void onDestroy() { 27 super.onDestroy(); 28 if (linearLayout != null) 29 windowManager.removeView(linearLayout); 30 } 31 32 @Nullable 33 @Override 34 public IBinder onBind(Intent intent) { 35 return null; 36 } 37 38 @SuppressWarnings(value = "all") 39 private void createScreenFilter() { 40 layoutParams = new WindowManager.LayoutParams(); 41 windowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE); 42 layoutParams.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; 43 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 44 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 45 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 46 layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; 47 layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; 48 49 LayoutInflater layoutInflater = LayoutInflater.from(getApplication()); 50 linearLayout = (LinearLayout) layoutInflater.inflate(R.layout.screen_filter, null); 51 windowManager.addView(linearLayout, layoutParams); 52 removeScreenFilter(); 53 } 54 55 public static void updateScreenFilter(DarkerSettings darkerSettings) { 56 layoutParams.screenBrightness = darkerSettings.getBrightness(); 57 layoutParams.alpha = darkerSettings.getAlpha(); 58 windowManager.updateViewLayout(linearLayout, layoutParams); 59 } 60 61 public static void removeScreenFilter() { 62 layoutParams.screenBrightness = DarkerSettings.BRIGHTNESS_AUTO; 63 layoutParams.alpha = DarkerSettings.ALPHA_MINIMUM; 64 windowManager.updateViewLayout(linearLayout, layoutParams); 65 } 66 } ScreenFilterService.java

此處應注意,給layoutParams設置屬性type時需要用到類型TYPE_PRIORITY_PHONE,可以覆蓋一切屏幕上的內容。

關於此項類型需要特定的permission申請,此處不表,見下。

screenBrightness為懸浮窗自身亮度,這裡默認為最低0.0F

alpha為懸浮窗layout的透明度,默認為0.4F,最高設定為0.8F防止全黑導致無法操作。

update...()方法用於讀入用戶在app控制面版上的配置並更新filter

remove...()方法並沒有移除filter而是將filter的亮度恢復為自動並設置為全透明,方便下一次啟動filter。

 

1 package com.amastigote.darker.activity; 2 3 import android.content.Intent; 4 import android.net.Uri; 5 import android.os.Build; 6 import android.os.Bundle; 7 import android.provider.Settings; 8 import android.support.v7.app.AppCompatActivity; 9 import android.support.v7.widget.Toolbar; 10 import android.view.Menu; 11 import android.view.MenuItem; 12 import android.view.View; 13 import android.view.animation.AlphaAnimation; 14 import android.widget.Button; 15 import android.widget.Switch; 16 import android.widget.Toast; 17 import android.widget.ToggleButton; 18 import com.amastigote.darker.R; 19 import com.amastigote.darker.model.DarkerSettings; 20 import com.amastigote.darker.service.ScreenFilterService; 21 import com.rtugeek.android.colorseekbar.ColorSeekBar; 22 import io.feeeei.circleseekbar.CircleSeekBar; 23 24 public class MainActivity extends AppCompatActivity { 25 DarkerSettings currentDarkerSettings = new DarkerSettings(); 26 CircleSeekBar circleSeekBar_brightness; 27 CircleSeekBar circleSeekBar_alpha; 28 ColorSeekBar colorSeekBar; 29 Switch aSwitch; 30 Intent intent; 31 32 @Override 33 protected void onDestroy() { 34 if (intent != null) 35 stopService(intent); 36 super.onDestroy(); 37 } 38 39 @Override 40 protected void onCreate(Bundle savedInstanceState) { 41 super.onCreate(savedInstanceState); 42 setContentView(R.layout.activity_main); 43 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 44 toolbar.setTitle("make it darker!"); 45 setSupportActionBar(toolbar); 46 DarkerSettings.initializeContext(getApplicationContext()); 47 48 checkPermissions(); 49 50 circleSeekBar_brightness = (CircleSeekBar) findViewById(R.id.cp_brightness_circleSeekBar); 51 circleSeekBar_alpha = (CircleSeekBar) findViewById(R.id.cp_alpha_circleSeekBar); 52 colorSeekBar = (ColorSeekBar) findViewById(R.id.cp_colorSeekBar); 53 aSwitch = (Switch) findViewById(R.id.cp_useColor_switch); 54 ToggleButton toggleButton = (ToggleButton) findViewById(R.id.cm_toggle_button); 55 Button restore_settings_button = (Button) findViewById(R.id.cm_restore_settings_button); 56 57 restoreLatestSettings(); 58 59 toggleButton.setOnClickListener(new View.OnClickListener() { 60 61 @Override 62 public void onClick(View view) { 63 if (((ToggleButton) view).isChecked()) 64 collectCurrentDarkerSettings(); 65 else 66 ScreenFilterService.removeScreenFilter(); 67 } 68 }); 69 70 restore_settings_button.setOnClickListener(new View.OnClickListener() { 71 72 @Override 73 public void onClick(View view) { 74 DarkerSettings darkerSettings_default = DarkerSettings.getDefaultSettings(); 75 circleSeekBar_brightness.setCurProcess((int) (darkerSettings_default.getBrightness() * 100)); 76 circleSeekBar_alpha.setCurProcess((int) (darkerSettings_default.getAlpha() * 100)); 77 if (aSwitch.isChecked() != darkerSettings_default.isUseColor()) { 78 aSwitch.setChecked(darkerSettings_default.isUseColor()); 79 AlphaAnimation alphaAnimation_1 = new AlphaAnimation(1, 0); 80 alphaAnimation_1.setDuration(300); 81 colorSeekBar.startAnimation(alphaAnimation_1); 82 colorSeekBar.setVisibility(View.INVISIBLE); 83 } 84 } 85 }); 86 87 aSwitch.setOnClickListener(new View.OnClickListener() { 88 @Override 89 public void onClick(View view) { 90 if (((Switch) view).isChecked()) { 91 AlphaAnimation alphaAnimation_0 = new AlphaAnimation(0, 1); 92 alphaAnimation_0.setDuration(300); 93 colorSeekBar.startAnimation(alphaAnimation_0); 94 colorSeekBar.setVisibility(View.VISIBLE); 95 } 96 else { 97 AlphaAnimation alphaAnimation_1 = new AlphaAnimation(1, 0); 98 alphaAnimation_1.setDuration(300); 99 colorSeekBar.startAnimation(alphaAnimation_1); 100 colorSeekBar.setVisibility(View.INVISIBLE); 101 } 102 } 103 }); 104 105 } 106 107 @Override 108 public boolean onCreateOptionsMenu(Menu menu) { 109 // Inflate the menu; this adds items to the action bar if it is present. 110 getMenuInflater().inflate(R.menu.menu_main, menu); 111 return true; 112 } 113 114 @Override 115 public boolean onOptionsItemSelected(MenuItem item) { 116 // Handle action bar item clicks here. The action bar will 117 // automatically handle clicks on the Home/Up button, so long 118 // as you specify a parent activity in AndroidManifest.xml. 119 int id = item.getItemId(); 120 121 //noinspection SimplifiableIfStatement 122 if (id == R.id.action_settings) { 123 startActivity(new Intent(Intent.ACTION_VIEW, 124 Uri.parse("https://github.com/hwding/make-it-darker"))); 125 } 126 127 if (id == R.id.action_licenses) { 128 startActivity(new Intent(MainActivity.this, LicenseActivity.class)); 129 } 130 131 return super.onOptionsItemSelected(item); 132 } 133 134 private void collectCurrentDarkerSettings() { 135 currentDarkerSettings.setBrightness(((float) circleSeekBar_brightness.getCurProcess()) / 100); 136 currentDarkerSettings.setAlpha(((float) circleSeekBar_alpha.getCurProcess()) / 100); 137 currentDarkerSettings.setUseColor(aSwitch.isChecked()); 138 currentDarkerSettings.setColor(colorSeekBar.getColor()); 139 currentDarkerSettings.saveCurrentSettings(); 140 ScreenFilterService.updateScreenFilter(currentDarkerSettings); 141 } 142 143 private void restoreLatestSettings() { 144 DarkerSettings latestDarkerSettings = DarkerSettings.getCurrentSettings(); 145 circleSeekBar_alpha.setCurProcess((int) (latestDarkerSettings.getAlpha() * 100)); 146 circleSeekBar_brightness.setCurProcess((int) (latestDarkerSettings.getBrightness() * 100)); 147 if (latestDarkerSettings.isUseColor()) { 148 aSwitch.setChecked(true); 149 colorSeekBar.setVisibility(View.VISIBLE); 150 } 151 colorSeekBar.setColorBarValue(latestDarkerSettings.getColor()); 152 } 153 154 private void checkPermissions() { 155 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 156 if (!Settings.canDrawOverlays(getApplicationContext())) { 157 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); 158 intent.setData(Uri.parse("package:" + getPackageName())); 159 startActivityForResult(intent, 0); 160 } 161 else 162 prepareForService(); 163 } 164 else 165 prepareForService(); 166 } 167 168 @Override 169 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 170 super.onActivityResult(requestCode, resultCode, data); 171 if (requestCode == 0) { 172 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 173 if (Settings.canDrawOverlays(this)) 174 prepareForService(); 175 else { 176 Toast.makeText(getApplicationContext(), "權限請求被拒絕 無法正常工作 :(", Toast.LENGTH_LONG).show(); 177 finish(); 178 } 179 } 180 } 181 } 182 183 private void prepareForService() { 184 intent = new Intent(getApplicationContext(), ScreenFilterService.class); 185 startService(intent); 186 } 187 } MainActivity.java

高優先級的懸浮窗是敏感權限,6.0以上系統需要特殊處理。

在啟動時,首先調用checkPermissions()方法,判斷系統版本為6.0及以上時,通過包裝一個intent的方式,使app專門請求用戶授權此項權限。

返回後通過接收result,再一次判斷是否具有drawOverlays的權限,如果沒有,則報錯並正常退出,如果獲取到權限則啟動service。

而如果系統版本低於6.0,則可以直接喚起service使系統自動向用戶請求該項權限。

請見文章:

http://pcedu.pconline.com.cn/692/6928996.html

http://blog.csdn.net/yangqingqo/article/details/48371123/

http://www.cnblogs.com/mengdd/p/3824782.html

 

另外需要在manifest中聲明權限  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 

 

尤其要注意在startService後不能立即讀寫ScreenFilterService類中的成員變量,否則會引null異常。

所以應首先同app一起自動啟動service,並在ScreenFilterService的onCreate方法中使用removeScreenFilter()方法防止filter自動生效。

 

還需注意應在manifest中將mainActivity的啟動模式設為單例模式以防止在childActivity中通過navigationIcon返回主activity後導致的重啟使filter消失。

 

:) 暑假好開心,月底就要去上海玩了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved