23 |

24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
19 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
22 |
23 |
26 |
27 |
32 |
33 |
39 |
40 |
45 |
46 |
47 |
48 |
51 |
52 |
57 |
58 |
63 |
64 |
70 |
71 |
72 |
73 |
78 |
79 |
85 |
86 |
87 |
88 |
89 |
96 |
97 |
102 |
103 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/src/main/java/org/dync/androidsystembar/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.dync.androidsystembar;
2 |
3 | import android.content.Context;
4 | import android.content.pm.ActivityInfo;
5 | import android.content.res.Configuration;
6 | import android.graphics.Color;
7 | import android.os.Bundle;
8 | import android.support.annotation.IdRes;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.RadioButton;
13 | import android.widget.RadioGroup;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import com.chiralcode.colorpicker.ColorPicker;
18 |
19 | public class MainActivity extends AppCompatActivity {
20 |
21 | private Context mContext;
22 | private ColorPicker mColorPicker;
23 | private Button mButton;
24 | private TextView mTitle;
25 | private RadioGroup mRadioGroup;
26 | private RadioGroup mRadioGroupConfiguration;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_main);
32 | mContext = this;
33 |
34 | mColorPicker = (ColorPicker) findViewById(R.id.color_picker);
35 | mTitle = (TextView) findViewById(R.id.tv_title);
36 |
37 | mRadioGroup = (RadioGroup) findViewById(R.id.rgroup);
38 | mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
39 | @Override
40 | public void onCheckedChanged(RadioGroup group, int checkedId) {
41 | int checkedRadioButtonId = group.getCheckedRadioButtonId();
42 | String message = "";
43 | RadioButton radioButton = null;
44 | if (checkedRadioButtonId == R.id.rb_statusbar_white) {
45 | StatusBarUtil.StatusBarLightMode(MainActivity.this, false);
46 | } else {
47 | StatusBarUtil.StatusBarLightMode(MainActivity.this, true);
48 | }
49 | radioButton = (RadioButton) MainActivity.this.findViewById(checkedRadioButtonId);
50 | message = radioButton.getText().toString();
51 | Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
52 | }
53 | });
54 | mRadioGroupConfiguration = (RadioGroup) findViewById(R.id.rgroup_configuration);
55 |
56 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);// 竖屏
57 | mRadioGroupConfiguration.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
58 | @Override
59 | public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
60 | if (checkedId == R.id.rb_landscape) {//横屏
61 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
62 | // getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏
63 | StatusBarUtil.setFitsSystemWindows(MainActivity.this, true);
64 | } else if (checkedId == R.id.rb_portrait) {//竖屏
65 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);// 竖屏
66 | // getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//清除全屏
67 | StatusBarUtil.setFitsSystemWindows(MainActivity.this, false);
68 | }
69 | }
70 | });
71 | mButton = (Button) findViewById(R.id.button);
72 | mButton.setOnClickListener(new View.OnClickListener() {
73 | @Override
74 | public void onClick(View v) {
75 | applySelectedColor();
76 | }
77 | });
78 | StatusBarUtil.setStatusBarColor(MainActivity.this, getResources().getColor(R.color.colorAccent));
79 | mTitle.setBackgroundColor(getResources().getColor(R.color.colorAccent));
80 | }
81 |
82 | @Override
83 | protected void onStart() {
84 | super.onStart();
85 | StatusBarUtil.setSystemUI(MainActivity.this, true);
86 | }
87 |
88 | @Override
89 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
90 | super.onRestoreInstanceState(savedInstanceState);
91 | // applySelectedColor();
92 | }
93 |
94 | private void applySelectedColor() {
95 | int selected = mColorPicker.getColor();
96 | // int color = Color.argb(153, Color.red(selected), Color.green(selected), Color.blue(selected));
97 | int color = Color.rgb(Color.red(selected), Color.green(selected), Color.blue(selected));
98 |
99 | StatusBarUtil.setStatusBarColor(MainActivity.this, color);
100 | mTitle.setBackgroundColor(color);
101 | }
102 |
103 | @Override
104 | public void onConfigurationChanged(Configuration newConfig) {
105 | super.onConfigurationChanged(newConfig);
106 | if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {// 横屏
107 | // Log.e(TAG, "onConfigurationChanged: " + "横屏");
108 | // onConfigurationLandScape();
109 |
110 | } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
111 | // Log.e(TAG, "onConfigurationChanged: " + "竖屏");
112 | // onConfigurationPortrait();
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/app/src/main/java/org/dync/androidsystembar/StatusBarUtil.java:
--------------------------------------------------------------------------------
1 | package org.dync.androidsystembar;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.os.Build;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.Window;
9 | import android.view.WindowManager;
10 |
11 | import java.lang.reflect.Field;
12 | import java.lang.reflect.Method;
13 |
14 | /**
15 | * Created by xiongxuesong-pc on 2016/5/15.
16 | */
17 | public class StatusBarUtil {
18 |
19 | private static SystemBarTintManager tintManager;
20 |
21 | /**
22 | * 修改状态栏为全透明
23 | *
24 | * @param activity
25 | */
26 | public static void transparencyBar(Activity activity) {
27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
28 | Window window = activity.getWindow();
29 | window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
30 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
31 | }
32 | }
33 |
34 | /**
35 | * 修改状态栏颜色,支持4.4以上版本,保持沉浸式状态
36 | *
37 | * @param activity
38 | * @param colorId
39 | */
40 | public static void setStatusBarColor(Activity activity, int colorId) {
41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
42 | //使用SystemBarTint库使4.4版本状态栏变色,需要先将状态栏设置为透明
43 | transparencyBar(activity);
44 | ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
45 | View parentView = contentFrameLayout.getChildAt(0);
46 | if (parentView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
47 | parentView.setFitsSystemWindows(true);
48 | }
49 | tintManager = new SystemBarTintManager(activity);
50 | tintManager.setStatusBarTintEnabled(true);
51 | tintManager.setStatusBarTintColor(colorId);
52 | /*// set a custom tint color for all system bars
53 | tintManager.setTintColor(Color.parseColor("#99000FF"));
54 | // set a custom navigation bar resource
55 | tintManager.setNavigationBarTintResource(R.drawable.my_tint);
56 | // set a custom status bar drawable
57 | tintManager.setStatusBarTintDrawable(MyDrawable);*/
58 | }
59 | }
60 |
61 | /**
62 | * 设置WindowManager.LayoutParams.FLAG_FULLSCREEN时,由于使用了fitSystemWindows()方法,导致的问题
63 | * 支持4.4以上版本,在6.0以上可以不需要调用该方法了
64 | *
65 | * @param activity
66 | * @param flag_fullscreen true:添加全屏 false:清除全屏
67 | */
68 | public static void setFitsSystemWindows(Activity activity, boolean flag_fullscreen) {
69 | ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
70 | View parentView = contentFrameLayout.getChildAt(0);
71 | if (flag_fullscreen) {
72 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏
73 | } else {
74 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//清除全屏
75 | }
76 | if (parentView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
77 | if (tintManager != null) {
78 | if (flag_fullscreen) {
79 | tintManager.setStatusBarTintEnabled(false);
80 | } else {
81 | tintManager.setStatusBarTintEnabled(true);
82 | }
83 | }
84 | }
85 | }
86 |
87 | /**
88 | *
89 | * @param activity
90 | * @param navigationBarState navigationBar是否可见,true:可见 false:不可见
91 | */
92 | public static void setSystemUI(Activity activity, boolean navigationBarState){
93 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
94 | Window window = activity.getWindow();
95 | if(navigationBarState){
96 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
97 | | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
98 | //添加Flag把状态栏设为可绘制模式
99 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
100 | int uiFlags = 0;
101 | // uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;//隐藏NavigationBar时会留下空白
102 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
103 | uiFlags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
104 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
105 | uiFlags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
106 | window.getDecorView().setSystemUiVisibility(uiFlags);
107 | window.setNavigationBarColor(Color.TRANSPARENT);
108 | window.setStatusBarColor(Color.TRANSPARENT);
109 | }else {
110 | window.getDecorView().setSystemUiVisibility(0);
111 | }
112 | }
113 | }
114 |
115 | /**
116 | * 设置状态栏黑色字体图标,
117 | * 适配4.4以上版本MIUIV、Flyme和6.0以上版本其他Android
118 | *
119 | * @param activity
120 | * @param dark 是否把状态栏字体及图标颜色设置为深色
121 | * @return 1:MIUUI 2:Flyme 3:android6.0
122 | */
123 | public static int StatusBarLightMode(Activity activity, boolean dark) {
124 | int result = 0;
125 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
126 | if (MIUISetStatusBarLightMode(activity.getWindow(), dark)) {
127 | result = 1;
128 | } else if (FlymeSetStatusBarLightMode(activity.getWindow(), dark)) {
129 | result = 2;
130 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
131 | View decorView = activity.getWindow().getDecorView();
132 | int oldVis = decorView.getSystemUiVisibility();
133 | int newVis = oldVis;
134 | if (dark) {
135 | newVis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
136 | } else {
137 | newVis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
138 | }
139 | if (newVis != oldVis) {
140 | decorView.setSystemUiVisibility(newVis);
141 | }
142 | result = 3;
143 | }
144 | }
145 | return result;
146 | }
147 |
148 | /**
149 | * 设置状态栏图标为深色和魅族特定的文字风格
150 | * 可以用来判断是否为Flyme用户
151 | *
152 | * @param window 需要设置的窗口
153 | * @param dark 是否把状态栏字体及图标颜色设置为深色
154 | * @return boolean 成功执行返回true
155 | */
156 | public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
157 | boolean result = false;
158 | if (window != null) {
159 | try {
160 | WindowManager.LayoutParams lp = window.getAttributes();
161 | Field darkFlag = WindowManager.LayoutParams.class
162 | .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
163 | Field meizuFlags = WindowManager.LayoutParams.class
164 | .getDeclaredField("meizuFlags");
165 | darkFlag.setAccessible(true);
166 | meizuFlags.setAccessible(true);
167 | int bit = darkFlag.getInt(null);
168 | int value = meizuFlags.getInt(lp);
169 | if (dark) {
170 | value |= bit;
171 | } else {
172 | value &= ~bit;
173 | }
174 | meizuFlags.setInt(lp, value);
175 | window.setAttributes(lp);
176 | result = true;
177 | } catch (Exception e) {
178 |
179 | }
180 | }
181 | return result;
182 | }
183 |
184 | /**
185 | * 设置状态栏字体图标为深色,需要MIUIV6以上
186 | *
187 | * @param window 需要设置的窗口
188 | * @param dark 是否把状态栏字体及图标颜色设置为深色
189 | * @return boolean 成功执行返回true
190 | */
191 | public static boolean MIUISetStatusBarLightMode(Window window, boolean dark) {
192 | boolean result = false;
193 | if (window != null) {
194 | Class clazz = window.getClass();
195 | try {
196 | int darkModeFlag = 0;
197 | Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
198 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
199 | darkModeFlag = field.getInt(layoutParams);
200 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
201 | if (dark) {
202 | extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
203 | } else {
204 | extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
205 | }
206 | result = true;
207 | } catch (Exception e) {
208 |
209 | }
210 | }
211 | return result;
212 | }
213 |
214 | /**
215 | * 已知系统类型时,设置状态栏黑色字体图标。
216 | * 适配4.4以上版本MIUIV、Flyme和6.0以上版本其他Android
217 | *
218 | * @param activity
219 | * @param type 1:MIUUI 2:Flyme 3:android6.0
220 | */
221 | public static void StatusBarLightMode(Activity activity, int type) {
222 | if (type == 1) {
223 | MIUISetStatusBarLightMode(activity.getWindow(), true);
224 | } else if (type == 2) {
225 | FlymeSetStatusBarLightMode(activity.getWindow(), true);
226 | } else if (type == 3) {
227 | View decorView = activity.getWindow().getDecorView();
228 | int oldVis = decorView.getSystemUiVisibility();
229 | int newVis = oldVis;
230 | newVis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
231 | if (newVis != oldVis) {
232 | decorView.setSystemUiVisibility(newVis);
233 | }
234 | }
235 |
236 | }
237 |
238 | /**
239 | * 清除MIUI或flyme或6.0以上版本状态栏黑色字体,即白色字体
240 | */
241 | public static void StatusBarDarkMode(Activity activity, int type) {
242 | if (type == 1) {
243 | MIUISetStatusBarLightMode(activity.getWindow(), false);
244 | } else if (type == 2) {
245 | FlymeSetStatusBarLightMode(activity.getWindow(), false);
246 | } else if (type == 3) {
247 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
248 | }
249 |
250 | }
251 |
252 | }
253 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 改变状态栏颜色
4 | Color Example
5 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ligula sapien, fermentum vitae aliquam sed, lacinia in nibh. Pellentesque euismod diam eget justo interdum, sit amet elementum ipsum vulputate. Aliquam sed purus urna. Vivamus luctus nisi sem, a fringilla velit iaculis id. Donec nec vulputate justo. Fusce vulputate sodales tellus, in fringilla ante posuere non. Vivamus vulputate nisl non augue dignissim, consectetur rutrum risus facilisis. Sed consectetur aliquam dolor, sed pulvinar mi tristique vitae. Donec quis ligula quis velit consequat dictum id eu felis. Mauris ac congue ante, sed elementum eros.\n\nSed eu euismod dolor, a vestibulum lorem. Phasellus euismod volutpat risus sit amet pellentesque. Integer sit amet nisl malesuada, posuere orci sodales, euismod metus. Suspendisse potenti. Nullam mollis tristique accumsan. Vestibulum sit amet dictum nisl. Sed rhoncus lacus purus, vitae scelerisque urna venenatis at.\n\nUt ornare sapien sed condimentum varius. Nulla ut varius nibh. Nam consequat ligula sem, interdum hendrerit diam commodo sed. Vestibulum imperdiet mauris quis mauris vestibulum lobortis. Nunc bibendum, nunc ut porttitor tristique, turpis mauris cursus magna, ac molestie risus hendrerit odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras pulvinar odio vestibulum ligula mollis, vel venenatis orci semper. Duis consectetur molestie justo, ut pulvinar nisi semper vel. Cras quis fringilla augue, ut vehicula turpis. Praesent nec imperdiet dui. Morbi quis pharetra lectus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed luctus mauris vitae augue rhoncus, vel interdum nisl pellentesque. In tempor, mi et vestibulum condimentum, nisl mauris cursus diam, aliquet vestibulum risus erat sit amet diam.\n\nInteger suscipit eros at diam tempor, ac condimentum turpis pharetra. Vestibulum pharetra risus in lacus semper, at bibendum ligula condimentum. Proin sed massa eget risus malesuada dignissim et in ipsum. Donec convallis tellus vel lectus lobortis, non lobortis libero faucibus. Sed nec posuere mi. Pellentesque sed sem sit amet erat lobortis commodo nec ut nisl. Pellentesque rhoncus risus id massa accumsan, hendrerit posuere mauris pulvinar.\n\nNullam risus felis, dictum et varius eget, rutrum non nunc. Vestibulum lorem nulla, porttitor ac sapien interdum, porta tristique turpis. Quisque ut dui vitae urna congue scelerisque. Nulla eu commodo felis. Nulla aliquam magna a arcu elementum, vitae tincidunt risus semper. Sed consectetur diam vel magna mattis, sed congue nisi fringilla. Ut in facilisis elit. Etiam aliquet orci urna. Nam interdum nunc fringilla iaculis cursus.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ligula sapien, fermentum vitae aliquam sed, lacinia in nibh. Pellentesque euismod diam eget justo interdum, sit amet elementum ipsum vulputate. Aliquam sed purus urna. Vivamus luctus nisi sem, a fringilla velit iaculis id. Donec nec vulputate justo. Fusce vulputate sodales tellus, in fringilla ante posuere non. Vivamus vulputate nisl non augue dignissim, consectetur rutrum risus facilisis. Sed consectetur aliquam dolor, sed pulvinar mi tristique vitae. Donec quis ligula quis velit consequat dictum id eu felis. Mauris ac congue ante, sed elementum eros.\n\nSed eu euismod dolor, a vestibulum lorem. Phasellus euismod volutpat risus sit amet pellentesque. Integer sit amet nisl malesuada, posuere orci sodales, euismod metus. Suspendisse potenti. Nullam mollis tristique accumsan. Vestibulum sit amet dictum nisl. Sed rhoncus lacus purus, vitae scelerisque urna venenatis at.\n\nUt ornare sapien sed condimentum varius. Nulla ut varius nibh. Nam consequat ligula sem, interdum hendrerit diam commodo sed. Vestibulum imperdiet mauris quis mauris vestibulum lobortis. Nunc bibendum, nunc ut porttitor tristique, turpis mauris cursus magna, ac molestie risus hendrerit odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras pulvinar odio vestibulum ligula mollis, vel venenatis orci semper. Duis consectetur molestie justo, ut pulvinar nisi semper vel. Cras quis fringilla augue, ut vehicula turpis. Praesent nec imperdiet dui. Morbi quis pharetra lectus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed luctus mauris vitae augue rhoncus, vel interdum nisl pellentesque. In tempor, mi et vestibulum condimentum, nisl mauris cursus diam, aliquet vestibulum risus erat sit amet diam.\n\nInteger suscipit eros at diam tempor, ac condimentum turpis pharetra. Vestibulum pharetra risus in lacus semper, at bibendum ligula condimentum. Proin sed massa eget risus malesuada dignissim et in ipsum. Donec convallis tellus vel lectus lobortis, non lobortis libero faucibus. Sed nec posuere mi. Pellentesque sed sem sit amet erat lobortis commodo nec ut nisl. Pellentesque rhoncus risus id massa accumsan, hendrerit posuere mauris pulvinar.\n\nNullam risus felis, dictum et varius eget, rutrum non nunc. Vestibulum lorem nulla, porttitor ac sapien interdum, porta tristique turpis. Quisque ut dui vitae urna congue scelerisque. Nulla eu commodo felis. Nulla aliquam magna a arcu elementum, vitae tincidunt risus semper. Sed consectetur diam vel magna mattis, sed congue nisi fringilla. Ut in facilisis elit. Etiam aliquet orci urna. Nam interdum nunc fringilla iaculis cursus.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ligula sapien, fermentum vitae aliquam sed, lacinia in nibh. Pellentesque euismod diam eget justo interdum, sit amet elementum ipsum vulputate. Aliquam sed purus urna. Vivamus luctus nisi sem, a fringilla velit iaculis id. Donec nec vulputate justo. Fusce vulputate sodales tellus, in fringilla ante posuere non. Vivamus vulputate nisl non augue dignissim, consectetur rutrum risus facilisis. Sed consectetur aliquam dolor, sed pulvinar mi tristique vitae. Donec quis ligula quis velit consequat dictum id eu felis. Mauris ac congue ante, sed elementum eros.\n\nSed eu euismod dolor, a vestibulum lorem. Phasellus euismod volutpat risus sit amet pellentesque. Integer sit amet nisl malesuada, posuere orci sodales, euismod metus. Suspendisse potenti. Nullam mollis tristique accumsan. Vestibulum sit amet dictum nisl. Sed rhoncus lacus purus, vitae scelerisque urna venenatis at.\n\nUt ornare sapien sed condimentum varius. Nulla ut varius nibh. Nam consequat ligula sem, interdum hendrerit diam commodo sed. Vestibulum imperdiet mauris quis mauris vestibulum lobortis. Nunc bibendum, nunc ut porttitor tristique, turpis mauris cursus magna, ac molestie risus hendrerit odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras pulvinar odio vestibulum ligula mollis, vel venenatis orci semper. Duis consectetur molestie justo, ut pulvinar nisi semper vel. Cras quis fringilla augue, ut vehicula turpis. Praesent nec imperdiet dui. Morbi quis pharetra lectus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed luctus mauris vitae augue rhoncus, vel interdum nisl pellentesque. In tempor, mi et vestibulum condimentum, nisl mauris cursus diam, aliquet vestibulum risus erat sit amet diam.\n\nInteger suscipit eros at diam tempor, ac condimentum turpis pharetra. Vestibulum pharetra risus in lacus semper, at bibendum ligula condimentum. Proin sed massa eget risus malesuada dignissim et in ipsum. Donec convallis tellus vel lectus lobortis, non lobortis libero faucibus. Sed nec posuere mi. Pellentesque sed sem sit amet erat lobortis commodo nec ut nisl. Pellentesque rhoncus risus id massa accumsan, hendrerit posuere mauris pulvinar.\n\nNullam risus felis, dictum et varius eget, rutrum non nunc. Vestibulum lorem nulla, porttitor ac sapien interdum, porta tristique turpis. Quisque ut dui vitae urna congue scelerisque. Nulla eu commodo felis. Nulla aliquam magna a arcu elementum, vitae tincidunt risus semper. Sed consectetur diam vel magna mattis, sed congue nisi fringilla. Ut in facilisis elit. Etiam aliquet orci urna. Nam interdum nunc fringilla iaculis cursus.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ligula sapien, fermentum vitae aliquam sed, lacinia in nibh. Pellentesque euismod diam eget justo interdum, sit amet elementum ipsum vulputate. Aliquam sed purus urna. Vivamus luctus nisi sem, a fringilla velit iaculis id. Donec nec vulputate justo. Fusce vulputate sodales tellus, in fringilla ante posuere non. Vivamus vulputate nisl non augue dignissim, consectetur rutrum risus facilisis. Sed consectetur aliquam dolor, sed pulvinar mi tristique vitae. Donec quis ligula quis velit consequat dictum id eu felis. Mauris ac congue ante, sed elementum eros.\n\nSed eu euismod dolor, a vestibulum lorem. Phasellus euismod volutpat risus sit amet pellentesque. Integer sit amet nisl malesuada, posuere orci sodales, euismod metus. Suspendisse potenti. Nullam mollis tristique accumsan. Vestibulum sit amet dictum nisl. Sed rhoncus lacus purus, vitae scelerisque urna venenatis at.\n\nUt ornare sapien sed condimentum varius. Nulla ut varius nibh. Nam consequat ligula sem, interdum hendrerit diam commodo sed. Vestibulum imperdiet mauris quis mauris vestibulum lobortis. Nunc bibendum, nunc ut porttitor tristique, turpis mauris cursus magna, ac molestie risus hendrerit odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras pulvinar odio vestibulum ligula mollis, vel venenatis orci semper. Duis consectetur molestie justo, ut pulvinar nisi semper vel. Cras quis fringilla augue, ut vehicula turpis. Praesent nec imperdiet dui. Morbi quis pharetra lectus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed luctus mauris vitae augue rhoncus, vel interdum nisl pellentesque. In tempor, mi et vestibulum condimentum, nisl mauris cursus diam, aliquet vestibulum risus erat sit amet diam.\n\nInteger suscipit eros at diam tempor, ac condimentum turpis pharetra. Vestibulum pharetra risus in lacus semper, at bibendum ligula condimentum. Proin sed massa eget risus malesuada dignissim et in ipsum. Donec convallis tellus vel lectus lobortis, non lobortis libero faucibus. Sed nec posuere mi. Pellentesque sed sem sit amet erat lobortis commodo nec ut nisl. Pellentesque rhoncus risus id massa accumsan, hendrerit posuere mauris pulvinar.\n\nNullam risus felis, dictum et varius eget, rutrum non nunc. Vestibulum lorem nulla, porttitor ac sapien interdum, porta tristique turpis. Quisque ut dui vitae urna congue scelerisque. Nulla eu commodo felis. Nulla aliquam magna a arcu elementum, vitae tincidunt risus semper. Sed consectetur diam vel magna mattis, sed congue nisi fringilla. Ut in facilisis elit. Etiam aliquet orci urna. Nam interdum nunc fringilla iaculis cursus.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ligula sapien, fermentum vitae aliquam sed, lacinia in nibh. Pellentesque euismod diam eget justo interdum, sit amet elementum ipsum vulputate. Aliquam sed purus urna. Vivamus luctus nisi sem, a fringilla velit iaculis id. Donec nec vulputate justo. Fusce vulputate sodales tellus, in fringilla ante posuere non. Vivamus vulputate nisl non augue dignissim, consectetur rutrum risus facilisis. Sed consectetur aliquam dolor, sed pulvinar mi tristique vitae. Donec quis ligula quis velit consequat dictum id eu felis. Mauris ac congue ante, sed elementum eros.\n\nSed eu euismod dolor, a vestibulum lorem. Phasellus euismod volutpat risus sit amet pellentesque. Integer sit amet nisl malesuada, posuere orci sodales, euismod metus. Suspendisse potenti. Nullam mollis tristique accumsan. Vestibulum sit amet dictum nisl. Sed rhoncus lacus purus, vitae scelerisque urna venenatis at.\n\nUt ornare sapien sed condimentum varius. Nulla ut varius nibh. Nam consequat ligula sem, interdum hendrerit diam commodo sed. Vestibulum imperdiet mauris quis mauris vestibulum lobortis. Nunc bibendum, nunc ut porttitor tristique, turpis mauris cursus magna, ac molestie risus hendrerit odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras pulvinar odio vestibulum ligula mollis, vel venenatis orci semper. Duis consectetur molestie justo, ut pulvinar nisi semper vel. Cras quis fringilla augue, ut vehicula turpis. Praesent nec imperdiet dui. Morbi quis pharetra lectus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed luctus mauris vitae augue rhoncus, vel interdum nisl pellentesque. In tempor, mi et vestibulum condimentum, nisl mauris cursus diam, aliquet vestibulum risus erat sit amet diam.\n\nInteger suscipit eros at diam tempor, ac condimentum turpis pharetra. Vestibulum pharetra risus in lacus semper, at bibendum ligula condimentum. Proin sed massa eget risus malesuada dignissim et in ipsum. Donec convallis tellus vel lectus lobortis, non lobortis libero faucibus. Sed nec posuere mi. Pellentesque sed sem sit amet erat lobortis commodo nec ut nisl. Pellentesque rhoncus risus id massa accumsan, hendrerit posuere mauris pulvinar.\n\nNullam risus felis, dictum et varius eget, rutrum non nunc. Vestibulum lorem nulla, porttitor ac sapien interdum, porta tristique turpis. Quisque ut dui vitae urna congue scelerisque. Nulla eu commodo felis. Nulla aliquam magna a arcu elementum, vitae tincidunt risus semper. Sed consectetur diam vel magna mattis, sed congue nisi fringilla. Ut in facilisis elit. Etiam aliquet orci urna. Nam interdum nunc fringilla iaculis cursus.
6 | 设置
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/chiralcode/colorpicker/ColorPicker.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Piotr Adamus
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.chiralcode.colorpicker;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.content.Context;
21 | import android.graphics.Bitmap;
22 | import android.graphics.Bitmap.Config;
23 | import android.graphics.Canvas;
24 | import android.graphics.Color;
25 | import android.graphics.ComposeShader;
26 | import android.graphics.Matrix;
27 | import android.graphics.Paint;
28 | import android.graphics.Paint.Join;
29 | import android.graphics.Paint.Style;
30 | import android.graphics.Path;
31 | import android.graphics.PorterDuff;
32 | import android.graphics.RadialGradient;
33 | import android.graphics.RectF;
34 | import android.graphics.Shader.TileMode;
35 | import android.graphics.SweepGradient;
36 | import android.os.Bundle;
37 | import android.os.Parcelable;
38 | import android.util.AttributeSet;
39 | import android.view.MotionEvent;
40 | import android.view.View;
41 |
42 | public class ColorPicker extends View {
43 |
44 | /**
45 | * Customizable display parameters (in percents)
46 | */
47 | private final int paramOuterPadding = 2; // outer padding of the whole color picker view
48 | private final int paramInnerPadding = 5; // distance between value slider wheel and inner color wheel
49 | private final int paramValueSliderWidth = 10; // width of the value slider
50 | private final int paramArrowPointerSize = 4; // size of the arrow pointer; set to 0 to hide the pointer
51 |
52 | private Paint colorWheelPaint;
53 | private Paint valueSliderPaint;
54 |
55 | private Paint colorViewPaint;
56 |
57 | private Paint colorPointerPaint;
58 | private RectF colorPointerCoords;
59 |
60 | private Paint valuePointerPaint;
61 | private Paint valuePointerArrowPaint;
62 |
63 | private RectF outerWheelRect;
64 | private RectF innerWheelRect;
65 |
66 | private Path colorViewPath;
67 | private Path valueSliderPath;
68 | private Path arrowPointerPath;
69 |
70 | private Bitmap colorWheelBitmap;
71 |
72 | private int valueSliderWidth;
73 | private int innerPadding;
74 | private int outerPadding;
75 |
76 | private int arrowPointerSize;
77 | private int outerWheelRadius;
78 | private int innerWheelRadius;
79 | private int colorWheelRadius;
80 |
81 | private Matrix gradientRotationMatrix;
82 |
83 | /** Currently selected color */
84 | private float[] colorHSV = new float[] { 0f, 0f, 1f };
85 |
86 | public ColorPicker(Context context, AttributeSet attrs, int defStyle) {
87 | super(context, attrs, defStyle);
88 | init();
89 | }
90 |
91 | public ColorPicker(Context context, AttributeSet attrs) {
92 | super(context, attrs);
93 | init();
94 | }
95 |
96 | public ColorPicker(Context context) {
97 | super(context);
98 | init();
99 | }
100 |
101 | private void init() {
102 |
103 | colorPointerPaint = new Paint();
104 | colorPointerPaint.setStyle(Style.STROKE);
105 | colorPointerPaint.setStrokeWidth(2f);
106 | colorPointerPaint.setARGB(128, 0, 0, 0);
107 |
108 | valuePointerPaint = new Paint();
109 | valuePointerPaint.setStyle(Style.STROKE);
110 | valuePointerPaint.setStrokeWidth(2f);
111 |
112 | valuePointerArrowPaint = new Paint();
113 |
114 | colorWheelPaint = new Paint();
115 | colorWheelPaint.setAntiAlias(true);
116 | colorWheelPaint.setDither(true);
117 |
118 | valueSliderPaint = new Paint();
119 | valueSliderPaint.setAntiAlias(true);
120 | valueSliderPaint.setDither(true);
121 |
122 | colorViewPaint = new Paint();
123 | colorViewPaint.setAntiAlias(true);
124 |
125 | colorViewPath = new Path();
126 | valueSliderPath = new Path();
127 | arrowPointerPath = new Path();
128 |
129 | outerWheelRect = new RectF();
130 | innerWheelRect = new RectF();
131 |
132 | colorPointerCoords = new RectF();
133 |
134 | }
135 |
136 | @Override
137 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
138 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
139 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
140 | int size = Math.min(widthSize, heightSize);
141 | setMeasuredDimension(size, size);
142 | }
143 |
144 | @SuppressLint("DrawAllocation")
145 | @Override
146 | protected void onDraw(Canvas canvas) {
147 |
148 | int centerX = getWidth() / 2;
149 | int centerY = getHeight() / 2;
150 |
151 | // drawing color wheel
152 |
153 | canvas.drawBitmap(colorWheelBitmap, centerX - colorWheelRadius, centerY - colorWheelRadius, null);
154 |
155 | // drawing color view
156 |
157 | colorViewPaint.setColor(Color.HSVToColor(colorHSV));
158 | canvas.drawPath(colorViewPath, colorViewPaint);
159 |
160 | // drawing value slider
161 |
162 | float[] hsv = new float[] { colorHSV[0], colorHSV[1], 1f };
163 |
164 | SweepGradient sweepGradient = new SweepGradient(centerX, centerY, new int[] { Color.BLACK, Color.HSVToColor(hsv), Color.WHITE }, null);
165 | sweepGradient.setLocalMatrix(gradientRotationMatrix);
166 | valueSliderPaint.setShader(sweepGradient);
167 |
168 | canvas.drawPath(valueSliderPath, valueSliderPaint);
169 |
170 | // drawing color wheel pointer
171 |
172 | float hueAngle = (float) Math.toRadians(colorHSV[0]);
173 | int colorPointX = (int) (-Math.cos(hueAngle) * colorHSV[1] * colorWheelRadius) + centerX;
174 | int colorPointY = (int) (-Math.sin(hueAngle) * colorHSV[1] * colorWheelRadius) + centerY;
175 |
176 | float pointerRadius = 0.075f * colorWheelRadius;
177 | int pointerX = (int) (colorPointX - pointerRadius / 2);
178 | int pointerY = (int) (colorPointY - pointerRadius / 2);
179 |
180 | colorPointerCoords.set(pointerX, pointerY, pointerX + pointerRadius, pointerY + pointerRadius);
181 | canvas.drawOval(colorPointerCoords, colorPointerPaint);
182 |
183 | // drawing value pointer
184 |
185 | valuePointerPaint.setColor(Color.HSVToColor(new float[] { 0f, 0f, 1f - colorHSV[2] }));
186 |
187 | double valueAngle = (colorHSV[2] - 0.5f) * Math.PI;
188 | float valueAngleX = (float) Math.cos(valueAngle);
189 | float valueAngleY = (float) Math.sin(valueAngle);
190 |
191 | canvas.drawLine(valueAngleX * innerWheelRadius + centerX, valueAngleY * innerWheelRadius + centerY, valueAngleX * outerWheelRadius + centerX,
192 | valueAngleY * outerWheelRadius + centerY, valuePointerPaint);
193 |
194 | // drawing pointer arrow
195 |
196 | if (arrowPointerSize > 0) {
197 | drawPointerArrow(canvas);
198 | }
199 |
200 | }
201 |
202 | private void drawPointerArrow(Canvas canvas) {
203 |
204 | int centerX = getWidth() / 2;
205 | int centerY = getHeight() / 2;
206 |
207 | double tipAngle = (colorHSV[2] - 0.5f) * Math.PI;
208 | double leftAngle = tipAngle + Math.PI / 96;
209 | double rightAngle = tipAngle - Math.PI / 96;
210 |
211 | double tipAngleX = Math.cos(tipAngle) * outerWheelRadius;
212 | double tipAngleY = Math.sin(tipAngle) * outerWheelRadius;
213 | double leftAngleX = Math.cos(leftAngle) * (outerWheelRadius + arrowPointerSize);
214 | double leftAngleY = Math.sin(leftAngle) * (outerWheelRadius + arrowPointerSize);
215 | double rightAngleX = Math.cos(rightAngle) * (outerWheelRadius + arrowPointerSize);
216 | double rightAngleY = Math.sin(rightAngle) * (outerWheelRadius + arrowPointerSize);
217 |
218 | arrowPointerPath.reset();
219 | arrowPointerPath.moveTo((float) tipAngleX + centerX, (float) tipAngleY + centerY);
220 | arrowPointerPath.lineTo((float) leftAngleX + centerX, (float) leftAngleY + centerY);
221 | arrowPointerPath.lineTo((float) rightAngleX + centerX, (float) rightAngleY + centerY);
222 | arrowPointerPath.lineTo((float) tipAngleX + centerX, (float) tipAngleY + centerY);
223 |
224 | valuePointerArrowPaint.setColor(Color.HSVToColor(colorHSV));
225 | valuePointerArrowPaint.setStyle(Style.FILL);
226 | canvas.drawPath(arrowPointerPath, valuePointerArrowPaint);
227 |
228 | valuePointerArrowPaint.setStyle(Style.STROKE);
229 | valuePointerArrowPaint.setStrokeJoin(Join.ROUND);
230 | valuePointerArrowPaint.setColor(Color.BLACK);
231 | canvas.drawPath(arrowPointerPath, valuePointerArrowPaint);
232 |
233 | }
234 |
235 | @Override
236 | protected void onSizeChanged(int width, int height, int oldw, int oldh) {
237 |
238 | int centerX = width / 2;
239 | int centerY = height / 2;
240 |
241 | innerPadding = (int) (paramInnerPadding * width / 100);
242 | outerPadding = (int) (paramOuterPadding * width / 100);
243 | arrowPointerSize = (int) (paramArrowPointerSize * width / 100);
244 | valueSliderWidth = (int) (paramValueSliderWidth * width / 100);
245 |
246 | outerWheelRadius = width / 2 - outerPadding - arrowPointerSize;
247 | innerWheelRadius = outerWheelRadius - valueSliderWidth;
248 | colorWheelRadius = innerWheelRadius - innerPadding;
249 |
250 | outerWheelRect.set(centerX - outerWheelRadius, centerY - outerWheelRadius, centerX + outerWheelRadius, centerY + outerWheelRadius);
251 | innerWheelRect.set(centerX - innerWheelRadius, centerY - innerWheelRadius, centerX + innerWheelRadius, centerY + innerWheelRadius);
252 |
253 | colorWheelBitmap = createColorWheelBitmap(colorWheelRadius * 2, colorWheelRadius * 2);
254 |
255 | gradientRotationMatrix = new Matrix();
256 | gradientRotationMatrix.preRotate(270, width / 2, height / 2);
257 |
258 | colorViewPath.arcTo(outerWheelRect, 270, -180);
259 | colorViewPath.arcTo(innerWheelRect, 90, 180);
260 |
261 | valueSliderPath.arcTo(outerWheelRect, 270, 180);
262 | valueSliderPath.arcTo(innerWheelRect, 90, -180);
263 |
264 | }
265 |
266 | private Bitmap createColorWheelBitmap(int width, int height) {
267 |
268 | Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
269 |
270 | int colorCount = 12;
271 | int colorAngleStep = 360 / 12;
272 | int colors[] = new int[colorCount + 1];
273 | float hsv[] = new float[] { 0f, 1f, 1f };
274 | for (int i = 0; i < colors.length; i++) {
275 | hsv[0] = (i * colorAngleStep + 180) % 360;
276 | colors[i] = Color.HSVToColor(hsv);
277 | }
278 | colors[colorCount] = colors[0];
279 |
280 | SweepGradient sweepGradient = new SweepGradient(width / 2, height / 2, colors, null);
281 | RadialGradient radialGradient = new RadialGradient(width / 2, height / 2, colorWheelRadius, 0xFFFFFFFF, 0x00FFFFFF, TileMode.CLAMP);
282 | ComposeShader composeShader = new ComposeShader(sweepGradient, radialGradient, PorterDuff.Mode.SRC_OVER);
283 |
284 | colorWheelPaint.setShader(composeShader);
285 |
286 | Canvas canvas = new Canvas(bitmap);
287 | canvas.drawCircle(width / 2, height / 2, colorWheelRadius, colorWheelPaint);
288 |
289 | return bitmap;
290 |
291 | }
292 |
293 | @Override
294 | public boolean onTouchEvent(MotionEvent event) {
295 | int action = event.getAction();
296 | switch (action) {
297 | case MotionEvent.ACTION_DOWN:
298 | case MotionEvent.ACTION_MOVE:
299 |
300 | int x = (int) event.getX();
301 | int y = (int) event.getY();
302 | int cx = x - getWidth() / 2;
303 | int cy = y - getHeight() / 2;
304 | double d = Math.sqrt(cx * cx + cy * cy);
305 |
306 | if (d <= colorWheelRadius) {
307 |
308 | colorHSV[0] = (float) (Math.toDegrees(Math.atan2(cy, cx)) + 180f);
309 | colorHSV[1] = Math.max(0f, Math.min(1f, (float) (d / colorWheelRadius)));
310 |
311 | invalidate();
312 |
313 | } else if (x >= getWidth() / 2 && d >= innerWheelRadius) {
314 |
315 | colorHSV[2] = (float) Math.max(0, Math.min(1, Math.atan2(cy, cx) / Math.PI + 0.5f));
316 |
317 | invalidate();
318 | }
319 |
320 | return true;
321 | }
322 | return super.onTouchEvent(event);
323 | }
324 |
325 | public void setColor(int color) {
326 | Color.colorToHSV(color, colorHSV);
327 | }
328 |
329 | public int getColor() {
330 | return Color.HSVToColor(colorHSV);
331 | }
332 |
333 | @Override
334 | protected Parcelable onSaveInstanceState() {
335 | Bundle state = new Bundle();
336 | state.putFloatArray("color", colorHSV);
337 | state.putParcelable("super", super.onSaveInstanceState());
338 | return state;
339 | }
340 |
341 | @Override
342 | protected void onRestoreInstanceState(Parcelable state) {
343 | if (state instanceof Bundle) {
344 | Bundle bundle = (Bundle) state;
345 | colorHSV = bundle.getFloatArray("color");
346 | super.onRestoreInstanceState(bundle.getParcelable("super"));
347 | } else {
348 | super.onRestoreInstanceState(state);
349 | }
350 | }
351 |
352 | }
353 |
--------------------------------------------------------------------------------
/app/src/main/java/org/dync/androidsystembar/SystemBarTintManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 readyState Software Ltd
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.dync.androidsystembar;
17 |
18 | import android.annotation.SuppressLint;
19 | import android.annotation.TargetApi;
20 | import android.app.Activity;
21 | import android.content.Context;
22 | import android.content.res.Configuration;
23 | import android.content.res.Resources;
24 | import android.content.res.TypedArray;
25 | import android.graphics.drawable.Drawable;
26 | import android.os.Build;
27 | import android.util.DisplayMetrics;
28 | import android.util.TypedValue;
29 | import android.view.Gravity;
30 | import android.view.View;
31 | import android.view.ViewConfiguration;
32 | import android.view.ViewGroup;
33 | import android.view.Window;
34 | import android.view.WindowManager;
35 | import android.widget.FrameLayout.LayoutParams;
36 |
37 | import java.lang.reflect.Method;
38 |
39 | /**
40 | * Class to manage status and navigation bar tint effects when using KitKat
41 | * translucent system UI modes.
42 | *
43 | */
44 | public class SystemBarTintManager {
45 |
46 | static {
47 | // Android allows a system property to override the presence of the navigation bar.
48 | // Used by the emulator.
49 | // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076
50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
51 | try {
52 | Class c = Class.forName("android.os.SystemProperties");
53 | Method m = c.getDeclaredMethod("get", String.class);
54 | m.setAccessible(true);
55 | sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
56 | } catch (Throwable e) {
57 | sNavBarOverride = null;
58 | }
59 | }
60 | }
61 |
62 |
63 | /**
64 | * The default system bar tint color value.
65 | */
66 | public static final int DEFAULT_TINT_COLOR = 0x99000000;
67 |
68 | private static String sNavBarOverride;
69 |
70 | private final SystemBarConfig mConfig;
71 | private boolean mStatusBarAvailable;
72 | private boolean mNavBarAvailable;
73 | private boolean mStatusBarTintEnabled;
74 | private boolean mNavBarTintEnabled;
75 | private View mStatusBarTintView;
76 | private View mNavBarTintView;
77 |
78 | /**
79 | * Constructor. Call this in the host activity onCreate method after its
80 | * content view has been set. You should always create new instances when
81 | * the host activity is recreated.
82 | *
83 | * @param activity The host activity.
84 | */
85 | @TargetApi(19)
86 | public SystemBarTintManager(Activity activity) {
87 |
88 | Window win = activity.getWindow();
89 | ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
90 |
91 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
92 | // check theme attrs
93 | int[] attrs = {android.R.attr.windowTranslucentStatus,
94 | android.R.attr.windowTranslucentNavigation};
95 | TypedArray a = activity.obtainStyledAttributes(attrs);
96 | try {
97 | mStatusBarAvailable = a.getBoolean(0, false);
98 | mNavBarAvailable = a.getBoolean(1, false);
99 | } finally {
100 | a.recycle();
101 | }
102 |
103 | // check window flags
104 | WindowManager.LayoutParams winParams = win.getAttributes();
105 | int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
106 | if ((winParams.flags & bits) != 0) {
107 | mStatusBarAvailable = true;
108 | }
109 | bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
110 | if ((winParams.flags & bits) != 0) {
111 | mNavBarAvailable = true;
112 | }
113 | }
114 |
115 | mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);
116 | // device might not have virtual navigation keys
117 | if (!mConfig.hasNavigtionBar()) {
118 | mNavBarAvailable = false;
119 | }
120 |
121 | if (mStatusBarAvailable) {
122 | setupStatusBarView(activity, decorViewGroup);
123 | }
124 | if (mNavBarAvailable) {
125 | setupNavBarView(activity, decorViewGroup);
126 | }
127 |
128 | }
129 |
130 | /**
131 | * Enable tinting of the system status bar.
132 | *
133 | * If the platform is running Jelly Bean or earlier, or translucent system
134 | * UI modes have not been enabled in either the theme or via window flags,
135 | * then this method does nothing.
136 | *
137 | * @param enabled True to enable tinting, false to disable it (default).
138 | */
139 | public void setStatusBarTintEnabled(boolean enabled) {
140 | mStatusBarTintEnabled = enabled;
141 | if (mStatusBarAvailable) {
142 | mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
143 | }
144 | }
145 |
146 | /**
147 | * Enable tinting of the system navigation bar.
148 | *
149 | * If the platform does not have soft navigation keys, is running Jelly Bean
150 | * or earlier, or translucent system UI modes have not been enabled in either
151 | * the theme or via window flags, then this method does nothing.
152 | *
153 | * @param enabled True to enable tinting, false to disable it (default).
154 | */
155 | public void setNavigationBarTintEnabled(boolean enabled) {
156 | mNavBarTintEnabled = enabled;
157 | if (mNavBarAvailable) {
158 | mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE);
159 | }
160 | }
161 |
162 | /**
163 | * Apply the specified color tint to all system UI bars.
164 | *
165 | * @param color The color of the background tint.
166 | */
167 | public void setTintColor(int color) {
168 | setStatusBarTintColor(color);
169 | setNavigationBarTintColor(color);
170 | }
171 |
172 | /**
173 | * Apply the specified drawable or color resource to all system UI bars.
174 | *
175 | * @param res The identifier of the resource.
176 | */
177 | public void setTintResource(int res) {
178 | setStatusBarTintResource(res);
179 | setNavigationBarTintResource(res);
180 | }
181 |
182 | /**
183 | * Apply the specified drawable to all system UI bars.
184 | *
185 | * @param drawable The drawable to use as the background, or null to remove it.
186 | */
187 | public void setTintDrawable(Drawable drawable) {
188 | setStatusBarTintDrawable(drawable);
189 | setNavigationBarTintDrawable(drawable);
190 | }
191 |
192 | /**
193 | * Apply the specified alpha to all system UI bars.
194 | *
195 | * @param alpha The alpha to use
196 | */
197 | public void setTintAlpha(float alpha) {
198 | setStatusBarAlpha(alpha);
199 | setNavigationBarAlpha(alpha);
200 | }
201 |
202 | /**
203 | * Apply the specified color tint to the system status bar.
204 | *
205 | * @param color The color of the background tint.
206 | */
207 | public void setStatusBarTintColor(int color) {
208 | if (mStatusBarAvailable) {
209 | mStatusBarTintView.setBackgroundColor(color);
210 | }
211 | }
212 |
213 | /**
214 | * Apply the specified drawable or color resource to the system status bar.
215 | *
216 | * @param res The identifier of the resource.
217 | */
218 | public void setStatusBarTintResource(int res) {
219 | if (mStatusBarAvailable) {
220 | mStatusBarTintView.setBackgroundResource(res);
221 | }
222 | }
223 |
224 | /**
225 | * Apply the specified drawable to the system status bar.
226 | *
227 | * @param drawable The drawable to use as the background, or null to remove it.
228 | */
229 | @SuppressWarnings("deprecation")
230 | public void setStatusBarTintDrawable(Drawable drawable) {
231 | if (mStatusBarAvailable) {
232 | mStatusBarTintView.setBackgroundDrawable(drawable);
233 | }
234 | }
235 |
236 | /**
237 | * Apply the specified alpha to the system status bar.
238 | *
239 | * @param alpha The alpha to use
240 | */
241 | @TargetApi(11)
242 | public void setStatusBarAlpha(float alpha) {
243 | if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
244 | mStatusBarTintView.setAlpha(alpha);
245 | }
246 | }
247 |
248 | /**
249 | * Apply the specified color tint to the system navigation bar.
250 | *
251 | * @param color The color of the background tint.
252 | */
253 | public void setNavigationBarTintColor(int color) {
254 | if (mNavBarAvailable) {
255 | mNavBarTintView.setBackgroundColor(color);
256 | }
257 | }
258 |
259 | /**
260 | * Apply the specified drawable or color resource to the system navigation bar.
261 | *
262 | * @param res The identifier of the resource.
263 | */
264 | public void setNavigationBarTintResource(int res) {
265 | if (mNavBarAvailable) {
266 | mNavBarTintView.setBackgroundResource(res);
267 | }
268 | }
269 |
270 | /**
271 | * Apply the specified drawable to the system navigation bar.
272 | *
273 | * @param drawable The drawable to use as the background, or null to remove it.
274 | */
275 | @SuppressWarnings("deprecation")
276 | public void setNavigationBarTintDrawable(Drawable drawable) {
277 | if (mNavBarAvailable) {
278 | mNavBarTintView.setBackgroundDrawable(drawable);
279 | }
280 | }
281 |
282 | /**
283 | * Apply the specified alpha to the system navigation bar.
284 | *
285 | * @param alpha The alpha to use
286 | */
287 | @TargetApi(11)
288 | public void setNavigationBarAlpha(float alpha) {
289 | if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
290 | mNavBarTintView.setAlpha(alpha);
291 | }
292 | }
293 |
294 | /**
295 | * Get the system bar configuration.
296 | *
297 | * @return The system bar configuration for the current device configuration.
298 | */
299 | public SystemBarConfig getConfig() {
300 | return mConfig;
301 | }
302 |
303 | /**
304 | * Is tinting enabled for the system status bar?
305 | *
306 | * @return True if enabled, False otherwise.
307 | */
308 | public boolean isStatusBarTintEnabled() {
309 | return mStatusBarTintEnabled;
310 | }
311 |
312 | /**
313 | * Is tinting enabled for the system navigation bar?
314 | *
315 | * @return True if enabled, False otherwise.
316 | */
317 | public boolean isNavBarTintEnabled() {
318 | return mNavBarTintEnabled;
319 | }
320 |
321 | private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
322 | mStatusBarTintView = new View(context);
323 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
324 | params.gravity = Gravity.TOP;
325 | if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
326 | params.rightMargin = mConfig.getNavigationBarWidth();
327 | }
328 | mStatusBarTintView.setLayoutParams(params);
329 | mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
330 | mStatusBarTintView.setVisibility(View.GONE);
331 | decorViewGroup.addView(mStatusBarTintView);
332 | }
333 |
334 | private void setupNavBarView(Context context, ViewGroup decorViewGroup) {
335 | mNavBarTintView = new View(context);
336 | LayoutParams params;
337 | if (mConfig.isNavigationAtBottom()) {
338 | params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight());
339 | params.gravity = Gravity.BOTTOM;
340 | } else {
341 | params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT);
342 | params.gravity = Gravity.RIGHT;
343 | }
344 | mNavBarTintView.setLayoutParams(params);
345 | mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
346 | mNavBarTintView.setVisibility(View.GONE);
347 | decorViewGroup.addView(mNavBarTintView);
348 | }
349 |
350 | /**
351 | * Class which describes system bar sizing and other characteristics for the current
352 | * device configuration.
353 | *
354 | */
355 | public static class SystemBarConfig {
356 |
357 | private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
358 | private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
359 | private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
360 | private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
361 | private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
362 |
363 | private final boolean mTranslucentStatusBar;
364 | private final boolean mTranslucentNavBar;
365 | private final int mStatusBarHeight;
366 | private final int mActionBarHeight;
367 | private final boolean mHasNavigationBar;
368 | private final int mNavigationBarHeight;
369 | private final int mNavigationBarWidth;
370 | private final boolean mInPortrait;
371 | private final float mSmallestWidthDp;
372 |
373 | private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) {
374 | Resources res = activity.getResources();
375 | mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
376 | mSmallestWidthDp = getSmallestWidthDp(activity);
377 | mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME);
378 | mActionBarHeight = getActionBarHeight(activity);
379 | mNavigationBarHeight = getNavigationBarHeight(activity);
380 | mNavigationBarWidth = getNavigationBarWidth(activity);
381 | mHasNavigationBar = (mNavigationBarHeight > 0);
382 | mTranslucentStatusBar = translucentStatusBar;
383 | mTranslucentNavBar = traslucentNavBar;
384 | }
385 |
386 | @TargetApi(14)
387 | private int getActionBarHeight(Context context) {
388 | int result = 0;
389 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
390 | TypedValue tv = new TypedValue();
391 | context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
392 | result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics());
393 | }
394 | return result;
395 | }
396 |
397 | @TargetApi(14)
398 | private int getNavigationBarHeight(Context context) {
399 | Resources res = context.getResources();
400 | int result = 0;
401 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
402 | if (hasNavBar(context)) {
403 | String key;
404 | if (mInPortrait) {
405 | key = NAV_BAR_HEIGHT_RES_NAME;
406 | } else {
407 | key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME;
408 | }
409 | return getInternalDimensionSize(res, key);
410 | }
411 | }
412 | return result;
413 | }
414 |
415 | @TargetApi(14)
416 | private int getNavigationBarWidth(Context context) {
417 | Resources res = context.getResources();
418 | int result = 0;
419 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
420 | if (hasNavBar(context)) {
421 | return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
422 | }
423 | }
424 | return result;
425 | }
426 |
427 | @TargetApi(14)
428 | private boolean hasNavBar(Context context) {
429 | Resources res = context.getResources();
430 | int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
431 | if (resourceId != 0) {
432 | boolean hasNav = res.getBoolean(resourceId);
433 | // check override flag (see static block)
434 | if ("1".equals(sNavBarOverride)) {
435 | hasNav = false;
436 | } else if ("0".equals(sNavBarOverride)) {
437 | hasNav = true;
438 | }
439 | return hasNav;
440 | } else { // fallback
441 | return !ViewConfiguration.get(context).hasPermanentMenuKey();
442 | }
443 | }
444 |
445 | private int getInternalDimensionSize(Resources res, String key) {
446 | int result = 0;
447 | int resourceId = res.getIdentifier(key, "dimen", "android");
448 | if (resourceId > 0) {
449 | result = res.getDimensionPixelSize(resourceId);
450 | }
451 | return result;
452 | }
453 |
454 | @SuppressLint("NewApi")
455 | private float getSmallestWidthDp(Activity activity) {
456 | DisplayMetrics metrics = new DisplayMetrics();
457 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
458 | activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
459 | } else {
460 | // TODO this is not correct, but we don't really care pre-kitkat
461 | activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
462 | }
463 | float widthDp = metrics.widthPixels / metrics.density;
464 | float heightDp = metrics.heightPixels / metrics.density;
465 | return Math.min(widthDp, heightDp);
466 | }
467 |
468 | /**
469 | * Should a navigation bar appear at the bottom of the screen in the current
470 | * device configuration? A navigation bar may appear on the right side of
471 | * the screen in certain configurations.
472 | *
473 | * @return True if navigation should appear at the bottom of the screen, False otherwise.
474 | */
475 | public boolean isNavigationAtBottom() {
476 | return (mSmallestWidthDp >= 600 || mInPortrait);
477 | }
478 |
479 | /**
480 | * Get the height of the system status bar.
481 | *
482 | * @return The height of the status bar (in pixels).
483 | */
484 | public int getStatusBarHeight() {
485 | return mStatusBarHeight;
486 | }
487 |
488 | /**
489 | * Get the height of the action bar.
490 | *
491 | * @return The height of the action bar (in pixels).
492 | */
493 | public int getActionBarHeight() {
494 | return mActionBarHeight;
495 | }
496 |
497 | /**
498 | * Does this device have a system navigation bar?
499 | *
500 | * @return True if this device uses soft key navigation, False otherwise.
501 | */
502 | public boolean hasNavigtionBar() {
503 | return mHasNavigationBar;
504 | }
505 |
506 | /**
507 | * Get the height of the system navigation bar.
508 | *
509 | * @return The height of the navigation bar (in pixels). If the device does not have
510 | * soft navigation keys, this will always return 0.
511 | */
512 | public int getNavigationBarHeight() {
513 | return mNavigationBarHeight;
514 | }
515 |
516 | /**
517 | * Get the width of the system navigation bar when it is placed vertically on the screen.
518 | *
519 | * @return The width of the navigation bar (in pixels). If the device does not have
520 | * soft navigation keys, this will always return 0.
521 | */
522 | public int getNavigationBarWidth() {
523 | return mNavigationBarWidth;
524 | }
525 |
526 | /**
527 | * Get the layout inset for any system UI that appears at the top of the screen.
528 | *
529 | * @param withActionBar True to include the height of the action bar, False otherwise.
530 | * @return The layout inset (in pixels).
531 | */
532 | public int getPixelInsetTop(boolean withActionBar) {
533 | return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0);
534 | }
535 |
536 | /**
537 | * Get the layout inset for any system UI that appears at the bottom of the screen.
538 | *
539 | * @return The layout inset (in pixels).
540 | */
541 | public int getPixelInsetBottom() {
542 | if (mTranslucentNavBar && isNavigationAtBottom()) {
543 | return mNavigationBarHeight;
544 | } else {
545 | return 0;
546 | }
547 | }
548 |
549 | /**
550 | * Get the layout inset for any system UI that appears at the right of the screen.
551 | *
552 | * @return The layout inset (in pixels).
553 | */
554 | public int getPixelInsetRight() {
555 | if (mTranslucentNavBar && !isNavigationAtBottom()) {
556 | return mNavigationBarWidth;
557 | } else {
558 | return 0;
559 | }
560 | }
561 |
562 | }
563 |
564 | }
--------------------------------------------------------------------------------