Делаем симпатичный виджет регулировки яркости
Давным давно у моей мамы на телефоне было приложение, которое позволяло изменить яркость экрана проведя пальцем по его левому краю. Мама к нему привыкла, а потом перешла на новый телефон и там уже то приложение из магазина исчезло. Собственно, не найдя аналогов, я решил написать его сам и подарить ей на день рождения. Пошаговое руководство по созданию и результат — в этой статье.
Для создания этого приложения нам потребуется два разрешения — разрешение на изменение системных настроек (непосредственно регулировка яркости) и разрешение наложения поверх других приложений. Оба этих разрешения начиная с версии Android 6.0 нельзя получить просто указав их в манифесте — их необходимо запросить у пользователя по отдельности.
Структура нашего приложения будет следующая — основная активность, которая будет иметь две кнопки — одна будет запускать службу, которая будет отрисовывать SeekBar для управления яркостью, а вторая будет эту службу останавливать. Начнем с нашей основной активности. Вот как выглядит файл разметки:
И вот как будет выглядеть сама активность:
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
public class MainActivity extends AppCompatActivity {
SeekBar seekBar;
Context context;
int Brightnes;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
//Здесь мы проверяем, какая версия Android у пользователя, и в случае, если у него шестая или выше запрашиваем разрешение по сложному алгоритму
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(myIntent);
startActivity(intent);
}
final Button startService = (Button) findViewById(R.id.startService);
final Button stopService = (Button) findViewById(R.id.stopService);
startService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(new Intent(getApplication(), BrightnessChekingService.class));
}
});
stopService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(new Intent(getApplication(), BrightnessChekingService.class));
}
});
}
}
Теперь создадим службу BrightnessChekingService, ее функции я уже указал выше. Не забывайте — в случае, если вы создаете ее вручную, необходимо зарегистрировать ее в манифесте
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.SeekBar;
public class BrightnessChekingService extends Service{
private WindowManager windowManager;
private WindowManager.LayoutParams params;
private VerticalSeekBar seekBar;
private Context context;
public void onCreate () {
super.onCreate();
//Имя требуемого нам флага наложения поверх приложений так же отличается в разных версиях системы, так что выполняем проверку
int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
context = this.getApplicationContext();
seekBar = new VerticalSeekBar(context);
seekBar.setMax(255);
float alpha = (float) 0.1;
seekBar.setAlpha(alpha);
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.MATCH_PARENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT;
params.x = 0;
params.y = 0;
params.height = 700;
windowManager.addView(seekBar, params);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,i);
}
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStopTrackingTouch (SeekBar seekBar) {
}
});
}
public void onDestroy() {
super.onDestroy();
if (seekBar != null)
windowManager.removeView(seekBar);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Ну и напоследок, создадим класс VerticalSeekBar который будет являться кастомной версией обычного SeekBar, отличие будет в том, что наш SeekBar будет располагаться вертикально
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar (Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
public synchronized void setProgress(int progress)
{
super.setProgress(progress);
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
}
Вот как при этом будет выглядеть манифест приложения:
Вот и все, простенький, но сделанный с душой подарок маме на день рождения готов. При желании можно добавить кнопки, регулирующие размер полоски, ее положение на экране и прозрачность.