package com.android.settings.cyanogenmod;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import java.util.ArrayList;
import com.android.settings.R;
public class AutoBrightnessCustomizeDialog extends AlertDialog
implements DialogInterface.OnClickListener {
private static final String TAG = "AutoBrightnessCustomizeDialog";
private TextView mSensorLevel;
private TextView mBrightnessLevel;
private ListView mConfigList;
private SensorManager mSensorManager;
private Sensor mLightSensor;
private static class SettingRow {
int luxFrom;
int luxTo;
int backlight;
public SettingRow(int luxFrom, int luxTo, int backlight) {
this.luxFrom = luxFrom;
this.luxTo = luxTo;
this.backlight = backlight;
}
};
private SettingRowAdapter mAdapter;
private int mMinLevel;
private boolean mIsDefault;
private SensorEventListener mLightSensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
final int lux = Math.round(event.values[0]);
mSensorLevel.setText(getContext().getString(R.string.light_sensor_current_value, lux));
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
public AutoBrightnessCustomizeDialog(Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
final Context context = getContext();
View view = getLayoutInflater().inflate(R.layout.dialog_auto_brightness_levels, null);
setView(view);
setTitle(R.string.auto_brightness_dialog_title);
setCancelable(true);
setButton(DialogInterface.BUTTON_POSITIVE, context.getString(android.R.string.ok), this);
setButton(DialogInterface.BUTTON_NEUTRAL,
context.getString(R.string.auto_brightness_reset_button), this);
setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), this);
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mMinLevel = pm.getMinimumAbsoluteScreenBrightness();
mSensorLevel = (TextView) view.findViewById(R.id.light_sensor_value);
mBrightnessLevel = (TextView) view.findViewById(R.id.current_brightness);
mConfigList = (ListView) view.findViewById(android.R.id.list);
mAdapter = new SettingRowAdapter(context, new ArrayList<SettingRow>());
mConfigList.setAdapter(mAdapter);
registerForContextMenu(mConfigList);
}
@Override
protected void onStart() {
updateSettings(false);
super.onStart();
mSensorManager.registerListener(mLightSensorListener,
mLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
Button neutralButton = getButton(DialogInterface.BUTTON_NEUTRAL);
neutralButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showResetConfirmation();
}
});
}
@Override
protected void onStop() {
super.onStop();
mSensorManager.unregisterListener(mLightSensorListener, mLightSensor);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
menu.setHeaderTitle(R.string.auto_brightness_level_options);
menu.add(Menu.NONE, Menu.FIRST, 0, R.string.auto_brightness_menu_edit_lux)
.setEnabled(!mAdapter.isLastItem(info.position));
menu.add(Menu.NONE, Menu.FIRST + 1, 1, R.string.auto_brightness_menu_split)
.setEnabled(mAdapter.canSplitRow(info.position));
menu.add(Menu.NONE, Menu.FIRST + 2, 2, R.string.auto_brightness_menu_remove)
.setEnabled(mAdapter.getCount() > 1);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int position = info.position;
switch (item.getItemId() - Menu.FIRST) {
case 0:
showLuxSetup(position);
return true;
case 1:
showSplitDialog(position);
break;
case 2:
mAdapter.removeRow(position);
return true;
}
return false;
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
putSettings();
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
cancel();
}
}
private void updateSettings(boolean forceDefault) {
int[] lux = null, values = null;
if (!forceDefault) {
lux = fetchItems(Settings.System.AUTO_BRIGHTNESS_LUX);
values = fetchItems(Settings.System.AUTO_BRIGHTNESS_BACKLIGHT);
}
if (lux != null && values != null && lux.length != values.length - 1) {
Log.e(TAG, "Found invalid backlight settings, ignoring");
values = null;
}
if (lux == null || values == null) {
final Resources res = getContext().getResources();
lux = res.getIntArray(com.android.internal.R.array.config_autoBrightnessLevels);
values = res.getIntArray(com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
mIsDefault = true;
} else {
mIsDefault = false;
}
mAdapter.initFromSettings(lux, values);
}
private void showLuxSetup(final int position) {
final SettingRow row = mAdapter.getItem(position);
final View v = getLayoutInflater().inflate(R.layout.auto_brightness_lux_config, null);
final EditText startLux = (EditText) v.findViewById(R.id.start_lux);
final EditText endLux = (EditText) v.findViewById(R.id.end_lux);
final AlertDialog d = new AlertDialog.Builder(getContext())
.setTitle(R.string.auto_brightness_lux_dialog_title)
.setCancelable(true)
.setView(v)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int which) {
try {
int newLux = Integer.valueOf(endLux.getText().toString());
mAdapter.setLuxToForRow(position, newLux);
} catch (NumberFormatException e) {
//ignored
}
}
})
.setNegativeButton(R.string.cancel, null)
.create();
startLux.setText(String.valueOf(row.luxFrom));
endLux.setText(String.valueOf(row.luxTo));
d.show();
}
private void showSplitDialog(final int position) {
final SettingRow row = mAdapter.getItem(position);
final View v = getLayoutInflater().inflate(R.layout.auto_brightness_split_dialog, null);
final TextView label = (TextView) v.findViewById(R.id.split_label);
final EditText value = (EditText) v.findViewById(R.id.split_position);
final AlertDialog d = new AlertDialog.Builder(getContext())
.setTitle(R.string.auto_brightness_lux_dialog_title)
.setCancelable(true)
.setView(v)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int which) {
int splitLux = Integer.valueOf(value.getText().toString());
mAdapter.splitRow(position, splitLux);
}
})
.setNegativeButton(R.string.cancel, null)
.create();
label.setText(getContext().getString(R.string.auto_brightness_split_lux_format,
row.luxFrom + 1, row.luxTo - 1));
value.setText(String.valueOf(row.luxFrom + 1));
value.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
boolean ok = false;
try {
int newLux = Integer.valueOf(s.toString());
ok = newLux > row.luxFrom && newLux < row.luxTo;
} catch (NumberFormatException e) {
//ignored, ok is false anyway
}
Button okButton = d.getButton(DialogInterface.BUTTON_POSITIVE);
if (okButton != null) {
okButton.setEnabled(ok);
}
}
});
d.show();
}
private void showResetConfirmation() {
final AlertDialog d = new AlertDialog.Builder(getContext())
.setTitle(R.string.auto_brightness_reset_dialog_title)
.setCancelable(true)
.setMessage(R.string.auto_brightness_reset_confirmation)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int which) {
updateSettings(true);
}
})
.setNegativeButton(R.string.cancel, null)
.create();
d.show();
}
private void putSettings() {
int[] lux = null, values = null;
if (!mIsDefault) {
lux = mAdapter.getLuxValues();
values = mAdapter.getBacklightValues();
}
putItems(Settings.System.AUTO_BRIGHTNESS_LUX, lux);
putItems(Settings.System.AUTO_BRIGHTNESS_BACKLIGHT, values);
}
private int[] fetchItems(String setting) {
String value = Settings.System.getString(getContext().getContentResolver(), setting);
if (value != null) {
String[] values = value.split(",");
if (values != null && values.length != 0) {
int[] result = new int[values.length];
int i;
for (i = 0; i < values.length; i++) {
try {
result[i] = Integer.valueOf(values[i]);
} catch (NumberFormatException e) {
break;
}
}
if (i == values.length) {
return result;
}
}
}
return null;
}
private void putItems(String setting, int[] values) {
String value = null;
if (values != null) {
final StringBuilder builder = new StringBuilder();
for (int i = 0; i < values.length; i++) {
if (i > 0) {
builder.append(",");
}
builder.append(values[i]);
}
value = builder.toString();
}
Settings.System.putString(getContext().getContentResolver(), setting, value);
}
private class SettingRowAdapter extends ArrayAdapter<SettingRow> {
public SettingRowAdapter(Context context, ArrayList<SettingRow> rows) {
super(context, 0, rows);
setNotifyOnChange(false);
}
private boolean isLastItem(int position) {
return position == getCount() - 1;
}
public boolean canSplitRow(int position) {
if (isLastItem(position)) {
return false;
}
SettingRow row = getItem(position);
return row.luxTo > (row.luxFrom + 1);
}
public void initFromSettings(int[] lux, int[] values) {
ArrayList<SettingRow> settings = new ArrayList<SettingRow>(values.length);
for (int i = 0; i < lux.length; i++) {
settings.add(new SettingRow(i == 0 ? 0 : lux[i - 1], lux[i], values[i]));
}
settings.add(new SettingRow(lux[lux.length - 1], Integer.MAX_VALUE, values[values.length - 1]));
clear();
addAll(settings);
notifyDataSetChanged();
}
public int[] getLuxValues() {
int count = getCount();
int[] lux = new int[count - 1];
for (int i = 0; i < count - 1; i++) {
lux[i] = getItem(i).luxTo;
}
return lux;
}
public int[] getBacklightValues() {
int count = getCount();
int[] values = new int[count];
for (int i = 0; i < count; i++) {
values[i] = getItem(i).backlight;
}
return values;
}
public void splitRow(int position, int splitLux) {
if (!canSplitRow(position)) {
return;
}
ArrayList<SettingRow> rows = new ArrayList<SettingRow>();
for (int i = 0; i <= position; i++) {
rows.add(getItem(i));
}
SettingRow lastRow = getItem(position);
SettingRow nextRow = getItem(position + 1);
rows.add(new SettingRow(splitLux, nextRow.luxFrom, lastRow.backlight));
for (int i = position + 1; i < getCount(); i++) {
rows.add(getItem(i));
}
clear();
addAll(rows);
sanitizeValuesAndNotify();
}
public void removeRow(int position) {
if (getCount() <= 1) {
return;
}
remove(getItem(position));
sanitizeValuesAndNotify();
}
public void setLuxToForRow(final int position, int newLuxTo) {
final SettingRow row = getItem(position);
if (isLastItem(position) || row.luxTo == newLuxTo) {
return;
}
row.luxTo = newLuxTo;
sanitizeValuesAndNotify();
}
public void sanitizeValuesAndNotify() {
final int count = getCount();
getItem(0).luxFrom = 0;
for (int i = 1; i < count; i++) {
SettingRow lastRow = getItem(i - 1);
SettingRow thisRow = getItem(i);
thisRow.luxFrom = Math.max(lastRow.luxFrom + 1, thisRow.luxFrom);
thisRow.backlight = Math.max(lastRow.backlight, thisRow.backlight);
lastRow.luxTo = thisRow.luxFrom;
}
getItem(count - 1).luxTo = Integer.MAX_VALUE;
mIsDefault = false;
mAdapter.notifyDataSetChanged();
}
private int brightnessToProgress(int brightness) {
brightness -= mMinLevel;
return brightness * 100;
}
private float progressToBrightness(int progress) {
float brightness = (float) progress / 100F;
return brightness + mMinLevel;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final Holder holder;
if (convertView == null) {
convertView = getLayoutInflater().inflate(
R.layout.auto_brightness_list_item, parent, false);
holder = new Holder();
holder.lux = (TextView) convertView.findViewById(R.id.lux);
holder.backlight = (SeekBar) convertView.findViewById(R.id.backlight);
holder.percent = (TextView) convertView.findViewById(R.id.backlight_percent);
convertView.setTag(holder);
holder.backlight.setMax(brightnessToProgress(PowerManager.BRIGHTNESS_ON));
holder.backlight.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
private boolean mIsDragging = false;
private void updateBrightness(float brightness) {
final Window window = getWindow();
final WindowManager.LayoutParams params = window.getAttributes();
params.screenBrightness = brightness;
window.setAttributes(params);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int pos = (Integer) seekBar.getTag();
if (fromUser) {
int minValue = pos == 0
? 0
: brightnessToProgress(getItem(pos - 1).backlight);
int maxValue = isLastItem(pos)
? seekBar.getMax()
: brightnessToProgress(getItem(pos + 1).backlight);
if (progress < minValue) {
seekBar.setProgress(minValue);
return;
} else if (progress > maxValue) {
seekBar.setProgress(maxValue);
return;
}
getItem(pos).backlight = Math.round(progressToBrightness(progress));
mIsDefault = false;
}
if (mIsDragging) {
float brightness = progressToBrightness(progress);
updateBrightness(brightness / PowerManager.BRIGHTNESS_ON);
}
holder.updatePercent();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
float brightness = progressToBrightness(seekBar.getProgress());
updateBrightness(brightness / PowerManager.BRIGHTNESS_ON);
mIsDragging = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
updateBrightness(WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE);
mIsDragging = false;
}
});
} else {
holder = (Holder) convertView.getTag();
}
SettingRow row = (SettingRow) getItem(position);
final String to = row.luxTo == Integer.MAX_VALUE ? "\u221e" : String.valueOf(row.luxTo);
holder.lux.setText(getContext().getString(R.string.auto_brightness_level_format,
String.valueOf(row.luxFrom), to));
holder.backlight.setTag(position);
holder.backlight.setProgress(brightnessToProgress(row.backlight));
holder.updatePercent();
return convertView;
}
private class Holder {
TextView lux;
SeekBar backlight;
TextView percent;
public void updatePercent() {
int percentValue = Math.round((float) backlight.getProgress() * 100F / backlight.getMax());
percent.setText(getContext().getString(
R.string.auto_brightness_brightness_format, percentValue));
}
};
};
}