需求
在悬浮窗的快捷中心中实现设置屏幕亮度的功能,一共有25/50/75/100%以及Auto五中模式。
实现方案
这个功能刚开始查资料的时候觉得挺简单,就几句代码的事情,如下:
/**
* 设置屏幕亮度
* @param brightness 即我们所希望的25/50/75/100
*/
private void setScreenBrightness(int brightness) {
// TODO Auto-generated method stub
Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, (brightness * 255 / 100));
}
并且可以通过下面的代码直接写入屏幕亮度模式(自动/普通)
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); //普通模式
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); //自动模式
遇到问题
由于我用的测试设备是Nexus 5和MotoX,在Android Lollipop和KatKit版本上没有问题,点击Button后都生效,但是项目的测试童靴在别的测试机型和系统上发现了不能立即生效的问题,要在设置里点一次亮度进度条才生效。
更好的方案
没办法又遇到碎片化的问题,我很快定位到肯定是我的setScreenBrightness方法没有生效,在网上找了下资料,发现了不是这条语句不行,而是这套代码不够严谨,有另一套更准确的实现方案,参考代码。里面用到了这个方法:
/**
* 设置屏幕亮度,这会反映到真实屏幕上
*
* @param activity
* @param brightness
*/
public void setActScreenBrightness(final Activity activity, final int brightness) {
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
lp.screenBrightness = brightness / (float) MAX_BRIGHTNESS;
activity.getWindow().setAttributes(lp);
}
其中的getWindow().getAttributes()和getWindow().setAttributes(lp)都必须通过activity调用,但是我们的控制悬浮窗是一个View,里面调不到这两个方法,而悬浮窗的创建是通过Service后台控制是没有Activity进入的,怎么办?
优化方案
那么我们就造一个Activity出来,可是这样不会影响到显示界面吗?如果只是普通的Activity是肯定会的,别的不说,至少有一个打开的动画并且又在悬浮窗上覆盖了一层View。这个时候我们就要对这个Activity做特殊处理了,由于我们只是要借助Activity的接口实现我们的方法而已,其他的功能(包括界面)我们都可以不要,所以这里应该是建造一个虚拟(Dummy)的Activity,什么事虚拟的,就是透明的无动画的成功后自动消失的,以便让用户察觉不到。
具体方案
先来看看这个DummyBrightnessActivity的代码,具体的功能在代码后有注释,创建后立即设置立即消失
/**
* @Function 虚拟的亮度窗口,用于调用设置亮度接口
* @date 2014-12-2
*
* @author rivers
* @version 1.0
*/
public class DummyBrightnessActivity extends BaseActivity {
private static final int DELAYED_MESSAGE = 1;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(msg.what == DELAYED_MESSAGE) {
DummyBrightnessActivity.this.finish(); //关闭该Activity
}
super.handleMessage(msg);
}
};
Intent brightnessIntent = this.getIntent();
int brightness = brightnessIntent.getIntExtra("brightness value", 0); //获取需要改变的亮度值
Settings.System.putInt(this.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, brightness);
WindowManager.LayoutParams lp = getWindow().getAttributes(); //调用我们需要立即实现的接口
lp.screenBrightness = brightness / 255.0f; //计算
getWindow().setAttributes(lp); //调用我们需要立即实现的接口
Message message = handler.obtainMessage(DELAYED_MESSAGE);
handler.sendMessageDelayed(message,0); //立即发送message关闭该窗口
}
}
然后要在AndroidManifest.xml中声明该Activity
<activity android:name="yourPackageName.DummyBrightnessActivity"
android:taskAffinity="yourPackageName.Dummy"
android:excludeFromRecents="true"
android:theme="@style/EmptyActivity">
</activity>
上面已经实现了创建设置后自动消失的功能了,那么还剩下透明和无动画要做到,就在这个android:theme="@style/EmptyActivity"风格中
<style name="EmptyActivity" parent="android:Theme.Dialog">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Toast</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:colorForeground">@android:color/transparent</item>
</style>
这样一来我们所需要的这个虚拟Activity就算是已经创建好了,只需要在快捷中心的View中调用下面的跳转代码,这个功能就算是完成了
private void intentToDummyBrightness(int brightness) {
Intent intent = new Intent(mContext, DummyBrightnessActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //注意一定要使用New Task
intent.putExtra("brightness value", brightness);
mContext.startActivity(intent);
}
总结
开发这个功能的时候,我犯了想当然以及重视程度不足的问题,觉得只不过调用一个读取/写入的功能就能实现了,实不知那不是最精确的办法,并且还有碎片化的问题没测试就提交了版本,下次考虑问题该更全面。