项目地址:https://github.com/hwding/make-it-darker
欢迎star、fork以及一切建议和意见!
images/loading.gif' data-original="http://images2015.cnblogs.com/blog/939493/201607/939493-20160725134908559-929888155.png" width="543" height="249" />
在完全黑暗中看手机眼睛会非常容易疲劳,即使将手机亮度调整到最低也会让自己在完全适应后感到非常刺眼。
利用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 @Override20 public void onCreate() {21 super.onCreate();22 createScreenFilter();23 }24 25 @Override26 public void onDestroy() {27 super.onDestroy();28 if (linearLayout != null)29 windowManager.removeView(linearLayout);30 }31 32 @Nullable33 @Override34 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_FOCUSABLE44 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL45 | 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 @Override108 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 @Override115 public boolean onOptionsItemSelected(MenuItem item) {116 // Handle action bar item clicks here. The action bar will117 // automatically handle clicks on the Home/Up button, so long118 // as you specify a parent activity in AndroidManifest.119 int id = item.getItemId();120 121 //noinspection SimplifiableIfStatement122 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 else162 prepareForService();163 }164 else165 prepareForService();166 }167 168 @Override169 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消失。
:) 暑假好开心,月底就要去上海玩了。
原标题:利用悬浮窗进一步降低屏幕亮度保护眼睛(app based on Android)
关键词:Android